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

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;
-}
+