示例#1
0
//*****************************************************************************
//
// Displays the "Position Control Mode" panel.  The returned valud is the ID of
// the panel to be displayed instead of the "Position Control Mode" panel.
//
//*****************************************************************************
unsigned long
DisplayPosition(void)
{
    unsigned long ulPos, ulIdx, ulDelay, ulDemo, ulTime, ulStep;

    //
    // Read the current position mode configuration.
    //
    PositionConfigRead();

    //
    // Enable position control mode.
    //
    CANPositionModeEnable(((g_sPositionConfig.lPosition / 100) * 65536) +
                          (((g_sPositionConfig.lPosition % 100) * 65536) /
                           100));

    //
    // Initially, updates to the position occur immediately.
    //
    ulDelay = 0;

    //
    // Initially, demo mode is disabled.
    //
    ulDemo = 0;
    ulTime = 0;
    ulStep = 0;

    //
    // Disable the widget fill for all the widgets except the one for the
    // device ID selection.
    //
    for(ulIdx = 0; ulIdx < 7; ulIdx++)
    {
        CanvasFillOff(g_psPositionWidgets + ulIdx);
    }
    CanvasFillOn(g_psPositionWidgets + 1);

    //
    // Add the "Position Control Mode" panel widgets to the widget list.
    //
    for(ulIdx = 0; ulIdx < NUM_WIDGETS; ulIdx++)
    {
        WidgetAdd(WIDGET_ROOT, (tWidget *)(g_psPositionWidgets + ulIdx));
    }

    //
    // Enable the status display.
    //
    StatusEnable(0);

    //
    // Set the default cursor position to the device ID selection.
    //
    ulPos = 1;

    //
    // Loop forever.  This loop will be explicitly exited when the proper
    // condition is detected.
    //
    while(1)
    {
        //
        // Print out the current device ID.
        //
        usnprintf(g_pcIDBuffer, sizeof(g_pcIDBuffer), "%d", g_ulCurrentID);

        //
        // Print out the current position.
        //
        if(g_sPositionConfig.lPosition < 0)
        {
            usnprintf(g_pcPositionBuffer, sizeof(g_pcPositionBuffer),
                      "-%d.%02d", (0 - g_sPositionConfig.lPosition) / 100,
                      (0 - g_sPositionConfig.lPosition) % 100);
        }
        else
        {
            usnprintf(g_pcPositionBuffer, sizeof(g_pcPositionBuffer),
                      "%d.%02d", g_sPositionConfig.lPosition / 100,
                      g_sPositionConfig.lPosition % 100);
        }

        //
        // Print out the current P coefficient.
        //
        if(g_sPositionConfig.lP < 0)
        {
            usnprintf(g_pcPositionPBuffer, sizeof(g_pcPositionPBuffer),
                      "-%d.%03d", (0 - g_sPositionConfig.lP) / 1000,
                      (0 - g_sPositionConfig.lP) % 1000);
        }
        else
        {
            usnprintf(g_pcPositionPBuffer, sizeof(g_pcPositionPBuffer),
                      "%d.%03d", g_sPositionConfig.lP / 1000,
                      g_sPositionConfig.lP % 1000);
        }

        //
        // Irint out the current I coefficient.
        //
        if(g_sPositionConfig.lI < 0)
        {
            usnprintf(g_pcPositionIBuffer, sizeof(g_pcPositionIBuffer),
                      "-%d.%03d", (0 - g_sPositionConfig.lI) / 1000,
                      (0 - g_sPositionConfig.lI) % 1000);
        }
        else
        {
            usnprintf(g_pcPositionIBuffer, sizeof(g_pcPositionIBuffer),
                      "%d.%03d", g_sPositionConfig.lI / 1000,
                      g_sPositionConfig.lI % 1000);
        }

        //
        // Print out the current D coefficient.
        //
        if(g_sPositionConfig.lD < 0)
        {
            usnprintf(g_pcPositionDBuffer, sizeof(g_pcPositionDBuffer),
                      "-%d.%03d", (0 - g_sPositionConfig.lD) / 1000,
                      (0 - g_sPositionConfig.lD) % 1000);
        }
        else
        {
            usnprintf(g_pcPositionDBuffer, sizeof(g_pcPositionDBuffer),
                      "%d.%03d", g_sPositionConfig.lD / 1000,
                      g_sPositionConfig.lD % 1000);
        }

        //
        // Print out the current position reference source.
        //
        usnprintf(g_pcReferenceBuffer, sizeof(g_pcReferenceBuffer), "%s",
                  g_ppcPosReference[g_sPositionConfig.ulPosRef]);

        //
        // Update the status display.
        //
        StatusUpdate();

        //
        // Update the display.
        //
        DisplayFlush();

        //
        // See if a serial download has begun.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SERIAL_BOOTLOADER) == 1)
        {
            //
            // Disable the status display.
            //
            StatusDisable();

            //
            // Remove the "Position Control Mode" panel widgets.
            //
            for(ulIdx = 0; ulIdx < NUM_WIDGETS; ulIdx++)
            {
                WidgetRemove((tWidget *)(g_psPositionWidgets + ulIdx));
            }
            CanvasTextColorSet(g_psPositionWidgets + 2, ClrWhite);

            //
            // Disable position control mode.
            //
            CANPositionModeDisable();

            //
            // Return the ID of the update panel.
            //
            return(PANEL_UPDATE);
        }

        //
        // See if demo mode is enabled.
        //
        if(ulDemo != 0)
        {
            //
            // See if the current time delay has expired.
            //
            if(ulTime < g_ulTickCount)
            {
                //
                // Increment to the next step, wrapping back to the beginning
                // of the sequence when the end has been reached.
                //
                ulStep++;
                if(ulStep == (sizeof(g_plPositionDemo) /
                              sizeof(g_plPositionDemo[0])))
                {
                    ulStep = 0;
                }

                //
                // Set the position as directed by the next step.
                //
                g_sPositionConfig.lPosition = g_plPositionDemo[ulStep][0];
                CANPositionSet(((g_sPositionConfig.lPosition / 100) * 65536) +
                               (((g_sPositionConfig.lPosition % 100) * 65536) /
                                100), 0);

                //
                // Set the time delay for this step.
                //
                ulTime = g_ulTickCount + g_plPositionDemo[ulStep][1];
            }
        }

        //
        // See if the up button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the top of the
            // screen and a delayed position update is not in progress.
            //
            if((ulPos != 0) && (ulDelay == 0))
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psPositionWidgets + ulPos);

                //
                // Decrement the cursor row, skipping the position row when
                // demo mode is enabled.
                //
                ulPos--;
                if((ulPos == 2) && (ulDemo != 0))
                {
                    ulPos--;
                }

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psPositionWidgets + ulPos);
            }

            //
            // Clear the press flag for the up button.
            //
            HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
        }

        //
        // See if the down button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the bottom of the
            // screen and a delayed position update is not in progress.
            //
            if((ulPos != 6) && (ulDelay == 0))
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psPositionWidgets + ulPos);

                //
                // Increment the cursor row, skipping the position row when
                // demo mode is enabled.
                //
                ulPos++;
                if((ulPos == 2) && (ulDemo != 0))
                {
                    ulPos++;
                }

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psPositionWidgets + ulPos);
            }

            //
            // Clear the press flag for the down button.
            //
            HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
        }

        //
        // See if the left button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) == 1)
        {
            //
            // See if the device ID is being changed.
            //
            if(ulPos == 1)
            {
                //
                // Only change the device ID if it is greater than one.
                //
                if(g_ulCurrentID > 1)
                {
                    //
                    // Exit demo mode.
                    //
                    ulDemo = 0;
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrWhite);

                    //
                    // Disable position control mode for the current device ID.
                    //
                    CANPositionModeDisable();

                    //
                    // Decrement the device ID.
                    //
                    if((HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1))
                    {
                        if(g_ulCurrentID > 3)
                        {
                            CANSetID(g_ulCurrentID - 3);
                        }
                        else
                        {
                            CANSetID(1);
                        }
                    }
                    else
                    {
                        CANSetID(g_ulCurrentID - 1);
                    }

                    //
                    // Read the configuration of the new device.
                    //
                    PositionConfigRead();

                    //
                    // Enable position control mode.
                    //
                    CANPositionModeEnable(((g_sPositionConfig.lPosition /
                                            100) * 65536) +
                                          (((g_sPositionConfig.lPosition %
                                             100) * 65536) / 100));
                }
            }

            //
            // See if the position is being changed.
            //
            else if(ulPos == 2)
            {
                //
                // Only change the position if it is not already fully
                // negative.
                //
                if(g_sPositionConfig.lPosition > -20000)
                {
                    //
                    // Decrement the position.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lPosition -= 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lPosition -= 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lPosition -= 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lPosition--;
                    }
                    if(g_sPositionConfig.lPosition < -20000)
                    {
                        g_sPositionConfig.lPosition = -20000;
                    }

                    //
                    // Send the updated position to the motor controller if a
                    // delayed update is not in progress.
                    //
                    if(ulDelay == 0)
                    {
                        CANPositionSet(((g_sPositionConfig.lPosition / 100) *
                                        65536) +
                                       (((g_sPositionConfig.lPosition % 100) *
                                         65536) / 100), 0);
                    }
                }
            }

            //
            // See if the position P gain is being changed.
            //
            else if(ulPos == 3)
            {
                //
                // Only change the P gain if it is not already fully negative.
                //
                if(g_sPositionConfig.lP > (-32767 * 1000))
                {
                    //
                    // Decrement the P gain.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lP -= 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lP -= 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lP -= 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lP--;
                    }
                    if(g_sPositionConfig.lP < (-32767 * 1000))
                    {
                        g_sPositionConfig.lP = -32767 * 1000;
                    }

                    //
                    // Send the new P gain to the motor controller.
                    //
                    CANPositionPGainSet(((g_sPositionConfig.lP / 1000) *
                                         65536) +
                                        (((g_sPositionConfig.lP % 1000) *
                                          65536) / 1000));
                }
            }

            //
            // See if the position I gain is being changed.
            //
            else if(ulPos == 4)
            {
                //
                // Only change the I gain if it is not already fully negative.
                //
                if(g_sPositionConfig.lI > (-32767 * 1000))
                {
                    //
                    // Decrement the I gain.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lI -= 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lI -= 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lI -= 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lI--;
                    }
                    if(g_sPositionConfig.lI < (-32767 * 1000))
                    {
                        g_sPositionConfig.lI = -32767 * 1000;
                    }

                    //
                    // Send the new I gain to the motor controller.
                    //
                    CANPositionIGainSet(((g_sPositionConfig.lI / 1000) *
                                         65536) +
                                        (((g_sPositionConfig.lI % 1000) *
                                          65536) / 1000));
                }
            }

            //
            // See if the position D gain is being changed.
            //
            else if(ulPos == 5)
            {
                //
                // Only change the D gain if it is not already fully negative.
                //
                if(g_sPositionConfig.lD > (-32767 * 1000))
                {
                    //
                    // Decrement the D gain.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lD -= 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lD -= 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lD -= 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lD--;
                    }
                    if(g_sPositionConfig.lD < (-32767 * 1000))
                    {
                        g_sPositionConfig.lD = -32767 * 1000;
                    }

                    //
                    // Send the new D gain to the motor controller.
                    //
                    CANPositionDGainSet(((g_sPositionConfig.lD / 1000) *
                                         65536) +
                                        (((g_sPositionConfig.lD % 1000) *
                                          65536) / 1000));
                }
            }

            //
            // See if the position reference source is being changed.
            //
            else if(ulPos == 6)
            {
                //
                // Toggle to the other position reference source.
                //
                g_sPositionConfig.ulPosRef ^= 1;

                //
                // Send the position reference source to the motor controller.
                //
                CANPositionRefSet(g_sPositionConfig.ulPosRef);
            }

            //
            // Clear the press flag for the left button.
            //
            HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) = 0;
        }

        //
        // See if the right button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) == 1)
        {
            //
            // See if the device ID is being changed.
            //
            if(ulPos == 1)
            {
                //
                // Only change the device ID if it is less than 63.
                //
                if(g_ulCurrentID < 63)
                {
                    //
                    // Exit demo mode.
                    //
                    ulDemo = 0;
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrWhite);

                    //
                    // Disable position control mode for the current device ID.
                    //
                    CANPositionModeDisable();

                    //
                    // Increment the device ID.
                    //
                    if((HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1))
                    {
                        if(g_ulCurrentID < 60)
                        {
                            CANSetID(g_ulCurrentID + 3);
                        }
                        else
                        {
                            CANSetID(63);
                        }
                    }
                    else
                    {
                        CANSetID(g_ulCurrentID + 1);
                    }

                    //
                    // Read the configuration of the new device.
                    //
                    PositionConfigRead();

                    //
                    // Enable position control mode.
                    //
                    CANPositionModeEnable(((g_sPositionConfig.lPosition /
                                            100) * 65536) +
                                          (((g_sPositionConfig.lPosition %
                                             100) * 65536) / 100));
                }
            }

            //
            // See if the position is being changed.
            //
            else if(ulPos == 2)
            {
                //
                // Only change the position if it is not already fully
                // positive.
                //
                if(g_sPositionConfig.lPosition < 20000)
                {
                    //
                    // Increment the position.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lPosition += 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lPosition += 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lPosition += 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lPosition++;
                    }
                    if(g_sPositionConfig.lPosition > 20000)
                    {
                        g_sPositionConfig.lPosition = 20000;
                    }

                    //
                    // Send the updated position to the motor controller if a
                    // delayed update is not in progress.
                    //
                    if(ulDelay == 0)
                    {
                        CANPositionSet(((g_sPositionConfig.lPosition / 100) *
                                        65536) +
                                       (((g_sPositionConfig.lPosition % 100) *
                                         65536) / 100), 0);
                    }
                }
            }

            //
            // See if the position P gain is being changed.
            //
            else if(ulPos == 3)
            {
                //
                // Only change the P gain if it is not already fully positive.
                //
                if(g_sPositionConfig.lP < (32767 * 1000))
                {
                    //
                    // Increment the P gain.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lP += 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lP += 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lP += 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lP++;
                    }
                    if(g_sPositionConfig.lP > (32767 * 1000))
                    {
                        g_sPositionConfig.lP = 32767 * 1000;
                    }

                    //
                    // Send the new P gain to the motor controller.
                    //
                    CANPositionPGainSet(((g_sPositionConfig.lP / 1000) *
                                         65536) +
                                        (((g_sPositionConfig.lP % 1000) *
                                          65536) / 1000));
                }
            }

            //
            // See if the position I gain is being changed.
            //
            else if(ulPos == 4)
            {
                //
                // Only change the I gain if it is not already fully positive.
                //
                if(g_sPositionConfig.lI < (32767 * 1000))
                {
                    //
                    // Increment the I gain.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lI += 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lI += 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lI += 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lI++;
                    }
                    if(g_sPositionConfig.lI > (32767 * 1000))
                    {
                        g_sPositionConfig.lI = 32767 * 1000;
                    }

                    //
                    // Send the new I gain to the motor controller.
                    //
                    CANPositionIGainSet(((g_sPositionConfig.lI / 1000) *
                                         65536) +
                                        (((g_sPositionConfig.lI % 1000) *
                                          65536) / 1000));
                }
            }

            //
            // See if the position D gain is being changed.
            //
            else if(ulPos == 5)
            {
                //
                // Only change the D gain if it is not already fully positive.
                //
                if(g_sPositionConfig.lD < (32767 * 1000))
                {
                    //
                    // Increment the D gain.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        g_sPositionConfig.lD += 11;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1)
                    {
                        g_sPositionConfig.lD += 111;
                    }
                    else if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1)
                    {
                        g_sPositionConfig.lD += 1111;
                    }
                    else
                    {
                        g_sPositionConfig.lD++;
                    }
                    if(g_sPositionConfig.lD > (32767 * 1000))
                    {
                        g_sPositionConfig.lD = 32767 * 1000;
                    }

                    //
                    // Send the new D gain to the motor controller.
                    //
                    CANPositionDGainSet(((g_sPositionConfig.lD / 1000) *
                                         65536) +
                                        (((g_sPositionConfig.lD % 1000) *
                                          65536) / 1000));
                }
            }

            //
            // See if the position reference source is being changed.
            //
            else if(ulPos == 6)
            {
                //
                // Toggle to the other position reference source.
                //
                g_sPositionConfig.ulPosRef ^= 1;

                //
                // Send the position reference source to the motor controller.
                //
                CANPositionRefSet(g_sPositionConfig.ulPosRef);
            }

            //
            // Clear the press flag for the right button.
            //
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) = 0;
        }

        //
        // See if the select button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) == 1)
        {
            //
            // Clear the press flag for the select button.
            //
            HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;

            //
            // See if the cursor is on the top row of the screen.
            //
            if(ulPos == 0)
            {
                //
                // Display the menu.
                //
                ulIdx = DisplayMenu(PANEL_POSITION);

                //
                // See if another panel was selected.
                //
                if(ulIdx != PANEL_POSITION)
                {
                    //
                    // Disable the status display.
                    //
                    StatusDisable();

                    //
                    // Remove the "Position Control Mode" panel widgets.
                    //
                    for(ulPos = 0; ulPos < NUM_WIDGETS; ulPos++)
                    {
                        WidgetRemove((tWidget *)(g_psPositionWidgets + ulPos));
                    }
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrWhite);

                    //
                    // Disable position control mode.
                    //
                    CANPositionModeDisable();

                    //
                    // Return the ID of the newly selected panel.
                    //
                    return(ulIdx);
                }

                //
                // Since the "Position Control Mode" panel was selected from
                // the menu, move the cursor down one row.
                //
                CanvasFillOff(g_psPositionWidgets);
                ulPos++;
                CanvasFillOn(g_psPositionWidgets + 1);
            }

            //
            // See if the cursor is on the ID selection.
            //
            else if(ulPos == 1)
            {
                //
                // Toggle demo mode.
                //
                ulDemo ^= 1;

                //
                // See if the demo has just been disabled.
                //
                if(ulDemo == 0)
                {
                    //
                    // Set the output position to the current position.
                    //
                    if(g_lStatusPosition < 0)
                    {
                        g_sPositionConfig.lPosition =
                            (((g_lStatusPosition / 65536) * 100) +
                             ((((g_lStatusPosition % 65536) * 100) - 32768) /
                              65536));
                    }
                    else
                    {
                        g_sPositionConfig.lPosition =
                            (((g_lStatusPosition / 65536) * 100) +
                             ((((g_lStatusPosition % 65536) * 100) + 32768) /
                              65536));
                    }
                    CANPositionSet(((g_sPositionConfig.lPosition / 100) *
                                    65536) +
                                   (((g_sPositionConfig.lPosition % 100) *
                                     65536) / 100), 0);

                    //
                    // Indicate that demo mode has exited by setting the text
                    // color to white.
                    //
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrWhite);
                }

                //
                // Otherwise start demo mode.
                //
                else
                {
                    //
                    // Indicate that demo mode is active by setting the text
                    // color to gray.
                    //
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrSelected);

                    //
                    // Start with the first step.
                    //
                    ulStep = 0;

                    //
                    // Set the position as directed by the first step.
                    //
                    g_sPositionConfig.lPosition = g_plPositionDemo[0][0];
                    CANPositionSet(((g_sPositionConfig.lPosition / 100) *
                                    65536) +
                                   (((g_sPositionConfig.lPosition % 100) *
                                     65536) / 100), 0);

                    //
                    // Set the time delay for the first step.
                    //
                    ulTime = g_ulTickCount + g_plPositionDemo[0][1];
                }
            }

            //
            // See if the cursor is on the position selection.
            //
            else if(ulPos == 2)
            {
                //
                // Toggle the state of the delayed update.
                //
                ulDelay ^= 1;

                //
                // See if a delayed update should be performed.
                //
                if(ulDelay == 0)
                {
                    //
                    // Send the delayed position update.
                    //
                    CANPositionSet(((g_sPositionConfig.lPosition / 100) *
                                    65536) +
                                   (((g_sPositionConfig.lPosition % 100) *
                                     65536) / 100), 0);

                    //
                    // Change the text color of the position selection to white
                    // to indicate that updates will occur immediately.
                    //
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrWhite);
                }
                else
                {
                    //
                    // Change the text color of the position selection to black
                    // to indicate that updates will be delayed.
                    //
                    CanvasTextColorSet(g_psPositionWidgets + 2, ClrBlack);
                }
            }
        }
    }
}
//*****************************************************************************
//
// Displays the "VComp Control Mode" panel.  The returned valud is the ID of
// the panel to be displayed instead of the "VComp Control Mode" panel.
//
//*****************************************************************************
unsigned long
DisplayVComp(void)
{
    unsigned long ulRamp, ulComp, ulPos, ulIdx, ulDelay, ulDemo, ulTime;
    unsigned long ulStep;
    long lVoltage;

    //
    // Enable voltage compensation control mode.
    //
    CANVCompModeEnable();

    //
    // Set the default voltage.
    //
    lVoltage = 0;
    CANVCompSet(0, 0);

    //
    // Read the ramp rate.
    //
    if(CANReadParameter(LM_API_VCOMP_IN_RAMP, 0, &ulRamp, 0) == 0)
    {
        ulRamp = 0;
    }
    else
    {
        ulRamp = (((ulRamp & 0xffff) * 100) + 128) / 256;
    }

    //
    // Read the compensation rate.
    //
    if(CANReadParameter(LM_API_VCOMP_COMP_RAMP, 0, &ulComp, 0) == 0)
    {
        ulComp = 0;
    }
    else
    {
        ulComp = (((ulComp & 0xffff) * 100) + 128) / 256;
    }

    //
    // Initially, updates to the voltage occur immediately.
    //
    ulDelay = 0;

    //
    // Initially, demo mode is disabled.
    //
    ulDemo = 0;
    ulTime = 0;
    ulStep = 0;

    //
    // Disable the widget fill for all the widgets except the one for the
    // device ID selection.
    //
    for(ulIdx = 0; ulIdx < 4; ulIdx++)
    {
        CanvasFillOff(g_psVCompWidgets + ulIdx);
    }
    CanvasFillOn(g_psVCompWidgets + 1);

    //
    // Add the "VComp Control Mode" panel widgets to the widget list.
    //
    for(ulIdx = 0; ulIdx < NUM_WIDGETS; ulIdx++)
    {
        WidgetAdd(WIDGET_ROOT, (tWidget *)(g_psVCompWidgets + ulIdx));
    }

    //
    // Enable the status display.
    //
    StatusEnable(0);

    //
    // Set the default cursor position to the device ID selection.
    //
    ulPos = 1;

    //
    // Loop forever.  This loop will be explicitly exited when the proper
    // condition is detected.
    //
    while(1)
    {
        //
        // Print out the current device ID.
        //
        usnprintf(g_pcIDBuffer, sizeof(g_pcIDBuffer), "%d", g_ulCurrentID);

        //
        // Print out the current voltage.
        //
        if(lVoltage < 0)
        {
            usnprintf(g_pcVoltageBuffer, sizeof(g_pcVoltageBuffer),
                      "-%d.%01d V", (0 - lVoltage) / 10, (0 - lVoltage) % 10);
        }
        else
        {
            usnprintf(g_pcVoltageBuffer, sizeof(g_pcVoltageBuffer),
                      "%d.%01d V", lVoltage / 10, lVoltage % 10);
        }

        //
        // Print out the current ramp rate.
        //
        if(ulRamp == 0)
        {
            usnprintf(g_pcRampBuffer, sizeof(g_pcRampBuffer), "none");
        }
        else
        {
            usnprintf(g_pcRampBuffer, sizeof(g_pcRampBuffer), "%d.%02d V/ms",
                      ulRamp / 100, ulRamp % 100);
        }

        //
        // Print out the current compensation rate.
        //
        if(ulComp == 0)
        {
            usnprintf(g_pcCompBuffer, sizeof(g_pcCompBuffer), "none");
        }
        else
        {
            usnprintf(g_pcCompBuffer, sizeof(g_pcCompBuffer), "%d.%02d V/ms",
                      ulComp / 100, ulComp % 100);
        }

        //
        // Update the status display.
        //
        StatusUpdate();

        //
        // Update the display.
        //
        DisplayFlush();

        //
        // See if a serial download has begun.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SERIAL_BOOTLOADER) == 1)
        {
            //
            // Disable the status display.
            //
            StatusDisable();

            //
            // Remove the "VComp Control Mode" panel widgets.
            //
            for(ulIdx = 0; ulIdx < NUM_WIDGETS; ulIdx++)
            {
                WidgetRemove((tWidget *)(g_psVCompWidgets + ulIdx));
            }
            CanvasTextColorSet(g_psVCompWidgets + 2, ClrWhite);

            //
            // Set the output voltage to zero.
            //
            CANVCompSet(0, 0);

            //
            // Return the ID of the update panel.
            //
            return(PANEL_UPDATE);
        }

        //
        // See if demo mode is enabled.
        //
        if(ulDemo != 0)
        {
            //
            // See if the current time delay has expired.
            //
            if(ulTime < g_ulTickCount)
            {
                //
                // Increment to the next step, wrapping back to the beginning
                // of the sequence when the end has been reached.
                //
                ulStep++;
                if(ulStep ==
                   (sizeof(g_plVCompDemo) / sizeof(g_plVCompDemo[0])))
                {
                    ulStep = 0;
                }

                //
                // Set the voltage as directed by the next step.
                //
                lVoltage = g_plVCompDemo[ulStep][0];
                CANVCompSet((lVoltage * 256) / 10, 0);

                //
                // Set the time delay for this step.
                //
                ulTime = g_ulTickCount + g_plVCompDemo[ulStep][1];
            }
        }

        //
        // See if the up button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the top of the
            // screen and a delayed voltage update is not in progress.
            //
            if((ulPos != 0) && (ulDelay == 0))
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psVCompWidgets + ulPos);

                //
                // Decrement the cursor row, skipping the voltage row when demo
                // mode is enabled.
                //
                ulPos--;
                if((ulPos == 2) && (ulDemo != 0))
                {
                    ulPos--;
                }

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psVCompWidgets + ulPos);
            }

            //
            // Clear the press flag for the up button.
            //
            HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
        }

        //
        // See if the down button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the bottom of the
            // screen and a delayed voltage update is not in progress.
            //
            if((ulPos != 4) && (ulDelay == 0))
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psVCompWidgets + ulPos);

                //
                // Increment the cursor row, skipping the voltage row when demo
                // mode is enabled.
                //
                ulPos++;
                if((ulPos == 2) && (ulDemo != 0))
                {
                    ulPos++;
                }

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psVCompWidgets + ulPos);
            }

            //
            // Clear the press flag for the down button.
            //
            HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
        }

        //
        // See if the left button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) == 1)
        {
            //
            // See if the device ID is being changed.
            //
            if(ulPos == 1)
            {
                //
                // Only change the device ID if it is greater than one.
                //
                if(g_ulCurrentID > 1)
                {
                    //
                    // Exit demo mode.
                    //
                    ulDemo = 0;
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrWhite);

                    //
                    // Set the voltage to 0 for the current device ID.
                    //
                    CANVCompSet(0, 0);

                    //
                    // Decrement the device ID.
                    //
                    if((HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1))
                    {
                        if(g_ulCurrentID > 3)
                        {
                            CANSetID(g_ulCurrentID - 3);
                        }
                        else
                        {
                            CANSetID(1);
                        }
                    }
                    else
                    {
                        CANSetID(g_ulCurrentID - 1);
                    }

                    //
                    // Enable voltage compensation mode.
                    //
                    CANVCompModeEnable();

                    //
                    // Set the voltage for the new device.
                    //
                    lVoltage = 0;
                    CANVCompSet(0, 0);

                    //
                    // Read the ramp rate.
                    //
                    if(CANReadParameter(LM_API_VCOMP_IN_RAMP, 0, &ulRamp,
                                        0) == 0)
                    {
                        ulRamp = 0;
                    }
                    else
                    {
                        ulRamp = (((ulRamp & 0xffff) * 100) + 128) / 256;
                    }

                    //
                    // Read the compensation rate.
                    //
                    if(CANReadParameter(LM_API_VCOMP_COMP_RAMP, 0, &ulComp,
                                        0) == 0)
                    {
                        ulComp = 0;
                    }
                    else
                    {
                        ulComp = (((ulComp & 0xffff) * 100) + 128) / 256;
                    }
                }
            }

            //
            // See if the voltage is being changed.
            //
            else if(ulPos == 2)
            {
                //
                // Only change the voltage if it is not already full reverse.
                //
                if(lVoltage > -120)
                {
                    //
                    // Decrement the voltage.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        lVoltage -= 11;
                    }
                    else if((HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1) ||
                            (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1))
                    {
                        lVoltage -= 111;
                    }
                    else
                    {
                        lVoltage--;
                    }
                    if(lVoltage < -120)
                    {
                        lVoltage = -120;
                    }

                    //
                    // Send the updated voltage to the motor controller if a
                    // delayed update is not in progress.
                    //
                    if(ulDelay == 0)
                    {
                        CANVCompSet((lVoltage * 256) / 10, 0);
                    }
                }
            }

            //
            // See if the voltage ramp rate is being changed.
            //
            else if(ulPos == 3)
            {
                //
                // Only change the ramp rate if it is not already zero.
                //
                if(ulRamp > 0)
                {
                    //
                    // Decrement the voltage ramp rate.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        ulRamp -= 11;
                    }
                    else if((HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1) ||
                            (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1))
                    {
                        ulRamp -= 111;
                    }
                    else
                    {
                        ulRamp--;
                    }
                    if(ulRamp & 0x80000000)
                    {
                        ulRamp = 0;
                    }

                    //
                    // Send the updated voltage ramp rate.
                    //
                    CANVCompInRampSet((ulRamp * 256) / 100);
                }
            }

            //
            // See if the compensation rate is being changed.
            //
            else if(ulPos == 4)
            {
                //
                // Only change the compensation rate if it is not already zero.
                //
                if(ulComp > 0)
                {
                    //
                    // Decrement the compensation rate.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) == 1)
                    {
                        ulComp -= 11;
                    }
                    else if((HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) == 1) ||
                            (HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) == 1))
                    {
                        ulComp -= 111;
                    }
                    else
                    {
                        ulComp--;
                    }
                    if(ulComp & 0x80000000)
                    {
                        ulComp = 0;
                    }

                    //
                    // Send the updated compensation rate.
                    //
                    CANVCompCompRampSet((ulComp * 256) / 100);
                }
            }

            //
            // Clear the press flag for the left button.
            //
            HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL1) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL2) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_ACCEL3) = 0;
        }

        //
        // See if the right button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) == 1)
        {
            //
            // See if the device ID is being changed.
            //
            if(ulPos == 1)
            {
                //
                // Only change the device ID if it is less than 63.
                //
                if(g_ulCurrentID < 63)
                {
                    //
                    // Exit demo mode.
                    //
                    ulDemo = 0;
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrWhite);

                    //
                    // Set the voltage to 0 for the current device ID.
                    //
                    CANVCompSet(0, 0);

                    //
                    // Increment the device ID.
                    //
                    if((HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1) ||
                       (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1))
                    {
                        if(g_ulCurrentID < 60)
                        {
                            CANSetID(g_ulCurrentID + 3);
                        }
                        else
                        {
                            CANSetID(63);
                        }
                    }
                    else
                    {
                        CANSetID(g_ulCurrentID + 1);
                    }

                    //
                    // Enable voltage compensation control mode.
                    //
                    CANVCompModeEnable();

                    //
                    // Set the voltage for the new device.
                    //
                    lVoltage = 0;
                    CANVCompSet(0, 0);

                    //
                    // Read the ramp rate.
                    //
                    if(CANReadParameter(LM_API_VCOMP_IN_RAMP, 0, &ulRamp,
                                        0) == 0)
                    {
                        ulRamp = 0;
                    }
                    else
                    {
                        ulRamp = (((ulRamp & 0xffff) * 100) + 128) / 256;
                    }

                    //
                    // Read the compensation rate.
                    //
                    if(CANReadParameter(LM_API_VCOMP_COMP_RAMP, 0, &ulComp,
                                        0) == 0)
                    {
                        ulComp = 0;
                    }
                    else
                    {
                        ulComp = (((ulComp & 0xffff) * 100) + 128) / 256;
                    }
                }
            }

            //
            // See if the voltage is being changed.
            //
            else if(ulPos == 2)
            {
                //
                // Only change the voltage if it is not already full forward.
                //
                if(lVoltage < 120)
                {
                    //
                    // Increment the voltage.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        lVoltage += 11;
                    }
                    else if((HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1) ||
                            (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1))
                    {
                        lVoltage += 111;
                    }
                    else
                    {
                        lVoltage++;
                    }
                    if(lVoltage > 120)
                    {
                        lVoltage = 120;
                    }

                    //
                    // Send the updated voltage to the motor controller if a
                    // delayed update is not in progress.
                    //
                    if(ulDelay == 0)
                    {
                        CANVCompSet((lVoltage * 256) / 10, 0);
                    }
                }
            }

            //
            // See if the voltage ramp rate is being changed.
            //
            else if(ulPos == 3)
            {
                //
                // Only change the ramp rate if it is not already the maximum.
                //
                if(ulRamp < 1200)
                {
                    //
                    // Increment the voltage ramp rate.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        ulRamp += 11;
                    }
                    else if((HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1) ||
                            (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1))
                    {
                        ulRamp += 111;
                    }
                    else
                    {
                        ulRamp++;
                    }
                    if(ulRamp > 1200)
                    {
                        ulRamp = 1200;
                    }

                    //
                    // Send the updated voltage ramp rate.
                    //
                    CANVCompInRampSet((ulRamp * 256) / 100);
                }
            }

            //
            // See if the compensation rate is being changed.
            //
            else if(ulPos == 4)
            {
                //
                // Only change the compensation rate if it is not already the
                // maximum.
                //
                if(ulComp < 1200)
                {
                    //
                    // Increment the compensation rate.
                    //
                    if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) == 1)
                    {
                        ulComp += 11;
                    }
                    else if((HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) == 1) ||
                            (HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) == 1))
                    {
                        ulComp += 111;
                    }
                    else
                    {
                        ulComp++;
                    }
                    if(ulComp > 1200)
                    {
                        ulComp = 1200;
                    }

                    //
                    // Send the updated compensation rate.
                    //
                    CANVCompCompRampSet((ulComp * 256) / 100);
                }
            }

            //
            // Clear the press flag for the right button.
            //
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL1) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL2) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_ACCEL3) = 0;
        }

        //
        // See if the select button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) == 1)
        {
            //
            // Clear the press flag for the select button.
            //
            HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;

            //
            // See if the cursor is on the top row of the screen.
            //
            if(ulPos == 0)
            {
                //
                // Display the menu.
                //
                ulIdx = DisplayMenu(PANEL_VCOMP);

                //
                // See if another panel was selected.
                //
                if(ulIdx != PANEL_VCOMP)
                {
                    //
                    // Disable the status display.
                    //
                    StatusDisable();

                    //
                    // Remove the "VComp Control Mode" panel widgets.
                    //
                    for(ulPos = 0; ulPos < NUM_WIDGETS; ulPos++)
                    {
                        WidgetRemove((tWidget *)(g_psVCompWidgets + ulPos));
                    }
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrWhite);

                    //
                    // Set the output voltage to zero.
                    //
                    CANVCompSet(0, 0);

                    //
                    // Return the ID of the newly selected panel.
                    //
                    return(ulIdx);
                }

                //
                // Since the "VComp Control Mode" panel was selected from the
                // menu, move the cursor down one row.
                //
                CanvasFillOff(g_psVCompWidgets);
                ulPos++;
                CanvasFillOn(g_psVCompWidgets + 1);
            }

            //
            // See if the cursor is on the ID selection.
            //
            else if(ulPos == 1)
            {
                //
                // Toggle demo mode.
                //
                ulDemo ^= 1;

                //
                // See if the demo has just been disabled.
                //
                if(ulDemo == 0)
                {
                    //
                    // Set the output voltage to zero.
                    //
                    lVoltage = 0;
                    CANVCompSet(0, 0);

                    //
                    // Indicate that demo mode has exited by setting the text
                    // color to white.
                    //
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrWhite);
                }

                //
                // Otherwise start demo mode.
                //
                else
                {
                    //
                    // Indicate that demo mode is active by setting the text
                    // color to gray.
                    //
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrSelected);

                    //
                    // Start with the first step.
                    //
                    ulStep = 0;

                    //
                    // Set the voltage as directed by the first step.
                    //
                    lVoltage = g_plVCompDemo[0][0];
                    CANVCompSet((lVoltage * 256) / 10, 0);

                    //
                    // Set the time delay for the first step.
                    //
                    ulTime = g_ulTickCount + g_plVCompDemo[0][1];
                }
            }

            //
            // See if the cursor is on the voltage selection.
            //
            else if(ulPos == 2)
            {
                //
                // Toggle the state of the delayed update.
                //
                ulDelay ^= 1;

                //
                // See if a delayed update should be performed.
                //
                if(ulDelay == 0)
                {
                    //
                    // Send the delayed voltage update.
                    //
                    CANVCompSet((lVoltage * 256) / 10, 0);

                    //
                    // Change the text color of the voltage selection to white
                    // to indicate that updates will occur immediately.
                    //
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrWhite);
                }
                else
                {
                    //
                    // Change the text color of the voltage selection to black
                    // to indicate that updates will be delayed.
                    //
                    CanvasTextColorSet(g_psVCompWidgets + 2, ClrBlack);
                }
            }
        }
    }
}
//*****************************************************************************
//
// Displays the "Device List" panel.  The returned value is the ID of the panel
// to be displayed instead of the "Device List" panel.
//
//*****************************************************************************
unsigned long
DisplayDevList(void)
{
    unsigned long ulPosX, ulPosY, ulIdx;

    //
    // Disable the widget fill for all the widgets except the one for device
    // ID 1.
    //
    CanvasFillOn(g_psDevListWidgets);
    for(ulIdx = 1; ulIdx < 64; ulIdx++)
    {
        CanvasFillOff(g_psDevListWidgets + ulIdx);
    }

    //
    // Add the "Device List" panel widgets to the widget list.
    //
    for(ulIdx = 0; ulIdx < NUM_WIDGETS; ulIdx++)
    {
        WidgetAdd(WIDGET_ROOT, (tWidget *)(g_psDevListWidgets + ulIdx));
    }

    //
    // Set the default cursor position to device ID 1.
    //
    ulPosX = 0;
    ulPosY = 1;

    //
    // Loop forever.  This loop will be explicitly exited when the proper
    // condition is detected.
    //
    while(1)
    {
        //
        // Enumerate the devices on the CAN bus.
        //
        CANEnumerate();

        //
        // Delay for 100ms while the bus is being enumerated.
        //
        for(ulIdx = 0; ulIdx < 100; ulIdx++)
        {
            HWREGBITW(&g_ulFlags, FLAG_TICK) = 0;
            while(HWREGBITW(&g_ulFlags, FLAG_TICK) == 0)
            {
            }
        }

        //
        // See if a serial download has begun.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SERIAL_BOOTLOADER) == 1)
        {
            //
            // Remove the "Device List" panel widgets.
            //
            for(ulIdx = 0; ulIdx < NUM_WIDGETS; ulIdx++)
            {
                WidgetRemove((tWidget *)(g_psDevListWidgets + ulIdx));
            }

            //
            // Return the ID of the update panel.
            //
            return(PANEL_UPDATE);
        }

        //
        // See if the up button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the top of the
            // screen.
            //
            if(ulPosY != 0)
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);

                //
                // Decrement the cursor row.
                //
                ulPosY--;

                //
                // Enable the widget fill for the newly selected widget.
                //
                if(ulPosY == 0)
                {
                    CanvasFillOn(g_psDevListWidgets + 63);
                }
                else
                {
                    CanvasFillOn(g_psDevListWidgets + (ulPosY * 7) + ulPosX -
                                 7);
                }
            }

            //
            // Clear the press flag for the up button.
            //
            HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
        }

        //
        // See if the down button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the bottom of the
            // screen.
            //
            if(ulPosY != 9)
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                if(ulPosY == 0)
                {
                    CanvasFillOff(g_psDevListWidgets + 63);
                }
                else
                {
                    CanvasFillOff(g_psDevListWidgets + (ulPosY * 7) + ulPosX -
                                  7);
                }

                //
                // Increment the cursor row.
                //
                ulPosY++;

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);
            }

            //
            // Clear the press flag for the down button.
            //
            HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
        }

        //
        // See if the left button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not on the top row of the screen
            // and if it is not already at the left edge of the screen.
            //
            if((ulPosX != 0) && (ulPosY != 0))
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);

                //
                // Decrement the cursor column.
                //
                ulPosX--;

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);
            }

            //
            // Clear the press flag for the left button.
            //
            HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
        }

        //
        // See if the right button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not on the top row of the screen
            // and if it is not already at the right edge of the screen.
            //
            if((ulPosX != 6) && (ulPosY != 0))
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);

                //
                // Increment the cursor column.
                //
                ulPosX++;

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);
            }

            //
            // Clear the press flag for the right button.
            //
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
        }

        //
        // Loop through the 63 possible device IDs and set the text color of
        // the corresponding widget based on that ID's presence or absence on
        // the bus.
        //
        for(ulIdx = 1; ulIdx < 64; ulIdx++)
        {
            if(g_pulStatusEnumeration[ulIdx / 32] & (1 << (ulIdx % 32)))
            {
                CanvasTextColorSet(g_psDevListWidgets + ulIdx - 1, ClrWhite);
            }
            else
            {
                CanvasTextColorSet(g_psDevListWidgets + ulIdx - 1,
                                   ClrNotPresent);
            }
        }

        //
        // See if the select button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) == 1)
        {
            //
            // Clear the press flag for the select button.
            //
            HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;

            //
            // See if the cursor is on the top row of the screen.
            //
            if(ulPosY == 0)
            {
                //
                // Display the menu.
                //
                ulIdx = DisplayMenu(PANEL_DEV_LIST);

                //
                // See if another panel was selected.
                //
                if(ulIdx != PANEL_DEV_LIST)
                {
                    //
                    // Remove the "Device List" panel widgets.
                    //
                    for(ulPosX = 0; ulPosX < NUM_WIDGETS; ulPosX++)
                    {
                        WidgetRemove((tWidget *)(g_psDevListWidgets + ulPosX));
                    }

                    //
                    // Return the ID of the newly selected panel.
                    //
                    return(ulIdx);
                }

                //
                // Since the "Device List" panel was selected from the menu,
                // move the cursor down one row.
                //
                CanvasFillOff(g_psDevListWidgets + 63);
                ulPosY++;
                CanvasFillOn(g_psDevListWidgets + (ulPosY * 7) + ulPosX - 7);
            }
            else
            {
                //
                // Indicate that the current ID is begin assigned.
                //
                usnprintf(g_pcBuffer, sizeof(g_pcBuffer), "Assigning %d...",
                          (ulPosY * 7) + ulPosX - 6);
                WidgetAdd(WIDGET_ROOT, (tWidget *)&g_sAssignWidget);

                //
                // Update the display.
                //
                DisplayFlush();

                //
                // Perform a CAN device ID assignment.
                //
                CANAssign((ulPosY * 7) + ulPosX - 6);

                //
                // Delay for 5 seconds while the ID assignment takes place.
                //
                for(ulIdx = 0; ulIdx < 5000; ulIdx++)
                {
                    HWREGBITW(&g_ulFlags, FLAG_TICK) = 0;
                    while(HWREGBITW(&g_ulFlags, FLAG_TICK) == 0)
                    {
                    }
                }

                //
                // Remove the assignment indicator widget.
                //
                WidgetRemove((tWidget *)&g_sAssignWidget);

                //
                // Clear any button presses that may have occurred during the
                // ID assignment.
                //
                HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;
            }
        }

        //
        // Update the display.
        //
        DisplayFlush();
    }
}
//*****************************************************************************
//
// Displays the "Firmware Update" panel.  The returned valud is the ID of the
// panel to be displayed instead of the "Firmware Update" panel.
//
//*****************************************************************************
unsigned long
DisplayUpdate(void)
{
    unsigned long ulPos, ulIdx;

    //
    // Disable the widget fill for all the widgets except the one for device
    // ID 1.
    //
    for(ulIdx = 0; ulIdx < 3; ulIdx++)
    {
        CanvasFillOff(g_psUpdateWidgets + ulIdx);
    }
    CanvasFillOn(g_psUpdateWidgets + 1);

    //
    // Add the "Firmware Update" panel widgets to the widget list.
    //
    for(ulIdx = 0; ulIdx < NUM_UPDATE_WIDGETS; ulIdx++)
    {
        WidgetAdd(WIDGET_ROOT, (tWidget *)(g_psUpdateWidgets + ulIdx));
    }

    //
    // Set the default cursor position to the device ID selection.
    //
    ulPos = 1;

    //
    // Clear the message buffer.
    //
    g_pcMessageBuffer[0] = '\0';

    //
    // Loop forever.  This loop will be explicitly exited when the proper
    // condition is detected.
    //
    while(1)
    {
        //
        // Print out the current device ID.
        //
        usnprintf(g_pcIDBuffer, sizeof(g_pcIDBuffer), "%d", g_ulCurrentID);

        //
        // Print out the firmware version.
        //
        if(g_ulStatusFirmwareVersion == 0xffffffff)
        {
            usnprintf(g_pcVersionBuffer, sizeof(g_pcVersionBuffer), "---");
        }
        else
        {
            usnprintf(g_pcVersionBuffer, sizeof(g_pcVersionBuffer), "%d",
                      g_ulStatusFirmwareVersion);
        }

        //
        // Update the display.
        //
        DisplayFlush();

        //
        // Wait until a button is pressed, the firmware version is received, or
        // a serial download begins.
        //
        while((HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) == 0) &&
              (HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) == 0) &&
              (HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) == 0) &&
              (HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) == 0) &&
              (HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) == 0) &&
              (HWREGBITW(&g_ulFlags, FLAG_SERIAL_BOOTLOADER) == 0))
        {
        }

        //
        // See if the up button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the top of the
            // screen.
            //
            if(ulPos != 0)
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psUpdateWidgets + ulPos);

                //
                // Decrement the cursor row.
                //
                ulPos--;

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psUpdateWidgets + ulPos);
            }

            //
            // Clear the press flag for the up button.
            //
            HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
        }

        //
        // See if the down button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) == 1)
        {
            //
            // Only move the cursor if it is not already at the bottom of the
            // screen.
            //
            if(ulPos != 2)
            {
                //
                // Disable the widget fill for the currently selected widget.
                //
                CanvasFillOff(g_psUpdateWidgets + ulPos);

                //
                // Increment the cursor row.
                //
                ulPos++;

                //
                // Enable the widget fill for the newly selected widget.
                //
                CanvasFillOn(g_psUpdateWidgets + ulPos);
            }

            //
            // Clear the press flag for the down button.
            //
            HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
        }

        //
        // See if the left button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) == 1)
        {
            //
            // Only change the device ID if it is greater than one.
            //
            if((ulPos == 1) && (g_ulCurrentID > 1))
            {
                //
                // Decrement the device ID.
                //
                CANSetID(g_ulCurrentID - 1);
            }

            //
            // Clear the press flag for the left button.
            //
            HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
        }

        //
        // See if the right button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) == 1)
        {
            //
            // Only change the device ID if it is less than 63.
            //
            if((ulPos == 1) && (g_ulCurrentID < 63))
            {
                //
                // Increment the device ID.
                //
                CANSetID(g_ulCurrentID + 1);
            }

            //
            // Clear the press flag for the right button.
            //
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
        }

        //
        // See if the select button was pressed.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) == 1)
        {
            //
            // Clear the press flag for the select button.
            //
            HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;

            //
            // See if the cursor is on the top row of the screen.
            //
            if(ulPos == 0)
            {
                //
                // Display the menu.
                //
                ulIdx = DisplayMenu(PANEL_UPDATE);

                //
                // See if another panel was selected.
                //
                if(ulIdx != PANEL_UPDATE)
                {
                    //
                    // Remove the "Firmware Update" panel widgets.
                    //
                    for(ulPos = 0; ulPos < NUM_UPDATE_WIDGETS; ulPos++)
                    {
                        WidgetRemove((tWidget *)(g_psUpdateWidgets + ulPos));
                    }

                    //
                    // Return the ID of the newly selected panel.
                    //
                    return(ulIdx);
                }

                //
                // Since the "Firmware Update" panel was selected from the
                // menu, move the cursor down one row.
                //
                CanvasFillOff(g_psUpdateWidgets);
                ulPos++;
                CanvasFillOn(g_psUpdateWidgets + 1);
            }

            //
            // See if the cursor is on the start button.
            //
            else if(ulPos == 2)
            {
                //
                // Turn off the fill on the start button.
                //
                CanvasFillOff(g_psUpdateWidgets + 2);

                //
                // Perform the CAN update.
                //
                CANUpdate();

                //
                // Turn on the fill on the start button.
                //
                CanvasFillOn(g_psUpdateWidgets + 2);

                //
                // Clear the button press flags so that any button presses that
                // occur during the firmware update are ignored.
                //
                HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
                HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;
            }
        }

        //
        // See if a serial download has begun.
        //
        if(HWREGBITW(&g_ulFlags, FLAG_SERIAL_BOOTLOADER) == 1)
        {
            //
            // Turn off the fill on the current cursor location.
            //
            CanvasFillOff(g_psUpdateWidgets + ulPos);

            //
            // Monitor the UART firmware download.
            //
            if(UARTUpdate() == 0)
            {
                //
                // The firmware was successfully downloaded via the UART, so
                // update the current motor controller with the new firmware.
                //
                CANUpdate();
            }

            //
            // Turn on the fill on the current cursor location.
            //
            CanvasFillOn(g_psUpdateWidgets + ulPos);

            //
            // Clear the button press flags so that any button presses that
            // occur during the firmware update are ignored.
            //
            HWREGBITW(&g_ulFlags, FLAG_UP_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_DOWN_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_LEFT_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_RIGHT_PRESSED) = 0;
            HWREGBITW(&g_ulFlags, FLAG_SELECT_PRESSED) = 0;
        }
    }
}