demo new haven display

Dependencies:   LCD Menu ButtonCtrl TimeManagement EventLog AddressMap emic2

ESCM 2000 Control and Display application provides interface for the LPC1768 processor boards with the ECSM 2000 system.

This application implements SW interface : - RX 485 Receive from physical system - RX 485 Interface to send toECOM / ESCM board - CAN Interface to send to ECOM / ESCM board - 4x40 LCD with menu controls - RTC configuration -EMIC2 Sound Card - GPIO Extender to push buttons etc

main.cpp

Committer:
foxbrianr
Date:
2019-09-27
Revision:
8:f15a5358883c
Parent:
7:0244f1a26545
Child:
10:f221dd1ef77b

File content as of revision 8:f15a5358883c:

/**************************************************************************
 * @file     main.cpp
 * @brief    Main function for ESCM Control System
 *           Application
 * @version: V1.0
 * @date:    9/17/2019

 *
 * @note
 * Copyright (C) 2019 E3 Design. All rights reserved.
 *
 * @par
 * E3 Designers LLC is supplying this software for use with Cortex-M3 LPC1768
 * processor based microcontroller for the ESCM 2000 Monitor and Display.  
 *  *
 * @par
 * THIS SOFTWARE IS PROVIDED "AS IS".  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.
 * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 ******************************************************************************/
#include "mbed.h"
#include "rtos.h"
#include "stats_report.h"
#include "math.h"
#include "LCD.h"

#include "ButtonController.h"

#include "ESCMControlApp.h"

#include "Menu.h"
#include "EditTimeMenu.h"
#include "EditAddressMenu.h"
#include "DisplayCodesMenu.h"
#include "FactoryResetMenu.h"

#define SLEEP_TIME                  500 // (msec)
#define PRINT_AFTER_N_LOOPS         10

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

SystemReport *sys_state;
/*-------------------------------------------------------------------
 * define displays
 *-------------------------------------------------------------------*/
Serial pc(USBTX, USBRX); // tx, rx

#define MAX_THREADS 6
Thread * threads [MAX_THREADS]; 

/*-------------------------------------------------------------------
 * define displays
 *-------------------------------------------------------------------*/
LCD   lcd;

/*-------------------------------------------------------------------
 * define displays
 *-------------------------------------------------------------------*/
Menu                    rootMenu    ("root menu");
EditTimeMenu            editTime    ("Edit Time");
EditAddressMenu         editAddress ("Edit Addresses");
DisplayCodesMenu        showEvents  ("Display Events" );
FactoryResetMenu        factoryReset("Factory Reset" );

/*-------------------------------------------------------------------
 * define display escmBtnController
 *-------------------------------------------------------------------*/
ButtonController escmBtnController;

/*-------------------------------------------------------------------
 * define application
 *-------------------------------------------------------------------*/
ESCMControlApp escmController;

static int dataRxCnt = 0;
/*-------------------------------------------------------------------
 * define led toggles for diagnostics
 *-------------------------------------------------------------------*/
void toggleLed1(){    led1 = !led1;}
void toggleLed2(){    led2 = !led2;}
void toggleLed3(){    led3 = !led3;}
void toggleLed4(){    led4 = !led4;}

static volatile uint64_t idle;

#if DEBUG
OsTaskPerfData_t g_perfData;
void InitPerfData()
{
    for (int i=0;i<MAX_THREADS;i++) 
   {
      g_perfData.task[i].counter      = 0;
      g_perfData.task[i].deltaTime    = 0;
      g_perfData.task[i].deltaTimeMax = 0;
      g_perfData.task[i].deltaTimeMin = 0xFFFFFFFFu;
      g_perfData.task[i].deltaTimeAve = 0;
      
      g_perfData.task[i].cycleTimeMax = 0;
      g_perfData.task[i].cycleTimeMin = 0xFFFFFFFFu;
      g_perfData.task[i].cycleTimeAve = 0;
      
      g_perfData.task[i].timeStamp     = 0;
      g_perfData.task[i].lastTimeStamp = 0;
   }
}

void UpdatePerfDataStart(OsPerfData_t *data)
{
    #if 1
    if (data != NULL) {
        uint64_t now = Kernel::get_ms_count();
        data->counter++;
        data->timeStamp     = now;
        data->cycleTime     = data->timeStamp - data->lastTimeStamp;
        if (data->cycleTime > data->cycleTimeMax ) data->cycleTimeMax = data->cycleTime;
        if (data->cycleTime < data->cycleTimeMin ) data->cycleTimeMin = data->cycleTime;
        data->cycleTimeAve  = (data->cycleTime - data->cycleTimeAve)/2;
        data->lastTimeStamp = data->timeStamp;
    }
    #endif
}

void UpdatePerfDataStop(OsPerfData_t *data)
{
    #if 1
    if (data != NULL) {
        uint64_t now = Kernel::get_ms_count();
        data->deltaTime     = now - (data->timeStamp);
        if (data->deltaTime > data->deltaTimeMax ) data->deltaTimeMax = data->deltaTime;
        if (data->deltaTime < data->deltaTimeMin ) data->deltaTimeMin = data->deltaTime;
        data->deltaTimeAve  = (data->deltaTime + data->deltaTimeAve)/2;
        data->timeStamp     = now;

    }
    #endif
}
 
void ShowPerfData (OsPerfData_t *data)
{
}
#endif

/***********************************************************************
* Thread to read GPIO and handle events
***********************************************************************/

void ReadGPIOExtender(void) 
{
    uint8_t code = 0;

    Timer t;
    
    pc.printf("Starting escmBtnController task\n" );
    toggleLed4();
    
    while (true) {
        t.reset();
        t.start();
        escmBtnController.update();
        toggleLed4();
        ThisThread::sleep_for(50);
        
        t.stop();
        //printf("<1> %d ms\n", t.read_ms());
    }
}

/***********************************************************************
* Thread to read GPIO and handle events
***********************************************************************/

void ESCMController_Update(void) 
{

    pc.printf("Starting escmIOController task\n" );

    while(1) {
        
#if DEBUG
        UpdatePerfDataStart(&g_perfData.task[0]);
#endif
        escmController.update();
        
#if DEBUG
        UpdatePerfDataStop(&g_perfData.task[0]);
#endif
        ThisThread::sleep_for(200);
    }
}


/***********************************************************************
* Update LCD Display Thread
***********************************************************************/

void UpdateDisplay(void)
{
    static int counter = 0;
    
    pc.printf("Starting escmDisplay task\n" );

    lcd.init();
    lcd.cls();
    lcd.locate(0,0);
    lcd.printf ("Initializing System..");
    
    toggleLed3();
    
    Menu *activeMenu = Menu::setCurrentMenu (&showEvents);
    
    while (true) {

#if DEBUG
        UpdatePerfDataStart(&g_perfData.task[2]);
#endif
        #if AUTO_REFESH_ENABLED
        // note force a refresh
        if (counter==0) {
            activeMenu->update_needed = 1;
            counter = 100;
        }
        counter--;
        #endif
        if (activeMenu == NULL){
            lcd.printf ("ERROR: Invalid Menu Selected..");
            continue;
        }
        else {
            
            if ( activeMenu != Menu::getCurrentMenu() )
            {
                activeMenu = Menu::getCurrentMenu() ;
                activeMenu->update_needed = 1;
            }
            else
            {
            
                escmBtnController.processCmdQueue(activeMenu);
            }
            
            activeMenu->DrawDisplay(&lcd);  
        }

        toggleLed3();
        
#if DEBUG
        UpdatePerfDataStop(&g_perfData.task[2]);
#endif
        ThisThread::sleep_for(10);

    }
}
/***********************************************************************
* Play sounds
* TODO: should have its own queue.
***********************************************************************/

void PlaySound(void) // const *name)
{
    led2 = 1;
    pc.printf("Starting escmSound task\n" );

    while (1) {
        
#if DEBUG
        UpdatePerfDataStart(&g_perfData.task[3]);
#endif
        toggleLed2();
        escmController.processSoundQueue();
        
#if DEBUG
        UpdatePerfDataStop(&g_perfData.task[3]);
#endif
        Thread::wait(200);
    }
}


#if DEBUG
/***********************************************************************
* Dumps thread stats
***********************************************************************/

void PrintSystemStats (void)
{
    uint32_t frameCount = 0;
    while(1) {
        frameCount++;
        if ((0 == frameCount) || (PRINT_AFTER_N_LOOPS == frameCount)) {
            // Following the main thread wait, report on the current system status
            sys_state->report_state();
#if 1

            pc.printf("IDLE=%d", idle);
            pc.printf("\nThread   | cntr  | T     | Cycle Time             | Delta Time ");
            pc.printf("\n-------------------------------------------------------------------- ");
            pc.printf("\n");
            
            for(int i = 0; i<MAX_THREADS; i++) {
                pc.printf("%-8d | %-5d | %-5d | %-5d | %-5d | %-5d | %-5d | %-5d | %-5d \n\r",
                    i ,
                    g_perfData.task[i].counter ,
                    g_perfData.task[i].timeStamp ,
                    g_perfData.task[i].cycleTimeAve ,
                    g_perfData.task[i].cycleTimeMax ,
                    g_perfData.task[i].cycleTimeMin ,
                    g_perfData.task[i].deltaTimeAve ,
                    g_perfData.task[i].deltaTimeMax ,
                    g_perfData.task[i].deltaTimeMin );
            }
#else
            pc.printf("\nThread | size | free | used |  max | ");
            pc.printf("\n------------------------------------ ");
            pc.printf("\n");
            
            for(int i = 0; i<MAX_THREADS; i++) {
                pc.printf("\n%-8d | %4d | %4d | %4d | %4d |",
                          i,
                          threads[i]->stack_size(),
                          threads[i]->free_stack(),
                          threads[i]->used_stack(),
                          threads[i]->max_stack()
                         ) ;

            }
#endif

            pc.printf("\n------------------------------------ ");
            pc.printf("\n");
            
            escmEventLog.save();
            frameCount = 0;
        }
        
        Thread::wait(200);
    }
}
#endif


#if TEST
/***********************************************************************
* Handle Terminal Prompts
* TODO: should have its own queue.
***********************************************************************/

void TerminalPrompt(void) // const *name)
{
    
    pc.printf("Starting escmTerm task\n" );
    
    while (1)
    {
        int c;
        pc.printf("\n>>");
        pc.scanf("%d", &c);
        
        /* echo */
        pc.printf("\n%0d",c);
        
        if ( c >= 0 && c < 99) {        
            ESCMControlApp::postEvent((uint16_t)c,99); 
        }
        else if (c==555)
        {
            addressMap.reset();
        }        
        else if (c==666)
        {
            escmEventLog.reset();
        }
        else if (c==999)
        {
            pc.printf("\nThread   | size | free | used |  max | ");
            pc.printf("\n------------------------------------ ");
            for(int i = 0; i<MAX_THREADS; i++) {
                pc.printf("\n%-8d | %4d | %4d | %4d | %4d |",
                          i,
                          threads[i]->stack_size(),
                          threads[i]->free_stack(),
                          threads[i]->used_stack(),
                          threads[i]->max_stack()
                         ) ;
            }
        }
        else
        {
        }
    }
}
/***********************************************************************
* process incoming messages from rx485 serial (ISR)
***********************************************************************/

void rx485Message() {
    
#if 1
    dataRxCnt++;
#else
    // Note: you need to actually read from the serial to clear the RX interrupt
    int dataRxBuffer[4];
    int value = rs485port1.getc();
    
    if (value){
        dataRxBuffer[dataRxCnt++]=value;
        
        if(dataRxCnt==4) {
            cur_address = 10*(dataRxBuffer[0] -0x30) + (dataRxBuffer[1] -0x30);
            memset(dataRxBuffer,0,sizeof(dataRxBuffer));
            dataRxCnt=0; 
        }
        else
        {
            // do nothing
        }
    }
#endif
}
#endif
/***********************************************************************
* Main Loop
***********************************************************************/
void backgroundTask(void)
{
    idle++;
}
/***********************************************************************
* Main Loop
***********************************************************************/

int main()
{    pc.printf("\n\r");
    
    pc.printf("=====================================\n\r");
    pc.printf("= ESCM 2000                         =\n\r");
    pc.printf("= %s %s                             =\n\r", __DATE__ , __TIME__);
    pc.printf("= v0.01                             =\n\r");
    pc.printf("=====================================\n\r");

    sys_state = new SystemReport( SLEEP_TIME * PRINT_AFTER_N_LOOPS /* Loop delay time in ms */);
    
    
    Kernel::attach_idle_hook(&backgroundTask);
    
    led1=1;
    led1=!led1;

    
#if DEBUG
    InitPerfData();
#endif

    // -----------------------------------
    // set LCD configuration
    // -----------------------------------
    lcd.init();
    lcd.cls();
    lcd.locate(0,0);
    lcd.printf ("Initializing System..");
   
    // -----------------------------------
    // set EMIC speaker configuration
    // -----------------------------------
    speaker.volume(18);
    speaker.voice(3);
    
    escmController.say("Welcome ESCM");

    // -----------------------------------
    // initialize main controller
    // -----------------------------------
    escmController.init();
    
    //escmRs485_Input.attach ( &rx485Message );
    //addressMap.display(&pc);
    
    toggleLed1();

    // -----------------------------------
    // Setup menus
    // -----------------------------------
    rootMenu.add(&showEvents);
    rootMenu.add(&editTime);
    rootMenu.add(&editAddress);
    rootMenu.add(&factoryReset);
    Menu::setCurrentMenu (&rootMenu);

    toggleLed1();
    
    // -----------------------------------
    // Setup threads
    // -----------------------------------
    threads[0] = new Thread(osPriorityNormal5, 0x300 );
    threads[1] = new Thread(osPriorityNormal4, 0x500 );
    threads[2] = new Thread(osPriorityNormal3, 0x1000 );
    threads[3] = new Thread(osPriorityNormal2, 0x400 );
#if DEBUG
    threads[4] = new Thread(osPriorityNormal1, 0x200 );
#endif

#if TEST
    threads[5] = new Thread(osPriorityLow,     0x100 );
#endif

   
    // -----------------------------------
    // Start threads
    // -----------------------------------
    threads[0]->start(ESCMController_Update);
    threads[1]->start(ReadGPIOExtender);
    threads[2]->start(UpdateDisplay);
    threads[3]->start(PlaySound);
#if DEBUG
    //threads[4]->start(PrintSystemStats);
#endif

#if TEST
    threads[5]->start(TerminalPrompt);
#endif
    
    // -----------------------------------
    // Loop forever
    // -----------------------------------
    while(1) {
        toggleLed1();
        ThisThread::sleep_for(500);
    }
}