CAN-Gateway: Unterschied zwischen den Versionen

Aus LaborWiki
Wechseln zu: Navigation, Suche
Keine Bearbeitungszusammenfassung
 
(31 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
{{ProjektInfoBox
{{ProjektInfoBox
|name       = Can-Gateway
|name=Can-Gateway
|status     = stable
|status=stable
|image       = CAN-GW-Roulette.jpg
|image=CAN-GW-Roulette.jpg
|description = CAN <-> RS232 Gateway
|description=CAN <-> RS232 Gateway
|author     = [[Benutzer:Tixiv|Tixiv]]
|author=[[Benutzer:Tixiv|Tixiv]], [[Benutzer:Hansinator|Hansinator]]
|username    =
|version=1.1
|version     =
|platform=AVR (ATMega8)
|update      =  
|license=Source: GPL
|platform   = AVR (ATMega8)
|download=[https://www.das-labor.org/svn/microcontroller/src-atmel/automatization2.0/can_gw c Code], [https://www.das-labor.org/trac/browser/microcontroller/src-atmel/automatization2.0/can_gw trac]
|license     = Source: GPL
|update=
|download   = [https://www.das-labor.org/svn/microcontroller/src-atmel/automatization2.0/can_gw c Code], [https://www.das-labor.org/trac/browser/microcontroller/src-atmel/automatization2.0/can_gw trac]
|tags=Labor Automation,
}}
}}
Wir haben in ein 19' Rack Gehäuse, das mal aus dem Schrott gezogen wurde, ein CAN-RS232-Gateway eingebaut. Empfangene CAN Pakete werden dabei über RS232 getunnelt, so das eine Software auf einem Client PC diese wieder entkapseln kann. In den Gehäuse gibt es ein Netzteil für die 13V Bus Spannung (Es wurde von 24V umgebaut), und eine Menge Leuchtdioden, um diverse Betriebszustände signalisieren zu können. Außerdem ist eine Hauptplatine vorhanden, auf der ein Atmega8 werkelt. Auf dieser Platine befinden sich auch die Bausteine für den CAN Bus, und ein Max232 für die serielle Seite. Weiterhin gibt es Schieberegister und 16 Treiberstufen für die LEDs im Rest des Rack Gehäuses (Die waren schon so...).
Wir haben in ein 19' Rack Gehäuse, das mal aus dem Schrott gezogen wurde, ein CAN-RS232-Gateway eingebaut. Empfangene CAN Pakete werden dabei über RS232 getunnelt, so das eine Software auf einem Client PC diese wieder entkapseln kann. In den Gehäuse gibt es ein Netzteil für die 13V Bus Spannung (Es wurde von 24V umgebaut), und eine Menge Leuchtdioden, um diverse Betriebszustände signalisieren zu können. Außerdem ist eine Hauptplatine vorhanden, auf der ein Atmega8 werkelt. Auf dieser Platine befinden sich auch die Bausteine für den CAN Bus, und ein Max232 für die serielle Seite. Weiterhin gibt es Schieberegister und 16 Treiberstufen für die LEDs im Rest des Rack Gehäuses (Die waren schon so...).
== Aktuelle Parameter ==
* Atmega8 @ 18.432000 MHz
* MCP2515 @ 16.000000 MHz
* 230400 Baud Symbolrate auf der EIA-232 Schnittstelle (mit USB-Seriell Adapter)
* 125 kBit CAN Bus
* 13V Busspannung
* Bus U und I Messung
* /dev/cangw am Server
* Debug LEDs
* lfuse 0x1f, hfuse c1
== Netzaufbau ==
{{CANstructure}}
== UDev Rule ==
Folgende rule macht, dass das CAN-Gateway als '''/dev/cangw''' auftaucht:
$ cat /etc/udev/rules.d/99-cangateway.rules
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="2342",
  OWNER="cand", GROUP="dialout", MODE="666", SYMLINK+="cangw"


== RS232-CAN-Gateway Protokoll ==
== RS232-CAN-Gateway Protokoll ==
Zeile 44: Zeile 64:
Befinden sich Sender und Empfänger im Ausgangszustand, kann eine Paketübertragung initiiert werden in dem ein Kommandobyte mit einem Wert größer 0 übertragen wird. Die Null ist somit ein reservierter Wert und darf nicht für Kommandos verwendet werden. Das nächste Byte gibt die Länge des Payload an. Ist das Längenbyte 0, wird kein Payload übertragen. '''Jedes Paket endet mit einer 2-Byte langen CRC16-Checksumme über das gesamte Paket.'''
Befinden sich Sender und Empfänger im Ausgangszustand, kann eine Paketübertragung initiiert werden in dem ein Kommandobyte mit einem Wert größer 0 übertragen wird. Die Null ist somit ein reservierter Wert und darf nicht für Kommandos verwendet werden. Das nächste Byte gibt die Länge des Payload an. Ist das Längenbyte 0, wird kein Payload übertragen. '''Jedes Paket endet mit einer 2-Byte langen CRC16-Checksumme über das gesamte Paket.'''


Beachte, dass CAN-GW und Host gleichzeitig ein Sender und Empfänger sind.
Beachte, dass CAN-GW und Host gleichzeitig ein Sender und Empfänger sind. Es existieren also zwei unidirektionale Kommunikationskanäle, die auch unabhängig voneinander (De-)Synchronisiert sein können.
 
'''''Achtung: Aktuell wird nur in Richtung cand eine Checksumme gesendet, und die auch nur über das Payload. This is subject to change after the Labortage2k11. -- [[Benutzer:Hansinator|Hansinator]] 05:04, 19. Okt. 2011 (CEST)'''''


=== Kommandos ===
=== Kommandos ===
Das Kommando 0x11 kündigt einen CAN-Frame an.
Das Kommando 0x11 kündigt einen CAN-Frame an. Multi-Byte Werte sind Little Endian


{| {{prettytable}}
{| {{prettytable}}
Zeile 60: Zeile 78:
| packet || Raw CAN-Frame im Payload || 0x11 || beide || CAN-Frame
| packet || Raw CAN-Frame im Payload || 0x11 || beide || CAN-Frame
|-
|-
| setmode || Set CAN Bus Mode (Normal, Debug)<br/>(nicht implementiert) || 0x12 || GW || ?
| setmode || Set CAN Bus Mode (Normal, Debug)<br/>(nicht implementiert) || 0x12 || GW || enum { normal, mode_sleep, loopback, listenonly, config } can_mode_t
|-
|-
| error || CAN-GW Errormeldung || 0x13 || Host || -
| error || CAN-GW Errormeldung || 0x13 || Host || -
|-
|-
| notify reset || CAN-GW hat gestartet || 0x14 || Host || -
| notify reset || CAN-GW hat gestartet || 0x14 || Host || (uint8_t) MCUSR & 0xF (reset cause flags)
|-
|-
| ping gateway || CAN-GW Pinganforderung oder Antwort || 0x15 || GW || -
| ping gateway || CAN-GW Pinganforderung oder Antwort || 0x15 || GW || -
|-
| resync request || Synchronisationssequenz anfordern || 0x16 || beide || -
|-
| version || Firmware Version anfordern oder Antwort || 0x17 || GW || uint8_t major, uint8_t minor
|-
| id string || Firmware ID-String anfordern oder Antwort || 0x18 || GW || reply: nicht null-terminierter string
|-
| packet stats || Packet Counter anfordern oder Antwort || 0x19 || GW || reply: struct { uint32_t rx_count, tx_count, rx_size, tx_size; }
|-
| error stats || MCP2515 Error Counter anfordern oder Antwort || 0x1A || GW || reply: struct { uint8_t rx_errors, tx_errors, error_flags; }
|-
| power draw || Busenergieverbrauchsmessung anfordern oder Antwort || 0x1B || GW || reply: struct { uint16_t v, i, ref, gnd; }
|-
| read ctrl reg || Kontrollegister lesen|| 0x1C || GW || reply: uint8_t
|-
| write ctrl reg || Kontrolregister schreiben || 0x1D || GW || uint8_t value; reply: uint8_t new value
|-
| get reset cause || Resetgrund erfragen || 0x1E || GW || (uint8_t) MCUSR & 0xF (reset cause flags)
|}
|}


'''''Hinweis:''' Ein Ping darf zwar nur in Richtung Gateway gesendet werden, jedoch muss das Gateway auch mit einem Ping in Richtung Host antworten.''
'''''Hinweis:''' Ein Ping darf zwar nur in Richtung Gateway gesendet werden, jedoch muss das Gateway auch mit einem Ping in Richtung Host antworten.''
'''Achtung: Alle structs und puffer gehen mit byte 0 voran, alle Ganzzahlen sind little-endian!'''


=== CRC16-Algorithmus ===
=== CRC16-Algorithmus ===
Zeile 99: Zeile 137:




Folgender C-Code implementiert eine Reentrante Beispiel State-Machine zum Empfang von Daten für dieses Protokoll:
Folgender C-Code implementiert eine Reentrante Beispiel State-Machine zum Empfang von Paketen für dieses Protokoll:
  typedef enum {STATE_START, STATE_LEN, STATE_PAYLOAD, STATE_CRC} canu_rcvstate_t;
  typedef enum {STATE_START, STATE_LEN, STATE_PAYLOAD, STATE_CRC} canu_rcvstate_t;
   
   
Zeile 114: Zeile 152:
   
   
         //try to get the next char non-blocking from uart
         //try to get the next char non-blocking from uart
  while (uart_getc_nb(&c)) {
  while (uart_getc_nb(&c))
{
  switch (canu_rcvstate) {
  switch (canu_rcvstate)
{
  case STATE_START:
  case STATE_START:
  if (c) {
  if (c)
{
  canu_rcvstate = STATE_LEN;
  canu_rcvstate = STATE_LEN;
  canu_rcvpkt.cmd = c;
  canu_rcvpkt.cmd = c;
Zeile 129: Zeile 169:
  canu_rcvstate = STATE_START;
  canu_rcvstate = STATE_START;
  break;
  break;
}
else if(canu_rcvlen == 0)
{
canu_rcvstate = STATE_START;
canu_rcvpkt.len = 0;
return &canu_rcvpkt;
  }
  }
  canu_rcvstate    = STATE_PAYLOAD;
  canu_rcvstate    = STATE_PAYLOAD;
Zeile 141: Zeile 175:
  break;
  break;
  case STATE_PAYLOAD:
  case STATE_PAYLOAD:
  if(canu_rcvlen--){
  if(canu_rcvlen--)
  *(uartpkt_data++) = c;
  *(uartpkt_data++) = c;
  } else {
  else
{
  canu_rcvstate = STATE_CRC;
  canu_rcvstate = STATE_CRC;
  crc = c;
  crc = c;
Zeile 154: Zeile 189:
  if(crc == crc16(&canu_rcvpkt.cmd, canu_rcvpkt.len + 2))
  if(crc == crc16(&canu_rcvpkt.cmd, canu_rcvpkt.len + 2))
  return &canu_rcvpkt;
  return &canu_rcvpkt;
  break;
  break;
  }
  }
  }
  }
Zeile 163: Zeile 196:
  }
  }


== Aktuelle Parameter ==
== Energiemessung ==
* Atmega8
Auf dem CAN-Gateway befindet sich eine Schaltung um die Busspannung und den Strom zu messen. Dazu ist die Spannung über einen Spannungsteiler an einen ADC Pin des ATmega gelegt. Zur Strommessung wird der Spannungsabfall über einen High-Side 0,01 Ohm Shunt-Widerstand mit einem Operationsverstärker differentiell verstärkt und  ebenfalls an einen ADC pin des ATmega gelegt.
* 18.432000 MHz
 
* 115200 Baud Symbolrate auf der EIA-232 Schnittstelle
=== Spannungsmessung ===
* 100 kBit CAN Bus
 
* 13V Busspannung
Folgende Skizze entspricht der Spannungsmessschaltung:
* Strommessung vorhanden aber nicht implementiert
/ \ Buspower +13V (Ubus)
* /dev/ttyS0 am Server
  |
* Debug LEDs
---
| |
| | R1 = 2,7 kOhm
---
  |
  |-------------> PC5 [ADC5] +4,81V (Uadc)
  |
---
| |
| | R2 = 1 kOhm
---
  |
  |
--- GND
 
Uadc berechnet sich wie folgt:
            R2
Uadc =  --------- * Ubus
          R1 + R2
 
Umgekehrt, um von Uadc auf Ubus zu schließen, bedeutet das also:
          Uadc * (R1 + R2)
Ubus =  -----------------
                R2
 
=== Strommessung ===
Folgendes Schaltbild entspricht grob der Strommesschaltung (die Echte hat noch fancy Gleichtaktdingsungsstuff, ist aber vernachlässigbar hier):
 
/ \ Buspower-in +13V (Ubus_in)
  |
  |----------------
  |              |
---              |
| |  Rshunt    |  +      Differentialverstärker mit
| | = 0,01 Ohm  |---|\  <- 10x Verstärkung (amp = 10)
---                  | \ _____
  |                  | /      |--> PC4 [ADC4] (Uadc = Ushunt * 10)
  |-------------------|/
  |                  -
  |
  |
  --> Buspower (Ubus)
 
Daraus folgt für Uadc:
Uadc = I * Rshunt * amp
 
Nach I umgestellt:
          Uadc
I =  -------------
      amp * Rshunt
 
=== ADC ===
Der ADC des ATmega ist so langsam wie möglich eingestellt (prescaler = 128) und sampled abwechselnd ADC5 und ADC4. Die dort gemessenen Werte haben eine Auflösung von 10 Bit und orientieren sich an AVCC als Referenz. AVCC entspricht in der aktuellen Konfiguration VCC und hat somit hoffentlich meistens eine Spannung von 5V.
 
Folgende Konstanten seien gegeben:
ADC_res = 2^10    (10 Bit ADC Auflösung)
Uref    = 5V      (5V Referenz)
 
Dabei stellt der maximal darstellbare Wert die Referenzspannung dar, ein Bit entspricht also einer Spannung von:
          Uref
Ulsb = ---------
        ADC_res
 
Also ist für einen gemessenen wert ADC_value die Spannung Uadc am gewählten ADC pin:
Uadc = Ulsb * ADC_value
 
 
== Und wenn's Kapott ist? ==
'''Don't panic!''' Jetzt bitte nicht wild alle Dinge powercyclen, denn sonst wird dein Bugreport kacke..! Befolge lieber diese fünf einfachen Schritte:
* Man besorge sich eine Shell mit einem aktuellen lapcontrol binary, z.B. einer unserer Intranet-Server
* Folgenden Befehl absetzen: ''lapcontrol -s kvm gw ping''
* Uhrzeit & Datum in Erfahrung bringen, kurz nachdenken was zuletzt vor dem Crash passiert ist
* Alle Daten notieren und an [[benutzer:Hansinator|Hansinator]] senden.
''Schritt 1 & 2 sind im Zweifel optional.. '''Die Zeit ist wichtig!'''''
 
Wenn das Gateway nicht auf den Ping antwortet, dann könnte der [[Cand]] tot sein. Hier hilft ein Restart. Wenn das Gateway gesichert tot ist, sollte man es powercyclen. Kann man das Gateway gerade nicht Pingen, weil man vielleicht kein lapcontrol hat, dann gibt es eine alternative Möglichkeit: Man Beobachte die LEDs am Device, die sollten hin und wieder Flackern, z.B. wenn man Lichter schaltet oder etwas an den Laufschriftborg sendet.. oder einfach so...
 
== Impressionen ==
Hier ist ein [http://youtu.be/SFYF9skzbPk Video] von einem glücklichen CAN-Gateway bei der Arbeit!
 
[[Kategorie:Automatisierung]]
[[Kategorie:Infrastruktur]]

Aktuelle Version vom 5. November 2021, 02:27 Uhr

           
Can-Gateway

Release status: stable [box doku]

CAN-GW-Roulette.jpg
Description CAN <-> RS232 Gateway
Author(s)  Tixiv, Hansinator
Last Version  1.1 ()
Platform  AVR (ATMega8)
License  Source: GPL
Download  c Code, trac



Wir haben in ein 19' Rack Gehäuse, das mal aus dem Schrott gezogen wurde, ein CAN-RS232-Gateway eingebaut. Empfangene CAN Pakete werden dabei über RS232 getunnelt, so das eine Software auf einem Client PC diese wieder entkapseln kann. In den Gehäuse gibt es ein Netzteil für die 13V Bus Spannung (Es wurde von 24V umgebaut), und eine Menge Leuchtdioden, um diverse Betriebszustände signalisieren zu können. Außerdem ist eine Hauptplatine vorhanden, auf der ein Atmega8 werkelt. Auf dieser Platine befinden sich auch die Bausteine für den CAN Bus, und ein Max232 für die serielle Seite. Weiterhin gibt es Schieberegister und 16 Treiberstufen für die LEDs im Rest des Rack Gehäuses (Die waren schon so...).

Aktuelle Parameter[Bearbeiten | Quelltext bearbeiten]

  • Atmega8 @ 18.432000 MHz
  • MCP2515 @ 16.000000 MHz
  • 230400 Baud Symbolrate auf der EIA-232 Schnittstelle (mit USB-Seriell Adapter)
  • 125 kBit CAN Bus
  • 13V Busspannung
  • Bus U und I Messung
  • /dev/cangw am Server
  • Debug LEDs
  • lfuse 0x1f, hfuse c1

Netzaufbau[Bearbeiten | Quelltext bearbeiten]

+----------------+             +-------------------+                 +------------+              +---------------------+
|  CAN-Device  <-|-> CAN-Bus <-|->  CAN-Gateway  <-|->  EIA-232  <-|->  Cand  <-|->  tcp/ip  <-|->  lapcontrol + UI  | 
+----------------+             +-------------------+                 +------------+              +---------------------+

UDev Rule[Bearbeiten | Quelltext bearbeiten]

Folgende rule macht, dass das CAN-Gateway als /dev/cangw auftaucht:

$ cat /etc/udev/rules.d/99-cangateway.rules
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="2342",
 OWNER="cand", GROUP="dialout", MODE="666", SYMLINK+="cangw"

RS232-CAN-Gateway Protokoll[Bearbeiten | Quelltext bearbeiten]

Das CAN-Gateway verwendet ein einfaches Protokoll, welches Steuerkommandos und CAN-Frames übertragen kann.

RS232-CAN-Gateway Paket
 +-------------+-------------+-------------------+----------------+
 | uint8_t cmd | uint8_t len | uint8_t[] payload | uint16_t crc16 |
 +-------------+-------------+-------------------+----------------+
Feld Bedeutung Datentyp Länge (Bytes)
cmd Kommando unsigned byte 1
len Payload-Länge unsigned byte 1
payload Daten unsigned byte array 0-20
crc16 CRC16 Checksumme unsigned word, MSB first 2
  • Maximale Gesamtlänge: 24 Bytes
  • Minimale Gesamtlänge: 4 Bytes

Kommunikation (Ablauf)[Bearbeiten | Quelltext bearbeiten]

Zunächst muss zur korrekten Datenübertragung sichergestellt sein, dass Sender und Empfänger synchronisiert sind und sich im selben Zustand befinden. Wenn der Zustand des Empfängers unbekannt ist, muss ein Sender nach dem Einschalten eine Synchronisationssequenz senden. Diese Sequenz besteht aus einer Folge von Nullen die der maximalen Paketlänge entspricht (24 Bytes). Die State-Machine des Empfängers muss garantieren, dass eine Eingabe von 24 Nullbytes in Folge diese in ihren Ausgangszustand versetzt. Die Synchronisation kann auch durchgeführt werden, wenn der Byte-Offset von Sender und Empfänger im laufenden Betrieb nicht mehr synchron ist. Dies tritt z.B. auf, wenn Bytes auf der seriellen Leitung verloren oder Kaputt gehen. Insbesondere eine Fehlinterpretation des Längenbytes macht eine Resynchronisation nötig.

Befinden sich Sender und Empfänger im Ausgangszustand, kann eine Paketübertragung initiiert werden in dem ein Kommandobyte mit einem Wert größer 0 übertragen wird. Die Null ist somit ein reservierter Wert und darf nicht für Kommandos verwendet werden. Das nächste Byte gibt die Länge des Payload an. Ist das Längenbyte 0, wird kein Payload übertragen. Jedes Paket endet mit einer 2-Byte langen CRC16-Checksumme über das gesamte Paket.

Beachte, dass CAN-GW und Host gleichzeitig ein Sender und Empfänger sind. Es existieren also zwei unidirektionale Kommunikationskanäle, die auch unabhängig voneinander (De-)Synchronisiert sein können.

Kommandos[Bearbeiten | Quelltext bearbeiten]

Das Kommando 0x11 kündigt einen CAN-Frame an. Multi-Byte Werte sind Little Endian

Kommando Beschreibung Byte-Wert (hex) Richtung Payload
sync Synchronisationssequenz 0x00 beide -
setfilter (nicht implementiert) 0x10 GW -
packet Raw CAN-Frame im Payload 0x11 beide CAN-Frame
setmode Set CAN Bus Mode (Normal, Debug)
(nicht implementiert)
0x12 GW enum { normal, mode_sleep, loopback, listenonly, config } can_mode_t
error CAN-GW Errormeldung 0x13 Host -
notify reset CAN-GW hat gestartet 0x14 Host (uint8_t) MCUSR & 0xF (reset cause flags)
ping gateway CAN-GW Pinganforderung oder Antwort 0x15 GW -
resync request Synchronisationssequenz anfordern 0x16 beide -
version Firmware Version anfordern oder Antwort 0x17 GW uint8_t major, uint8_t minor
id string Firmware ID-String anfordern oder Antwort 0x18 GW reply: nicht null-terminierter string
packet stats Packet Counter anfordern oder Antwort 0x19 GW reply: struct { uint32_t rx_count, tx_count, rx_size, tx_size; }
error stats MCP2515 Error Counter anfordern oder Antwort 0x1A GW reply: struct { uint8_t rx_errors, tx_errors, error_flags; }
power draw Busenergieverbrauchsmessung anfordern oder Antwort 0x1B GW reply: struct { uint16_t v, i, ref, gnd; }
read ctrl reg Kontrollegister lesen 0x1C GW reply: uint8_t
write ctrl reg Kontrolregister schreiben 0x1D GW uint8_t value; reply: uint8_t new value
get reset cause Resetgrund erfragen 0x1E GW (uint8_t) MCUSR & 0xF (reset cause flags)

Hinweis: Ein Ping darf zwar nur in Richtung Gateway gesendet werden, jedoch muss das Gateway auch mit einem Ping in Richtung Host antworten.

Achtung: Alle structs und puffer gehen mit byte 0 voran, alle Ganzzahlen sind little-endian!

CRC16-Algorithmus[Bearbeiten | Quelltext bearbeiten]

Zur Berechnung der Checksumme wird die CRC16 Routine der AVR-Libc verwendet. Das C-Äquivalent dieser Funktion ist wie folgt:

uint16_t crc16_update(uint16_t crc, uint8_t a)
{
    int i;

    crc ^= a;
    for (i = 0; i < 8; ++i)
    {
        if (crc & 1)
            crc = (crc >> 1) ^ 0xA001;
        else
            crc = (crc >> 1);
    }

    return crc;
}

Beispielcode[Bearbeiten | Quelltext bearbeiten]

Folgende C-Struktur beschreibt ein RS232-CAN-Gateway Paket ohne Checksumme.

#define RS232CAN_MAXLENGTH 20
typedef struct {
	unsigned char cmd;
	unsigned char len;
	char data[RS232CAN_MAXLENGTH];
} rs232can_msg;


Folgender C-Code implementiert eine Reentrante Beispiel State-Machine zum Empfang von Paketen für dieses Protokoll:

typedef enum {STATE_START, STATE_LEN, STATE_PAYLOAD, STATE_CRC} canu_rcvstate_t;

rs232can_msg	 canu_rcvpkt;
canu_rcvstate_t  canu_rcvstate = STATE_START;
unsigned char 	 canu_rcvlen   = 0;
unsigned int	 crc;

//returns Message or 0 if there is no complete message.
rs232can_msg * canu_get_nb()
{
	static char *uartpkt_data;
	unsigned char c;

        //try to get the next char non-blocking from uart
	while (uart_getc_nb(&c))
	{
		switch (canu_rcvstate)
		{
		case STATE_START:
			if (c)
			{
				canu_rcvstate = STATE_LEN;
				canu_rcvpkt.cmd = c;
			}
			break;
		case STATE_LEN:
			canu_rcvlen       = (unsigned char)c;
			if(canu_rcvlen > RS232CAN_MAXLENGTH)
			{
				canu_rcvstate = STATE_START;
				break;
			}
			canu_rcvstate     = STATE_PAYLOAD;
			canu_rcvpkt.len   = (unsigned char)c;
			uartpkt_data      = &canu_rcvpkt.data[0];
			break;
		case STATE_PAYLOAD:
			if(canu_rcvlen--)
				*(uartpkt_data++) = c;
			else
			{
				canu_rcvstate = STATE_CRC;
				crc = c;
			}
			break;
		case STATE_CRC:
			canu_rcvstate = STATE_START;
			crc <<= 8;
			crc |= c;
			if(crc == crc16(&canu_rcvpkt.cmd, canu_rcvpkt.len + 2))
				return &canu_rcvpkt;
			break;
		}
	}

	return NULL;
}

Energiemessung[Bearbeiten | Quelltext bearbeiten]

Auf dem CAN-Gateway befindet sich eine Schaltung um die Busspannung und den Strom zu messen. Dazu ist die Spannung über einen Spannungsteiler an einen ADC Pin des ATmega gelegt. Zur Strommessung wird der Spannungsabfall über einen High-Side 0,01 Ohm Shunt-Widerstand mit einem Operationsverstärker differentiell verstärkt und ebenfalls an einen ADC pin des ATmega gelegt.

Spannungsmessung[Bearbeiten | Quelltext bearbeiten]

Folgende Skizze entspricht der Spannungsmessschaltung:

/ \ Buspower +13V (Ubus)
 |
---
| |
| | R1 = 2,7 kOhm
---
 |
 |-------------> PC5 [ADC5] +4,81V (Uadc)
 |
---
| |
| | R2 = 1 kOhm
---
 |
 |
--- GND

Uadc berechnet sich wie folgt:

           R2
Uadc =  --------- * Ubus
         R1 + R2

Umgekehrt, um von Uadc auf Ubus zu schließen, bedeutet das also:

         Uadc * (R1 + R2)
Ubus =  -----------------
               R2

Strommessung[Bearbeiten | Quelltext bearbeiten]

Folgendes Schaltbild entspricht grob der Strommesschaltung (die Echte hat noch fancy Gleichtaktdingsungsstuff, ist aber vernachlässigbar hier):

/ \ Buspower-in +13V (Ubus_in)
 |
 |----------------
 |               |
---              |
| |   Rshunt     |  +       Differentialverstärker mit
| | = 0,01 Ohm   |---|\  <- 10x Verstärkung (amp = 10)
---                  | \ _____
 |                   | /      |--> PC4 [ADC4] (Uadc = Ushunt * 10)
 |-------------------|/
 |                  -
 |
 |
 --> Buspower (Ubus)

Daraus folgt für Uadc:

Uadc = I * Rshunt * amp

Nach I umgestellt:

         Uadc
I =  -------------
      amp * Rshunt

ADC[Bearbeiten | Quelltext bearbeiten]

Der ADC des ATmega ist so langsam wie möglich eingestellt (prescaler = 128) und sampled abwechselnd ADC5 und ADC4. Die dort gemessenen Werte haben eine Auflösung von 10 Bit und orientieren sich an AVCC als Referenz. AVCC entspricht in der aktuellen Konfiguration VCC und hat somit hoffentlich meistens eine Spannung von 5V.

Folgende Konstanten seien gegeben:

ADC_res = 2^10    (10 Bit ADC Auflösung)
Uref    = 5V      (5V Referenz)

Dabei stellt der maximal darstellbare Wert die Referenzspannung dar, ein Bit entspricht also einer Spannung von:

         Uref
Ulsb = ---------
        ADC_res

Also ist für einen gemessenen wert ADC_value die Spannung Uadc am gewählten ADC pin:

Uadc = Ulsb * ADC_value


Und wenn's Kapott ist?[Bearbeiten | Quelltext bearbeiten]

Don't panic! Jetzt bitte nicht wild alle Dinge powercyclen, denn sonst wird dein Bugreport kacke..! Befolge lieber diese fünf einfachen Schritte:

  • Man besorge sich eine Shell mit einem aktuellen lapcontrol binary, z.B. einer unserer Intranet-Server
  • Folgenden Befehl absetzen: lapcontrol -s kvm gw ping
  • Uhrzeit & Datum in Erfahrung bringen, kurz nachdenken was zuletzt vor dem Crash passiert ist
  • Alle Daten notieren und an Hansinator senden.

Schritt 1 & 2 sind im Zweifel optional.. Die Zeit ist wichtig!

Wenn das Gateway nicht auf den Ping antwortet, dann könnte der Cand tot sein. Hier hilft ein Restart. Wenn das Gateway gesichert tot ist, sollte man es powercyclen. Kann man das Gateway gerade nicht Pingen, weil man vielleicht kein lapcontrol hat, dann gibt es eine alternative Möglichkeit: Man Beobachte die LEDs am Device, die sollten hin und wieder Flackern, z.B. wenn man Lichter schaltet oder etwas an den Laufschriftborg sendet.. oder einfach so...

Impressionen[Bearbeiten | Quelltext bearbeiten]

Hier ist ein Video von einem glücklichen CAN-Gateway bei der Arbeit!