breakLIN_RacEI

Dependencies:   mbed mbed-rtos Watchdog MODSERIAL ConfigFile

main.cpp

Committer:
JavierGC
Date:
2021-02-22
Revision:
0:939d1f478fb5

File content as of revision 0:939d1f478fb5:

#include "mbed.h"
#include "rtos.h"
#include "MODSERIAL.h"
#include "Watchdog.h"
#include "ConfigFile.h"

/***** DEFINITIONS *****/
#define TxBuffer_NumMess 16
#define RxBuffer_NumMess 16
#define MessSizePC 128
#define MessSizeLIN 128
#define TxBuffer TxBuffer_NumMess*MessSizePC
#define RxBuffer RxBuffer_NumMess*MessSizePC
#define PC_MaxMailElements 16
#define LIN_MaxMailElements 16
#define PCMessWait MessSizePC*10/9.6 //ms
#define LINMessWait 1//ms

/***** STRUCTURES *****/

typedef struct {    
    char command;   /* command to execute */
    char message[MessSizePC];   /* arguments */
} PC_mail_t;

typedef struct LINMessage_t  // Lin Message Structure
{
    char IDfield;
    char Data[8];   // Maximum Number of Data
    char Checksum;
} LINMessage;

typedef struct {
    char command;   /* command to execute */
    LINMessage mess;
} LIN_mail_t;

/***** FUNCTIONS *******/
void read_Full_Message(char Port_);                                                 // Reading Buffer from LIN Line [LIN Line Depends on the Port]
void send_Full_Message(char ID_Field, char Data[8], char Checksum, char Port);      // Sending a Full Message to the LIN Line
void send_Header_Message(char ID_Field,int Port);                                   // Sending a Header Message to the LIN Line
void send_Break(int Port);                                                          // Sending a Break Command to the LIN Line
void LoadPCMail(char comm,  char *mess);                                            // Puts a mail in the stuck
void messageFromPC(MODSERIAL_IRQ_INFO *q);                                          // Gets a Message from the PC and Calls the Load Mail [0]                           
int ComPC_Write(char *mess);                                                        // Send a Message Back to the PC
void TLogSTR(char *Tstr);                                                           // Get the Time signature
void GetConfig(void);                                                               // Read Configuration Data
void Initialize(void);                                                              // Initialize MBED after Reboot
void Read_Diagnostics(char *mess);                                                  // Return a Message with Diagnostics
void Flash_Messages(int Port);                                                      // Discards all messages in LIN Port
void Reset_UUT(void);                                                               // Reset The UUT
/**** Watchdog ****/
Watchdog wd;
extern "C" void mbed_reset();
/**** End of Watchdog ****/

/**** Serial Communication PC ****/
DigitalOut ledPC(LED1);
DigitalOut Reboot_Pin(p29);
MODSERIAL pc(USBTX, USBRX, TxBuffer,RxBuffer); // The USB as pc
char InitialMessage[50];                       // The initial Message when the MBED turns on 
bool LOGPC;                                    // Logging information from the PC
int PC_Baudrate=115200;                        // The Baudrate of the PC
double TxBufferWait;                           // The Time to Wait
char ChEnd;                                    // The termination character of the PC Serial Communication
Mail<PC_mail_t, PC_MaxMailElements> PC_mail;   // The PC_mail
int PCMailNum = 0;                              // Initialize to zero
time_t ctTime;
struct tm * timeinfo;

int LIN_Wait_Echo = 0;
int LIN_Wait_Response = 0;
bool Wait_Echo_Response = false;

/**** LIN 1 ****/
DigitalOut ledUART1(LED2);
MODSERIAL LIN1(p13, p14, TxBuffer,RxBuffer); // The UART1 as LIN1 
int LIN1Baud = 19200;

/**** LIN 2 ****/
MODSERIAL LIN2(p28, p27, TxBuffer,RxBuffer);  // The UART2 as LIN2
DigitalOut ledUART2(LED3);
int LIN2Baud = 19200;

void ComPC_thread_proc(void const *args) //proceso paralelo de gestión PC: tareas solicitadas y envío a PC
{
    while(true) 
    {
        osEvent evt = PC_mail.get(osWaitForever);
        if (evt.status == osEventMail) 
        {
            PC_mail_t *mail = (PC_mail_t*)evt.value.p;
            char mess[MessSizePC];
            char Tstr[20];
            TLogSTR(Tstr);
            switch (mail->command) 
            {
                case 0:                         //request from PC
                    switch(mail->message[0])
                    {
                        case 'R':                   // Reboot the Microcontroller/Updates the Firmware
                            if(strcmp(mail->message,"REBOOT")==0) {mbed_reset();/*wd.Configure(2.0);*/} 
                            else { snprintf (mess,MessSizePC,"NAK(%s):%s\r\n",Tstr, mail->message); }
                            break;
                        case 'T':                   // Set the Current Time
                            float seconds;
                            sscanf(&mail->message[1],"%f",&seconds);
                            set_time((double)seconds);
                            time_t ctTime;
                            ctTime = time(NULL);
                            snprintf(mess,MessSizePC,"%s",ctime(&ctTime));
                            LoadPCMail(1,mess);
                            break;
                        case 'L':                   // LIN Line
                            LINMessage LINMess;
                            unsigned int temp_ID;
                            unsigned int temp_Data[8];
                            unsigned int temp_Checksum;
                            switch (mail->message[1]) 
                            {
                                case '1':       //LIN 1
                                ledUART1 = true;
                                switch (mail->message[2]) 
                                {   
                                        case 'W': //Write Full Message to LIN1
                                            sscanf(&mail->message[3],"%u;%u;%u;%u;%u;%u;%u;%u;%u;%u;",&temp_ID,&temp_Data[0],&temp_Data[1],&temp_Data[2],&temp_Data[3],&temp_Data[4],&temp_Data[5],&temp_Data[6],&temp_Data[7],&temp_Checksum);
                                            LINMess.IDfield = temp_ID;
                                            LINMess.Checksum = temp_Checksum;
                                            for(int k=0; k<8; k++){ LINMess.Data[k] = temp_Data[k]; }
                                            send_Full_Message(LINMess.IDfield, LINMess.Data, LINMess.Checksum, 1); // Maybe Disable interrupts here
                                            if(Wait_Echo_Response) { wait_ms(LIN_Wait_Echo);  read_Full_Message(1);}
                                            ledUART1 = false;
                                            break;
                                        case 'H': //Write Remote Header to LIN1
                                            sscanf(&mail->message[3],"%u;",&temp_ID);
                                            LINMess.IDfield = temp_ID;
                                            send_Header_Message(LINMess.IDfield,1);
                                            if(Wait_Echo_Response) { wait_ms(LIN_Wait_Echo); wait_ms(LIN_Wait_Response); read_Full_Message(1); }
                                            ledUART1 = false;
                                            break;    
                                        case 'R': //Read Data from LIN1
                                            read_Full_Message(1);
                                            ledUART1 = false;
                                            break;  
                                        case 'T': //Reset
                                            Reset_UUT();
                                            ledUART1 = false;
                                            LoadPCMail(99,"Reset_OK");
                                            break;        
                                        default:
                                            ledUART1 = false;                                    
                                            break;
                                 }
                                    break;
                                case '2':       //LIN 2
                                ledUART2 = true;
                                switch (mail->message[2]) 
                                {
                                            
                                        case 'W': //Write Full Message to LIN2
                                            sscanf(&mail->message[3],"%u;%u;%u;%u;%u;%u;%u;%u;%u;%u;",&temp_ID,&temp_Data[0],&temp_Data[1],&temp_Data[2],&temp_Data[3],&temp_Data[4],&temp_Data[5],&temp_Data[6],&temp_Data[7],&temp_Checksum);
                                            LINMess.IDfield = temp_ID;
                                            LINMess.Checksum = temp_Checksum;
                                            for(int k=0; k<8; k++){ LINMess.Data[k] = temp_Data[k]; }
                                            send_Full_Message(LINMess.IDfield, LINMess.Data, LINMess.Checksum, 2); // Maybe Disable interrupts here
                                            if(Wait_Echo_Response) { wait_ms(LIN_Wait_Echo); read_Full_Message(2); }
                                            ledUART2 = false;
                                            break;
                                        case 'H': //Write Remote Header to LIN2
                                            sscanf(&mail->message[3],"%u;",&temp_ID);
                                            LINMess.IDfield = temp_ID;
                                            send_Header_Message(LINMess.IDfield,2);
                                            if(Wait_Echo_Response) { wait_ms(LIN_Wait_Echo); wait_ms(LIN_Wait_Response); read_Full_Message(2); }
                                            ledUART2 = false;
                                            break;    
                                        case 'R': //Read Data from LIN2
                                            read_Full_Message(2);
                                            ledUART2 = false;
                                            break;        
                                        default:
                                            ledUART2 = false;                                     
                                            break;
                                 }
                                    break;
                                case 'F':       //Flash the Buffer of all the LINs
                                {
                                    ledUART1 = true;
                                    ledUART2 = true;
                                    Flash_Messages(1);
                                    Flash_Messages(2);                                
                                    ledUART1 = false;
                                    ledUART2 = false;
                                    LoadPCMail(50,"Flash_OK");
                                    break;
                                }
                                default:
                                break;
                            }   
                            break; 
                  }
                case 1: //Send LOG to PC
                    if(LOGPC) { snprintf(mess,MessSizePC,"LOG(%s):%s\r\n",Tstr ,mail->message); } else { mess[0]=0; }
                    break;
                case 50: //Send to PC a Message from LINs
                    snprintf(mess,MessSizePC,"LINs:%s\r\n",mail->message);
                    break;
                case 51: //Send to PC a Message from LIN1
                    snprintf(mess,MessSizePC,"LIN1:%s\r\n",mail->message);
                    break;
                case 52: //Send to PC a Message from LIN2
                    snprintf(mess,MessSizePC,"LIN2:%s\r\n",mail->message);
                    break;
                case 99: //Information from the Micro
                    snprintf(mess,MessSizePC,"MBED:%s\r\n",mail->message);
                    break;
                default:
                    break;
            }
            PC_mail.free(mail);
            PCMailNum--;
            if(PCMailNum==0){ledPC=false;} else {ledPC=true;}
            ComPC_Write(mess);
        }
    }
}

/**** End of Serial Communication PC ****/

int main() 
{
    Initialize();
    PCMailNum=0;
    
    Thread ComPC_thread (ComPC_thread_proc,NULL,osPriorityBelowNormal); // Start a ComPC Thread!
    pc.attach(&messageFromPC, MODSERIAL::RxAutoDetect);                 // Attach an Interrupt to the TX Line
    pc.autoDetectChar(ChEnd);                                           // Autodetect the End Characted
    
    LoadPCMail(99,InitialMessage);
 
    // ************ WD *************
    wd.WatchdogCausedReset();
    wd.Configure(5.0);
    // ************ WD_end *********
    
    while(true)
    {
        wd.Service();
        Thread::wait(500); // what is this doing here?
    }
}

void GetConfig(void)
{

#define CfgNumParam 9
#define CfgSizeParam 50

    pc.format(8,Serial::Even,1);    // Configuration for the Format of the data for the PC
    pc.baud(115200);                // Configuration for the Baudrate of the communication to the PC [default]
    ConfigFile cfg;                 
    LocalFileSystem local("local"); 

    int i;
    char value[CfgNumParam][CfgSizeParam];
    char CfgK[CfgNumParam][CfgSizeParam]= {"InitialMessage","BaudRate","ChEnd","LOGPC","LIN1Baud","LIN2Baud","LINWaitResp_ms","LINWaitProd_ms","Wait_Response"};
    if (!cfg.read("/local/config.cfg")) { error("\r\nFailure to read a configuration file"); }
    
    char Tstr[10];
    for (i=0; i<CfgNumParam; i++) {
        if (cfg.getValue(CfgK[i], &value[i][0], sizeof(value[i]))) { TLogSTR(Tstr); /*pc.printf("CFG_Param(%s): '%s'='%s'\r\n", Tstr,CfgK[i], value[i]);*/ } 
        else { error("Failure Reading '%s'\r\n", CfgK[i]); }
    }
    strcpy(InitialMessage,value[0]);
    PC_Baudrate=atoi(value[1]);
    ChEnd=(char)atoi(value[2]);
    LOGPC=(bool)atoi(value[3]);
    
    LIN1Baud=atoi(value[4]);
    LIN2Baud=atoi(value[5]);
    
    LIN_Wait_Echo = atoi(value[6]);
    LIN_Wait_Response = atoi(value[7]);
    
    Wait_Echo_Response = (bool)atoi(value[8]);
    
    TxBufferWait= 10000*MessSizePC/PC_Baudrate;
    while(!pc.txBufferEmpty()) { Thread::wait(100); };
}

void Initialize(void)
{
    Reboot_Pin = false;
    GetConfig();
    pc.baud(PC_Baudrate);   pc.format(8,Serial::Even,1);        // Configuration for PC
    LIN1.baud(LIN1Baud);    LIN1.format(8,Serial::None,1);      // Configuration for LIN1
    LIN2.baud(LIN2Baud);    LIN2.format(8,Serial::None,1);      // Configuration for LIN2
}

void TLogSTR(char *Tstr)    // Put to Tstr the Time information as a character
{
    ctTime = time(NULL);
    timeinfo = localtime ( &ctTime );
    timeinfo->tm_hour=(timeinfo->tm_hour+1)%24;
    strftime (Tstr,MessSizePC,"%H:%M:%S",timeinfo);
}

void LoadPCMail(char comm,  char *mess) //Working in Parallel to Load a message to the stack
{
    while(PCMailNum>=PC_MaxMailElements) { Thread::wait(PCMessWait); }  // Wait if there are many other things in Queue
    if(comm!=1 || LOGPC) {
        PC_mail_t *mail = PC_mail.alloc();
        mail->command = comm;
        snprintf(mail->message,MessSizePC,"%s",mess);
        PC_mail.put(mail);
        PCMailNum++;
    }
}

void messageFromPC(MODSERIAL_IRQ_INFO *q) //Received Message from PC and Put it in stack with a Value of 0
{
    ledPC=true;
    MODSERIAL *sys = q->serial;
    char temp[MessSizePC];

    int i=sys->move(temp,MessSizePC,ChEnd);
    if (temp[i-2]=='\r') {
        i-=2;
    } else {
        i-=1;
    }
    temp[i]=0;
    LoadPCMail(0,temp);
}

int ComPC_Write(char *mess) // Send a Message Back to the PC
{
    int i=strlen(mess);
    if(i>0) {
        while((TxBuffer-pc.txBufferGetCount())<i) {  Thread::wait(TxBufferWait);  } // Wait until the Buffer is ready
        return pc.printf(mess);
    }
    return 0;                                                   // return code if i negative
}
void Convert_Character_to_Number_to_String(char* temp_string, char Character)
{
    unsigned int Temp_Number = Character;
    sprintf (temp_string,"%u",Temp_Number);
    temp_string[3]=0;
}
void read_Full_Message(char Port_)  // Maybe Disable Interrupts Here
{
    char tmp[MessSizeLIN];
    char digit[4];
    char uniq_char;
    int index = 0;
    switch(Port_)                   // Read the Buffer from LIN Port AND Send a Message to the PC
    {
        case 1:     // LIN1
            index = 0;
            while(LIN1.readable()==1)
            {
                uniq_char = LIN1.getc();
                Convert_Character_to_Number_to_String(digit,uniq_char);
                for(int j=0; j<strlen(digit);j++) { tmp[index++] = digit[j]; }
                tmp[index++]=';';
            }
            tmp[index]=0;
            LoadPCMail(51,tmp);
            break; 
        case 2:     // LIN2
            index = 0;
            while(LIN2.readable()==1)
            {
                uniq_char = LIN2.getc();
                Convert_Character_to_Number_to_String(digit,uniq_char);
                for(int j=0; j<strlen(digit);j++) { tmp[index++] = digit[j]; }
                tmp[index++]=';';
            }
            tmp[index]=0;
            LoadPCMail(52,tmp);
            break;
        default: 
            break;
    }

}


void send_Full_Message(char ID_Field_, char Data_[8], char Checksum_, char Port_)  // Maybe Disable interrupts here
{  
    switch(Port_) 
    {
        case 1:     // LIN1
            send_Break(Port_);                              //send 15bit of Zero Break;
            LIN1.putc(0x55);                                //send 0x55 Synchronisation Character
            LIN1.putc(ID_Field_);                           //send ID field  
            for(int k=0;k<8;k++) {LIN1.putc(Data_[k]);}     //send Data
            LIN1.putc(Checksum_);                           //send Checksum
            break; 
        case 2:     // LIN2
            send_Break(Port_);                              //send 15bit of Zero Break;
            LIN2.putc(0x55);                                //send 0x55 Synchronisation Character
            LIN2.putc(ID_Field_);                           //send ID field   
            for(int k=0;k<8;k++) {LIN2.putc(Data_[k]);}     //send Data
            LIN2.putc(Checksum_);                           //send Checksum
            break;
        default: 
            break;
    }
}

void send_Header_Message(char ID_Field,int Port) // Maybe Disable interrupts here
{
    switch(Port) 
    {
        case 1:     // LIN1 
            send_Break(Port);                       //send 15bit of Zero Break;
            LIN1.putc(0x55);                        //send 0x55 Synchronisation Character
            LIN1.putc(ID_Field);                    //send ID field
            break;
        case 2:      // LIN2
            send_Break(Port);                       //send 15bit of Zero Break;
            LIN2.putc(0x55);                        //send 0x55 Synchronisation Character
            LIN2.putc(ID_Field);                    //send ID field
            break;
        default: 
            break;
     }
}

void send_Break(int Port)
{
    int time_BREAK = 0;
    switch(Port) 
    {
        case 1:     // LIN1   
            time_BREAK = 1000000/LIN1Baud;  // time in us
            LPC_UART1->LCR |= 0x40;
            wait_us(time_BREAK*15);       
            LPC_UART1->LCR &= ~(0x40);
            break;
        case 2:     // LIN2 
            time_BREAK = 1000000/LIN2Baud;  // time in us
            LPC_UART2->LCR |= 0x40;
            wait_us(time_BREAK*15);       
            LPC_UART2->LCR &= ~(0x40);
            break;
        default: 
            break;
    }
}
void Flash_Messages(int Port_) // Flashes all the Messages from the Buffer on LINs
{
    if(Port_==1)                   // Read the Buffer from LIN Port AND Send a Message to the PC
    {
        while(LIN1.readable()==1) { LIN1.getc();}
    }
    else if(Port_==2)
    {
        while(LIN2.readable()==1) { LIN2.getc();}
    }
}

void Reset_UUT(void)
{
    Reboot_Pin = true;
    wait_ms(200);
    Reboot_Pin = false;
    }