Zeitsteuerung

Fork of timer0 by V09

rs_485.cpp

Committer:
rs27
Date:
2016-02-05
Revision:
1:8779e76fd4ea

File content as of revision 1:8779e76fd4ea:

//---------------------------------------------------------------------------
// Modul...: RS_485.CPP    
// Chip....: iox.mini
// 
//---------------------------------------------------------------------------
// Author..: Reinhold Schäfer
// Date....: 2016.01.23
// http....: //www.microsps.net
//---------------------------------------------------------------------------
#include "mbed.h"
#include "rs_485.h"
#include "timer0.h"

MODSERIAL RS485(RS485_TX2, RS485_RX2);  // tx, rx
DigitalOut RS485_DIR(RS485_DIR2,0);     // RS485 Direction 

extern MODSERIAL pc;
extern timer0 down_timer;               // definiert in main

//--------------------------------------------------------
// Interruptroutine wird nach 300µs aufgerufen, da das Senden von
// einem Zeichen ca. 100µs Zeit beansprucht, kann die Umschaltung
// auf Empfang erst verzögert erfolgen.

void rs_485::isr_timeout(void)
{
  RS485_DIR = 0; // auf Empfang umschalten
  send_end_flag = true;  
}

/*
// -----------------------------------------------------------------------
// This function is called when TX buffer goes empty
//
void rs_485::txEmpty(MODSERIAL_IRQ_INFO *q) 
{
    timeout.attach_us(this, &rs_485::isr_timeout, 300);    // Zeit für das Umschalten
}
*/
//--------------------------------------------------------
// Construktor initialisiert den Timer
rs_485::rs_485()
{
    RS485.baud(115200);
    //RS485.attach(this, &rs_485::txEmpty);
    timeout.stop();
    timeout.reset();
    msg_in.sm = 0;
    msg_out.sm = 0;
    rs_aktiv = 0;
    rs_aktiv_old = 0;    
}
//-------------------------------------------------------------
// Checksum ermitteln

uint8_t rs_485::get_crc(uint8_t *pbuffer, uint8_t count)
{
    uint8_t crc_value = 0;
    uint8_t temp;
    
    // CheckSum calculation
    for(int i=0; i <= count; i++)
    {
       temp = *pbuffer;
       // pc.printf("\n CRC #%02d  %02x ^ %02x = ",i,crc_value,temp);
       crc_value ^= temp;    // XOR from ID to Data
       pbuffer++;
       // pc.printf("%02x",crc_value);
    }
    return crc_value;
} 

//-------------------------------------------------------------
// zum Testen das Telegramm ausgeben
//
void rs_485::msg_print(Message msg) 
{
    uint8_t len;
    
    pc.printf(" %02d:%02d:%02d.%03d",msg.h,msg.m,msg.s,msg.ms);
 
    pc.printf(" %02x",msg.STX);
    pc.printf(" %02x",msg.source);
    pc.printf(" %02x",msg.dest);
    pc.printf(" %02x [",msg.len);
    
    len = msg.len;
    for (int i = 0; i < len; i++)
    {
      pc.printf(" %02x",msg.data[i]);   
    }
    pc.printf(" ] %02x",msg.CRC);
    pc.printf(" %02x",msg.ETX);
       
}

// -----------------------------------------------------------------------
// eine Telegramm erzeugen
//
// die Zeichen STX, CRC und ETX werden automatisch erzeugt
// das Telegramm hat folgenden Aufbau
// STX ADR ZIEL Länge [daten] CRC ETX
//   Länge ist Anzahl der Zeichen im Datenfeld
//
void rs_485::write(uint8_t *data)
{  
   uint16_t millis;
   uint8_t len;
   
   msg_out.STX  = 0x02;      // STX
 
   msg_out.source = *data;   // Start Adresse
   data++; 
      
   msg_out.dest = *data;     // Ziel Adresse
   data++;
  
   msg_out.len = *data;      // Länge
   len = *data;
   data++;
           
   for (int i = 0; i < len; i++)
   {
        msg_out.data[i]  = *data; // Datenbyte
        data++;
   }

   // pc.printf("\n write crc berechnen \n");
   msg_out.CRC = get_crc(&msg_out.source,msg_out.len+3); // CRC Summe ermitteln
      
   msg_out.ETX      = 0x03;    // Telegramm Abschluss
   
   // Zeitstempel schreiben
   down_timer.get_time_stamp(t_array,&millis);
   msg_out.h = t_array[0];
   msg_out.m = t_array[1];
   msg_out.s = t_array[2];
   msg_out.ms = millis;
   
   // Datenausgabe wird aktiviert, prüfen ob harte Umschaltung hier sinnvoll 
   msg_out.sm = 0;
   rs_aktiv = 2; 
}
    
//-------------------------------------------------------------
// Die Telegramme steuern und überwachen
//
void rs_485::execute(void)
{
    // auf timeout testen, falls ein fehler auftritt
    // wird das Telegramm über diese Stelle abgebrochen
    // 
    
    int temp;
    
    temp = timeout.read_ms();
    if (temp >= 10)
    {
        timeout.stop();
        timeout.reset();
        msg_in.sm = 0;
        msg_out.sm = 0;

      
        if (rs_aktiv == 1) 
        {
            pc.printf("\nreceive timeout %02d ms",temp);
            pc.printf("\n sm: %02x",msg_in.sm);
            pc.printf("\n tel:");
            msg_print(msg_out);
        }
      
        if (rs_aktiv == 2) 
        {
            pc.printf("\nsende timeout %02d ms",temp);
            pc.printf("\n sm: %02x",msg_out.sm);
            pc.printf("\n tel:");
            msg_print(msg_out); 
        }
      
        rs_aktiv = 0; 
    }  
 
    // an dieser Stelle wird der Programmablauf gesteuert
    // 0 Bus inaktiv auf Empfang
    // 1 BUS aktiv auf Empfangsmode
    // 2 BUS aktiv im Sendemode 
    
    switch (rs_aktiv)
    {
      case 0:
      
        if (rs_aktiv != rs_aktiv_old)
        {
            pc.printf("\n\nreceive");  
            timeout.stop(); // timer starten
            timeout.reset(); // timer auf 0 setzen
            rs_aktiv_old = rs_aktiv;
        }
        receive();
        break;

      case 1:
        
        if (rs_aktiv != rs_aktiv_old)
        { 
            pc.printf("\n\nreceive aktiv");
            timeout.reset(); // timer auf 0 setzen
            timeout.start();
            rs_aktiv_old = rs_aktiv; 
        }    
        receive();
        break;
                
      case 2:
      
        if (rs_aktiv != rs_aktiv_old)
        {
            pc.printf("\n\nsende aktiv");
            timeout.reset(); // timer auf 0 setzen
            timeout.start();
            rs_aktiv_old = rs_aktiv; 
        }
        send();
        break;      
    }  // end switch
        
}

// -----------------------------------------------------------------------
// das Telegramm ausgeben
//
void rs_485::send(void)
{
   
   switch(msg_out.sm)
   {
      case 0: 
        // das Senden beginnt erst, wenn das eingehende Telegramm abgeschlossen ist

        msg_print(msg_out);
        pc.printf(" \n");
        
        RS485_DIR = 1;              // Bus belegen   
        msg_out.sm = 1;

        break;
        
      case 1:                       // Startzeichen senden 
        RS485.putc(msg_out.STX);
        msg_out.sm++;
        break;
      
      case 2: 
        RS485.putc(msg_out.source);
        msg_out.sm++;
        break;

      case 3: 
        RS485.putc(msg_out.dest);
        msg_out.sm++;
        break;
        
      case 4: 
        RS485.putc(msg_out.len); 
        msg_out.sm++;
        break;
        
      case 5: 
        for(int i=0; i < msg_out.len; i++)
        {
            RS485.putc(msg_out.data[i]);          
        }
        msg_out.sm++;
        break;
        
      case 6: 
        RS485.putc(msg_out.CRC);
        msg_out.sm++;
        break;
         
      case 7: 
        RS485.putc(msg_out.ETX);
        msg_out.sm++;
        break;
        
      case 8: 
        // hier warten bis alle Zeichen ausgegeben
        int n = RS485.txBufferGetCount();
        if (n == 0) msg_out.sm = 0;
        //tx_timeout1 = timeout.read_us();
        break; 

      case 9: 
        // hier warten bis alle Zeichen ausgegeben

        //tx_timeout2 = timeout.read_us();
        //if ((tx_timeout2 - tx_timeout1) >= 100) 
        //{
            msg_out.sm = 0;
            RS485_DIR = 0;      // Bus frei geben
            rs_aktiv = 0;       // Bus wieder auf Empfang
        //} 
        break;
       
      default:  // wird nie erreicht
        pc.printf(" error in sm send %d",msg_out.sm);
        break;                                                             // 
    } // end switch                                
}

// -----------------------------------------------------------------------
// ein Telegramm lesen
//
void rs_485::receive(void)
{
    uint8_t ch, pos;
 
    if (RS485.readable())  // prüfen ob Zeichen im buffer vorhanden
    {
    ch = RS485.getc();
    pc.printf(" %02x",ch);
    if ((ch == 0x02) && (msg_in.sm == 0))
    { 
        // ein neues Telegramm startet
        // ? ein timemout einbauen
        msg_in.STX = ch;
        msg_in.sm = 1;
    }
    else
    {
       switch(msg_in.sm)
       {
          case 1:
            msg_in.source = ch;
            msg_in.sm++;
            break;
            
          case 2:
            msg_in.dest = ch;
            msg_in.sm++;
            break;
            
          case 3:
            msg_in.count = ch;
            msg_in.sm++;
            pos = 0;
            break;
            
          case 4:
            msg_in.data[pos] = ch;
            pos++;
            msg_in.count--;
            if (msg_in.count == 0)
            {
              msg_in.sm++;   
            }
            break;
             
           case 5:
            msg_in.CRC = ch;
            msg_in.sm++;
            break;
            
           case 6:
            msg_in.ETX = ch;
            msg_in.sm = 0;  // auf ein neues Telegramm warten 
            rs_aktiv = 0;
              
            // CRC prüfen
            uint8_t crc = get_crc(&msg_in.source,msg_in.len+3); // CRC Summe ermitteln
            if (crc == msg_in.CRC)
            {
                msg_in.error = 0xFF; // Telegramm korrekt empfangen
            }
            else
            {
                msg_in.error |= 0x80; // CRC Fehler
            }
            
            // Telegramm ausgeben
            pc.printf("\n receive");
            msg_print(msg_in);
            pc.printf(" stauts: %02x\n",msg_in.error);
            
            break;   
       }
       }
    }
}