![](/media/cache/group/download_IjbieK2.png.50x50_q85.png)
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
ESCMControlApp.cpp
- Committer:
- foxbrianr
- Date:
- 2019-09-17
- Revision:
- 6:010ceb99f7b0
- Parent:
- 5:65f21c0b6b79
- Child:
- 7:0244f1a26545
File content as of revision 6:010ceb99f7b0:
/************************************************************************** * @file ESCMControlApp.cpp * @brief Main class for wrapping the interface with ESCM Control * 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 "ESCMControlApp.h" #include "SPI_MX25R.h" // --------------------------------------------------------------------- // External IO for the ESCM Io Board // --------------------------------------------------------------------- Serial escmRs485_Input(p9, p10, 9600); //tx,rx,baud DigitalOut escmRs485_Mode (p11); //Transmit = 1, Receive = 0 // --------------------------------------------------------------------- // External IO for the MicroComm ESCM Control Board // --------------------------------------------------------------------- Serial microCommRs485_Tx(p13, p14, 9600); //tx,rx,baud DigitalOut microCommRs485_Mode (p12); //Transmit = 1, Receive = 0 CAN microCommCanItf (p30, p29, 50000); // rx,tx DigitalOut microCommCan_Mode (p25); //Silent Mode = 1, Normal = 0 // --------------------------------------------------------------------- // External IO for the Speaker / EMIC2 board // --------------------------------------------------------------------- emic2 speaker(p28, p27); //serial RX,TX pins to emic Mutex sound_mutex; // --------------------------------------------------------------------- // External MEMORY for the FAULT AND ADDRESS MAPS (not used) // --------------------------------------------------------------------- SPI_MX25R spi_memory (p5, p6, p7, p8); // --------------------------------------------------------------------- ESCM_EventLog escmEventLog; // --------------------------------------------------------------------- AddressMap addressMap; // --------------------------------------------------------------------- RealTimeClock rtc; /* for incoming messages */ CircularBuffer<event_t, 64> message_queue; /* for button presses */ CircularBuffer<event_t, 64> event_queue; /* for playing sound */ CircularBuffer<playbackMessage_t, 10> playback_queue; // --------------------------------------------------------------------- void setCurrentTime (char* timeBuf) { time_t rawtime; struct tm * timeinfo; time ( &rawtime ); timeinfo = localtime ( &rawtime ); int hours = timeinfo->tm_hour; int mins = timeinfo->tm_min; int secs = timeinfo->tm_sec; int years = timeinfo->tm_year + 1900; int months = timeinfo->tm_mon + 1 ; int days = timeinfo->tm_mday; sprintf(timeBuf,"%0d/%0d/%04d %02d:%02d:%02d", months,days,years,hours,mins,secs ); printf("NEW %s\n", timeBuf); } // --------------------------------------------------------------------- void ESCMControlApp::init() { // set on power, should not change escmRs485_Mode = 0; // Receive microCommRs485_Mode = 1; // Transmit microCommCan_Mode = 0; // Normal mode (turn on CNA transeiver) escmEventLog.init(); addressMap.init(); cur_address = 0; if (escmEventLog.size()>0) { cur_address = escmEventLog.index(0)->address; } } // --------------------------------------------------------------------- void ESCMControlApp::update(void) { static int counter = 0; char value; int msgCount = 0; int nChar = 0; int new_address = 0; bool update_needed = 0; char dataRxBuffer[4]; if(escmRs485_Input.readable() ) { //rx485Message(); while (msgCount < 10 && (value = escmRs485_Input.getc())) { //printf("%02x ",value); dataRxBuffer[nChar++]=value; if(nChar==4) { // read 4 characters if (dataRxBuffer[2] == 0xd && dataRxBuffer[3] == 0xa) { new_address = 10*(dataRxBuffer[0] -0x30) + (dataRxBuffer[1] -0x30); printf("ADDR = %d ",new_address); update_needed = 1; // receive at least 1 nChar = 0; dataRxCnt++; msgCount++; break; } } } } if (update_needed) { if (new_address >= 0 && new_address < 100 ) { cur_address = new_address; printf("New Addr=%d\n",cur_address); postEvent(cur_address,0); counter = 0; new_address = -1; } else { for (int i=0;i<4;i++) printf( "%0x ", dataRxBuffer[i]); error("ERROR: INVALID_ADDR=[%d] [%d]\n", cur_address, new_address); } } if (counter == 0 ) { relayMessage (cur_address); counter = 5; //send .5 sec dataTxCnt++; } counter--; } /*************************************************************************/ void ESCMControlApp::processMessageQueue () { event_t e; if (message_queue.empty()) return; while (!message_queue.empty()) { message_queue.pop(e); tx485Message(e.event); ThisThread::sleep_for(100); } } /*************************************************************************/ void ESCMControlApp::processSoundQueue () { playbackMessage_t e; if (playback_queue.empty()) return; // drain the queue while (!playback_queue.empty()) { playback_queue.pop(e); ThisThread::sleep_for(500); } // emic is very slow so play last message speaker.speakf("S"); //Speak command starts with "S" speaker.speakf(e.message); // Send the desired string to convert to speech speaker.speakf("\r"); //marks end of speak command speaker.ready(); //ready waits for speech to finish from last command with a ":" response } /*************************************************************************/ void ESCMControlApp::info (char *format, ...) { char buffer[128]; va_list args; va_start(args, format); vsprintf(buffer,format,args); printf("\nINFO:%s"); va_end(args); } /*************************************************************************/ void ESCMControlApp::warning (char *format, ...) { char buffer[128]; va_list args; va_start(args, format); vsprintf(buffer,format,args); printf("\nWARNING:%s"); va_end(args); } /*************************************************************************/ void ESCMControlApp::error (char *format, ...) { char buffer[128]; va_list args; va_start(args, format); vsprintf(buffer,format,args); printf("\n---------------------------------------------------"); printf("\nERROR:%s"); va_end(args); } /*************************************************************************/ void ESCMControlApp::say (int address) { char * desc = addressMap.getDescription(address); if (strlen(desc) > 0) { escmController.say("%s is open", desc ); } else { escmController.say("Unit %d is open", address ); } } /*************************************************************************/ void ESCMControlApp::say (char *format, ...) { playbackMessage_t e; char buffer[128]; va_list args; va_start(args, format); vsprintf(e.message,format,args); // note: immediately going to the emic blocks calling thread #if 0 speaker.speakf("S");//Speak command starts with "S" speaker.speakf(e.message); speaker.speakf("\r"); speaker.ready(); #else if (!playback_queue.full()) { playback_queue.push(e); } else { printf("Sound Queue Full\n"); } #endif va_end(args); } /*************************************************************************/ void ESCMControlApp::postEvent (uint16_t address) { event_t e; e.event = address; if (!message_queue.full()) { message_queue.push(e); } else { printf("Message Queue Full\n"); } } /************************************************************************* * The following function is called with a new event is received to * update the related parts *************************************************************************/ void ESCMControlApp::postEvent (uint16_t address, uint16_t source) { if ( address >= 0 && address < 100 ) { escmEventLog.add(address, source); ESCMControlApp::refresh_display(); #if 0 ESCMControlApp::say("Unit %d is open", address); #else ESCMControlApp::say("%s is open", addressMap.getDescription(address)); #endif } else { //ignore it } } /*************************************************************************/ void ESCMControlApp::refresh_display(void) { // Note: we only refresh the event log display to avoid LCD flashing // -- #if 1 showEvents.update_needed=1; #else Menu::getCurrentMenu()->update_needed=1 #endif } /************************************************************************* * The following function get time *************************************************************************/ void ESCMControlApp::getTime(char *timeBuf) { time_t rawtime; struct tm * timeinfo; time ( &rawtime ); timeinfo = localtime ( &rawtime ); int hours = timeinfo->tm_hour; int mins = timeinfo->tm_min; int secs = timeinfo->tm_sec; int years = timeinfo->tm_year + 1900; int months = timeinfo->tm_mon + 1 ; int days = timeinfo->tm_mday; sprintf(timeBuf,"%0d/%0d/%04d %02d:%02d:%02d", months,days,years,hours,mins,secs ); printf("TIME: %s\n", timeBuf); } /************************************************************************* * The following functdion sets time which set the RTC *************************************************************************/ void ESCMControlApp::setTime(int hours, int mins, int sec, int months, int days, int years ) { struct tm t; t.tm_hour = hours; t.tm_min = mins; t.tm_sec = 0; t.tm_year = years - 1900; t.tm_mon = months - 1; t.tm_mday = days; // set the time set_time(mktime(&t)); } /*************************************************************************/ void ESCMControlApp::relayMessage (int address) { //printf("Current_Address is %d \n\r", cur_address ); if (address >= 0 && address < 100 ) { tx485Message(address); //send on rs485 #if 1 // currently 501 & 502 control output txCanMessage501(address);//send on can txCanMessage502(address); #else txCanMessage580(address); #endif } else { error("relay: INVALID_ADDR=%d\n", address); } } /************************************************************************* * The following information is from the MicroComm_gen_input.doc * * Message is always 12 bytes with Check Sum * Byte 1 : 40 * Byte 2 : Indictator * arrival_dn_arrow :1, bit 1 * arrival_up_arrow :1, bit 0 * * Byte 3 : Scan_slot. * Byte 4 : Message_number. * Byte 5 : Indictor * traveling dn arrow :1, bit 1 * traveling up arrow :1, bit 0 * * Byte 6 : ASCII floor char, msb * Byte 7 : ASCII floor char, * Byte 8 : ASCII floor char, lsb * Note: floor ASCII range is 0x30 through 0x5a (‘0’ – ‘Z’). * 0x3a through 0x40 are special characters with * 0x3b being the space or blank character(semicolon) * 0x3d is normally displayed as a minus character. * * * Byte 9 : ASCII msg char, msb * Byte 10 : ASCII msg char, * Byte 11 : ASCII msg char, lsb * Note: message ASCII range is 0x30 through 0x5b (‘0’ – ‘[’). * 0x3a through 0x40 are special characters with * 0x3b being the space or blank character(semicolon) * 0x5d is sent when there is no message (instead of spaces). * * * Byte 12 : checksum * * note messages are sent .5 - 1 sec using 485 Bus *************************************************************************/ void ESCMControlApp::tx485Message(int address) { int sum =0; char dataTxBuffer[12]; if (address >= 0 && address < 100 ) { sum += dataTxBuffer[0] = 0x40; // fixed value sum += dataTxBuffer[1] = 0x01; sum += dataTxBuffer[2] = address; // floor number sum += dataTxBuffer[3] = 0x0; sum += dataTxBuffer[4] = 0x0; //--- sum += dataTxBuffer[5] = 0x0; sum += dataTxBuffer[6] = (0x30 + address / 10); sum += dataTxBuffer[7] = (0x30 + address % 10); //--- sum += dataTxBuffer[8] = 0x0; sum += dataTxBuffer[9] = 'F'; sum += dataTxBuffer[10] = 'X'; sum += dataTxBuffer[11] = (char)(~sum +1); for(int i= 0; i<12; i++) { microCommRs485_Tx.putc(dataTxBuffer[i]); } } else { warning("tx485: invalid address %d",address ); } } /************************************************************************* * The following information is from the ElevCANtoMC * for CAN Message 0x501 * * Byte 1 * Front arrows * Bit 0 – Front arrival arrow up * Bit 1 – Front arrival arrow down * Bit 2 – Play Strobe * Bit 3-5 – Reserved * Bit 6 – Fire Warning Lamp * Byte 2 * Floor Number. A floor number of 0 is not a valid. * Byte 3 * Priority message number * Byte 4 * Travel and rear arrows * Bit 0 – Travel arrow up * Bit 1 – Travel arrow down * Bit 2 – unused * Bit 3 – Passing Chime * Bit 4 – Message Level Low Bit * Bit 5 – Message Level High Bit * Bit 6 – Rear arrival arrow up * Bit 7 – Rear arrival arrow down * Byte 5-8 * Reserved * * * note messages are to come .5 - 1 sec using 50K CAN Bus ********************************************************************/ void ESCMControlApp::txCanMessage501 (int address) { static int counterTx = 0; char data[8]; if (address >= 0 && address < 100 ) { data[0] = (counterTx%2)?0x1:0x2; // toggle arrow data[1] = (uint8_t)address; // numerical floor # data[2] = 0x0; data[3] = (counterTx%2)?0x1:0x2; // toggle travel arrow data[4] = 0x0; data[5] = 0x0; data[6] = 0x0; data[7] = 0x0; if(microCommCanItf.write(CANMessage(0x501, data, 8))) { //printf("Message 501:(%d) sent via CAN: %d\n\r",counterTx, address); counterTx++; } else { //printf("Message 501: Reset\n\r"); microCommCanItf.reset(); } } else { warning("tx501: invalid address %d",address ); } } /************************************************************************* * The following information is from the ElevCANtoMC * for CAN Message 0x502 * Byte 1 * Floor marking character (leftmost) * Byte 2 * Floor marking character * Byte 3 * Floor marking character (rightmost) * Byte 4 * Message marking character (leftmost) * Byte 5 * Message marking character * Byte 6 * Message marking character (rightmost) * Byte 7 * Lantern Position (ThyssenKrupp) * Byte 8 * Unused * * note messages are to come .5 - 1 sec using 50K CAN Bus ********************************************************************/ void ESCMControlApp::txCanMessage502 (int address) { static int counterTx = 0; char data[8]; if (address >= 0 && address < 100 ) { data[0] = 0x0; data[1] = (0x30 + address / 10); // assumes address is 0-9 range data[2] = (0x30 + address % 10); // assumes address is 0-9 range data[3] = 0x0; data[4] = (0x30 + address / 10); // assumes address is 0-9 range data[5] = (0x30 + address % 10); // assumes address is 0-9 range data[6] = 'F'; data[7] = 0x0; if(microCommCanItf.write(CANMessage(0x502, data, 8))) { //printf("Message 502: (%d) sent via CAN: %d\n\r",counterTx, address); counterTx++; } else { microCommCanItf.reset(); } } else { warning("tx503: invalid address %d",address ); } } /************************************************************************* * The following information is from the ElevCANtoMC * for CAN Message 0x580 * Byte 1 * Floor Number. A floor number of 0 is not a valid floor position and should only be used when translating from a source that does not provide numeric position data. * Byte 2 * Floor marking character (leftmost) [the MICRO COMM® converter does not support this character] * Byte 3 * Floor marking character * Byte 4 * Floor marking character * Byte 5 * Floor marking character (rightmost) * Byte 6 * Bit 0 – Front in-car arrow up * Bit 1 – Front in-car arrow down * Bit 2 – Rear in-car arrow up * Bit 3 – Rear in-car arrow down * Bit 4 – Travel arrow up * Bit 5 – Travel arrow down * Bit 6 – Passing chime * Bit 7 – Unused * Byte 7 * Hall Arrows * Bit 0 – Front arrival arrow up * Bit 1 – Front arrival arrow down * Bit 2 – Front gong up * Bit 3 – Front gong down * Bit 4 – Rear arrival arrow up * Bit 5 – Rear arrival arrow down * Bit 6 – Rear gong up * Bit 7 – Rear gong down * Byte 8 * Target display number (This is not used by most controllers. * Just leave this set to 0xFF for basic controller operation). * If this is used, it only applies to data located in Byte 7. * * note messages are to come .5 - 1 sec using 50K CAN Bus ********************************************************************/ void ESCMControlApp::txCanMessage580 (int address) { static int counterTx = 0; char data[8]; if (address >= 0 && address < 100 ) { data[0] = address; data[1] = 0x0; data[2] = 0x0; data[3] = (0x30 + address / 10); data[4] = (0x30 + address % 10); data[5] = (counterTx%2)?0x1:0x2; data[6] = 0x0A;//front down and gong down data[7] = 0xFF; if(microCommCanItf.write(CANMessage(0x580, data, 8))) { //printf("Message 580: (%d) sent via CAN: %d\n\r",counterTx, address); counterTx++; } else { microCommCanItf.reset(); } } else { warning ("tx580: invalid address %d",address ); } }