![](/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
Diff: ESCMControlApp.cpp
- Revision:
- 5:65f21c0b6b79
- Parent:
- 3:ecaf9963341b
- Child:
- 6:010ceb99f7b0
--- a/ESCMControlApp.cpp Thu Jul 25 00:46:02 2019 +0000 +++ b/ESCMControlApp.cpp Thu Sep 12 11:28:26 2019 +0000 @@ -1,27 +1,50 @@ #include "mbed.h" #include "ESCMControlApp.h" +#include "SPI_MX25R.h" + +// --------------------------------------------------------------------- +// External IO for the ESCM Control Board +// +// --------------------------------------------------------------------- +Serial escmRs485_Input(p9, p10, 9600); //tx,rx,baud +DigitalOut escmRs485_Mode (p11); //Transmit = 1, Receive = 0 + +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 -Serial rs485port1(p9, p10, 9600); //tx,rx,baud -DigitalOut rs485port1mode (p11); //Transmit = 1, Receive = 0 +// --------------------------------------------------------------------- +// External IO for the Speaker / EMIC2 board +// --------------------------------------------------------------------- +emic2 speaker(p28, p27); //serial RX,TX pins to emic -Serial rs485port2(p13, p14, 9600); //tx,rx,baud -DigitalOut rs485port2mode (p12); //Transmit = 1, Receive = 0 - -CAN canport (p30, p29); // rx,tx -DigitalOut canportmode (p25); //Silent Mode = 1, Normal = 0 +// --------------------------------------------------------------------- +// External MEMORY for the FAULT AND ADDRESS MAPS +// --------------------------------------------------------------------- +SPI_MX25R spi_memory (p5, p6, p7, p8); -emic2 speaker(p28, p27); //serial RX,TX pins to emic - +// --------------------------------------------------------------------- Mutex sound_mutex; - ESCM_EventLog escmEventLog; -static int dataRxCnt = 0; -static int cur_address = 0; +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) @@ -41,130 +64,517 @@ int months = timeinfo->tm_mon + 1 ; int days = timeinfo->tm_mday; - sprintf(timeBuf,"%0d/%0d/%04d %02d:%02d:%02d\0", + sprintf(timeBuf,"%0d/%0d/%04d %02d:%02d:%02d", months,days,years,hours,mins,secs ); + + printf("NEW %s\n", timeBuf); } -void rx485Message() { - // Note: you need to actually read from the serial to clear the RX interrupt - int dataRxBuffer[4]; - char timeBuffer[40]; - - 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; - printf("ADDR=%d\n",cur_address); - - setCurrentTime(timeBuffer); - escmEventLog.add(cur_address, timeBuffer); - ESCMControlApp::say("Unit %d is open",cur_address); - } - } -} - - - void ESCMControlApp::init() { - rs485port1mode = 0; // Receive - rs485port2mode = 1; // Transmit - canportmode = 0; // Normal mode + // set on power, should not change + escmRs485_Mode = 0; // Receive + microCommRs485_Mode = 1; // Transmit + microCommCan_Mode = 0; // Normal mode (turn on CNA transeiver) - rs485port1.attach(&rx485Message); + //escmRs485_Input.attach(&rx485Message); + + escmEventLog.init(); + + addressMap.init(); + + if (escmEventLog.size()>0) + { + cur_address = escmEventLog.index(0)->address; + } } void ESCMControlApp::update(void) { - #if 0 - if(rs485port1.readable() ) + static int new_address = -1; + static int rxCount = 0; + static int counter = 0; + char value; + bool update_needed = 0; + #if 1 + if(escmRs485_Input.readable() ) { - rx485Message(); + //rx485Message(); + + int dataRxBuffer[4]; + while ( value = escmRs485_Input.getc() ) { + dataRxBuffer[rxCount++]=value; + if(rxCount==4) { // read 4 characters + if (dataRxBuffer[2] == 0xd && dataRxBuffer[3] == 0xa) { + new_address = 10*(dataRxBuffer[0] -0x30) + (dataRxBuffer[1] -0x30); + printf("ADDR=%d\n",new_address); + update_needed = 1; + dataRxCnt++; + break; + } + } + } + // reset cnt; + rxCount = 0; + memset(dataRxBuffer,0,sizeof(dataRxBuffer)); } + #endif + + if (update_needed) + { + if (new_address >= 0 && new_address < 100 ) + { + cur_address = new_address; + printf("ADDR=%d\n",cur_address); + postEvent(cur_address,0); + counter = 0; + new_address = -1; + } else { + + printf("ERROR: INVALID_ADDR=%d\n",new_address); + } + } + - if (cur_address) + if (cur_address >= 0 && cur_address < 100 ) + { + + if (counter == 0 ) { + + tx485Message(cur_address); //send on rs485 +#if 1 + txCanMessage501(cur_address);//send on can + txCanMessage502(cur_address); +#else + txCanMessage580(cur_address); +#endif + counter = 5; //send .5 sec + dataTxCnt++; + //printf("Current_Address is %d \n\r", cur_address ); + } + } + else { - tx485Message(cur_address); - say("%d is open", cur_address); + printf("ERROR: INVALID_ADDR=%d\n",cur_address); + } + counter--; +} + +/*************************************************************************/ +void ESCMControlApp::processMessageQueue () +{ + event_t e; + + if (message_queue.empty()) + return; + + while (!message_queue.empty()) { + message_queue.pop(e); + + tx485Message(e.event); + + Thread::wait(100); + } +} + +/*************************************************************************/ +void ESCMControlApp::processSoundQueue () +{ + playbackMessage_t e; + + if (playback_queue.empty()) + return; + + while (!playback_queue.empty()) { + playback_queue.pop(e); + 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::say (char *format, ...) { + + playbackMessage_t e; + char buffer[128]; va_list args; va_start(args, format); - vsprintf(buffer,format,args); - + vsprintf(e.message,format,args); +#if 0 speaker.speakf("S");//Speak command starts with "S" - speaker.speakf(buffer); + 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"); + } +} -void ESCMControlApp::tx485Message(int address) { + +/************************************************************************* + * 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); + //escmEventLog.save(); + + 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) +{ + printf("$"); + Menu::getCurrentMenu()->update_needed=1; +} + +/************************************************************************* + * 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\0", + 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)); +} + + +/************************************************************************* + * 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]; - sum += dataTxBuffer[0] = 0x40; - 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] = 0x0; - sum += dataTxBuffer[10] = 0x0; - sum += dataTxBuffer[11] = (char)(~sum +1); - - for(int i= 0;i<12;i++){ - rs485port2.putc(dataTxBuffer[i]); + + 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 { + printf ("Error: 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 { + printf ("Error: 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) { - CANMessage canMessage(502); - - canMessage.len = 8; + static int counterTx = 0; + char data[8]; - canMessage.data[0] = 0x0; - canMessage.data[1] = (0x30 + address / 10); - canMessage.data[2] = (0x30 + address % 10); - canMessage.data[3] = 0x0; - canMessage.data[4] = 0x0; - canMessage.data[5] = 0x0; - canMessage.data[6] = 0x0; - canMessage.data[7] = 0x0; - - wait_ms(5); //Wait a bit for the mode the first time - if(canport.write(canMessage)) { - printf("Message sent via CAN: %d\n\r", address); - } + 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 { + //printf("Message 502: Reset\n\r"); + microCommCanItf.reset(); + } + + } else { + printf ("Error: 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 { + //printf("Message 580: Reset\n\r"); + microCommCanItf.reset(); + } + + + } else { + printf ("Error: invalid address %d",address ); + } } -Menu ESCMControlApp::getAddressMenu() -{ - return NULL; -} +