summaryrefslogtreecommitdiff
path: root/firmware/can.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/can.c')
-rw-r--r--firmware/can.c756
1 files changed, 0 insertions, 756 deletions
diff --git a/firmware/can.c b/firmware/can.c
deleted file mode 100644
index 95090bb..0000000
--- a/firmware/can.c
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (c) 2007 Marco Glietsch (http://www.mikrocontroller.net/topic/98697)
- * Original author: Marco Glietsch
- * Modified for octopus by Michael Hartmann <ich@speicherleck.de>
- * All rights reserved.
- *
- * Short descripton of file:
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of the FH Augsburg nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF USE,
- * DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifdef __AVR_AT90CAN128__
-
-#include "common.h"
-#include "protocol.h"
-#include "can.h"
-
-#include <avr/io.h>
-#include <avr/interrupt.h>
-#include <util/delay.h>
-#include <inttypes.h>
-#include <stdbool.h>
-
-struct {
- uint32_t id;
- int8_t data[8];
-} message;
-
-int8_t iemob[15] = {
- IEMOB0, IEMOB1, IEMOB2, IEMOB3, IEMOB4, IEMOB5, IEMOB6, IEMOB7,
- IEMOB8, IEMOB9, IEMOB10, IEMOB11, IEMOB12, IEMOB13, IEMOB14 };
-
-// extended id
-int8_t extended_id;
-
-void can_parser(uint8_t *buf)
-{
- switch(buf[0])
- {
- case CMD_CAN_INIT:
- can_init_usb((uint8_t)buf[2], (uint8_t)buf[3]);
- break;
- case CMD_CAN_DEINIT:
- can_deinit_usb();
- break;
- case CMD_CAN_ENABLE_MOB:
- asm("nop");
- uint32_t idm = 0;
- uint32_t id = 0;
-
- id = ((uint32_t)buf[4]) +
- ((uint32_t)buf[5] << 8) +
- ((uint32_t)buf[6] << 16) +
- ((uint32_t)buf[7] << 24);
-
- idm = ((uint32_t)buf[8]) +
- ((uint32_t)buf[9] << 8) +
- ((uint32_t)buf[10] << 16) +
- ((uint32_t)buf[11] << 24);
-
- // mob, mode, id, idm
- can_enable_mob_usb(buf[2], buf[3], id, idm);
- break;
- case CMD_CAN_DISABLE_MOB:
- can_disable_mob_usb((uint8_t)buf[2]);
- break;
- case CMD_CAN_SEND_DATA:
- can_send_data_usb(buf[2], buf[3], &buf[4]);
- break;
- case CMD_CAN_SEND_REMOTE:
- can_send_remote_usb(buf[2]);
- break;
- case CMD_CAN_RECEIVE_DATA:
- can_receive_data_usb(buf[2]);
- break;
- case CMD_CAN_SET_AUTOREPLY:
- can_set_autoreply_usb(buf[2], buf[3], &buf[4]);
- break;
- default:
- answer[0] = buf[0];
- answer[1] = RSP_UNKOWN_CMD;
- answer[2] = 0;
- CommandAnswer(3);
- }
-}
-
-void can_init_usb(uint8_t baudrate, uint8_t eid)
-{
- answer[0] = CMD_CAN_INIT;
- answer[1] = (uint8_t)can_init(baudrate, CAN_INTERRUPTS_RX, eid);
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-// Message Objects zuruecksetzen, CAN-Controller aktivieren
-// Parameter:
-// uint8_t baud: 0,1,2...5 (fuer 100, 125, 200, 250, 500, 1000)
-// uint8_t intmode: Ereignis, bei dem ein Interrupt ausgelöst werden soll
-// - NONE - Deaktiviert
-// - TX - Daten gesendet
-// - RX - Daten empfangen
-// - TXRX - Daten gesendet und/oder empfangen
-int can_init(uint8_t baudrate, uint8_t intmode, uint8_t eid)
-{
- uint8_t i;
-
- octopus.ports[17] = PIN_CAN;
- octopus.ports[18] = PIN_CAN;
-
- extended_id = eid ? 1 : 0;
-
- message.id = 0;
- for(i = 0; i < 8; i++)
- message.data[i] = 0;
-
- // Status- und Steuerregister aller Message Objects initialisieren
- for(i = 0; i < NO_MOBS; i++)
- {
- can_get_mob(i);
- CANSTMOB = 0;
- CANCDMOB = 0;
- }
-
- // set baudrate
- if(can_set_baudrate(baudrate) == 0)
- return RSP_ERROR;
-
- if(can_set_interrupt(intmode) == 0)
- return RSP_ERROR;
-
- // CAN-Controller in Enabled Mode setzen
- setbit(CANGCON, ENASTB);
-
- // Warten bis der CAN-Controller das Enabled-Bit gesetzt hat und
- // einsatzbereit ist
- while (!getbit(CANGSTA, ENFG));
-
- return RSP_OK;
-}
-
-void can_deinit_usb(void)
-{
- answer[0] = CMD_CAN_DEINIT;
- answer[1] = (int8_t)can_deinit();
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-int can_deinit(void)
-{
- uint8_t i;
-
- octopus.ports[17] = PIN_NONE;
- octopus.ports[18] = PIN_NONE;
-
- for(i = 0; i < 15; i++)
- can_disable_mob(i);
-
- // CAN-Controller ausschalten
- clearbit(CANGCON, ENASTB);
-
- // warten bis wirklich ausgechaltet
- while (getbit(CANGSTA, ENFG));
-
- return RSP_OK;
-}
-
-void can_set_autoreply(uint8_t mob, uint8_t length, uint8_t *buf)
-{
- can_get_mob(mob);
- can_set_mode(CAN_MODE_AUTO_REPLY);
- can_set_data(length, buf);
-}
-
-void can_set_autoreply_usb(uint8_t mob, uint8_t length, uint8_t *buf)
-{
- can_set_autoreply(mob, length, buf);
-
- answer[0] = CMD_CAN_SET_AUTOREPLY;
- answer[1] = RSP_OK;
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-int can_set_baudrate(uint8_t baudrate)
-{
- // @16 MHz
- switch(baudrate)
- {
- case CAN_BAUDRATE_100K:
- CANBT1 = 0x12;
- CANBT2 = 0x0c;
- CANBT3 = 0x37;
- break;
-
- case CAN_BAUDRATE_125K:
- CANBT1 = 0x0e;
- CANBT2 = 0x0c;
- CANBT3 = 0x37;
- break;
-
- case CAN_BAUDRATE_200K:
- CANBT1 = 0x08;
- CANBT2 = 0x0c;
- CANBT3 = 0x37;
- break;
-
- case CAN_BAUDRATE_250K:
- CANBT1 = 0x06;
- CANBT2 = 0x0c;
- CANBT3 = 0x37;
- break;
-
- case CAN_BAUDRATE_500K:
- CANBT1 = 0x02;
- CANBT2 = 0x0c;
- CANBT3 = 0x37;
- break;
-
- case CAN_BAUDRATE_1000K:
- CANBT1 = 0x00;
- CANBT2 = 0x0c;
- CANBT3 = 0x37;
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-void can_enable_mob_usb(uint8_t mob, uint8_t mode, uint32_t id, uint32_t idm)
-{
- answer[0] = CMD_CAN_ENABLE_MOB;
- answer[1] = (int8_t)can_enable_mob(mob, mode, id, idm);
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-
-// Parameter:
-// uint8_t mob: Nummer des zu wählenden Objekts (0-14)
-//
-// uint8_t mode
-// - Betriebsart des Message Objekts:
-// - DISABLED Deaktiviert
-// - TRANSMIT_DATA Daten senden
-// - TRANSMIT_REMOTE Anfrage senden
-// - RECEIVE_DATA Empfangsmodus
-// - AUTO_REPLY automatischer Antwortmodus
-//
-// Funktion setzt die Betriebsart des vorher gewählten Objekts
-int can_enable_mob(uint8_t mob, uint8_t mode, uint32_t id, uint32_t idm)
-{
- // Objekt wählen
- can_get_mob(mob);
-
- // Interrupt für dieses Objekt aktivieren
- can_set_mob_interrupt(mob);
-
- // ID-Maske setzen
- can_set_id_mask(idm);
-
- // ID setzen
- can_set_id(id);
-
- // Betriebsmodus setzen
- if(can_set_mode(mode) == 0)
- return RSP_ERROR;
-
- return RSP_OK;
-}
-
-
-void can_send_data_usb(uint8_t mob, uint8_t length, uint8_t *data)
-{
- answer[0] = CMD_CAN_SEND_DATA;
- answer[1] = (int8_t)can_send_data(mob, length, data);
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-int can_send_data(uint8_t mob, uint8_t length, uint8_t * data)
-{
- uint8_t mode;
-
- // Objekt wählen
- can_get_mob(mob);
-
- // Aktuelle Betriebsart sichern
- mode = can_get_mode();
-
- // Nutzdaten in Register schreiben
- can_set_data(length, data);
-
- // Datenübertragung starten
- can_set_mode(CAN_MODE_TRANSMIT_DATA);
-
- // Warten bis die Datenübertragung beendet ist (TXOK-Flag von CAN-Controller
- // gesetzt)
- while (!getbit(CANSTMOB, TXOK));
-
- // TXOK-Flag von Hand löschen
- clearbit(CANSTMOB, TXOK);
-
- // Alte Betriebsart wiederherstellen
- can_set_mode(mode);
-
- return RSP_OK;
-}
-
-
-// Parameter: uint8_t mode: Ereignis, bei dem Interrupt ausgelöst werden soll
-// - NONE - Deaktiviert
-// - TX - Daten gesendet
-// - RX - Daten empfangen
-// - TXRX - Daten gesendet und/oder empfangen
-int can_set_interrupt(uint8_t mode)
-{
- switch(mode)
- {
- case CAN_INTERRUPTS_NONE:
- clearbit(CANGIE, ENIT);
- clearbit(CANGIE, ENRX);
- clearbit(CANGIE, ENTX);
- break;
-
- case CAN_INTERRUPTS_TX:
- setbit(CANGIE, ENIT);
- clearbit(CANGIE, ENRX);
- setbit(CANGIE, ENTX);
- break;
-
- case CAN_INTERRUPTS_RX:
- setbit(CANGIE, ENIT);
- setbit(CANGIE, ENRX);
- clearbit(CANGIE, ENTX);
- break;
-
- case CAN_INTERRUPTS_TXRX:
- setbit(CANGIE, ENIT);
- setbit(CANGIE, ENRX);
- setbit(CANGIE, ENTX);
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-
-// Funktion wählt CANPAGE des betreffenden Objekts aus und stellt Zugang zu
-// Registern des Objekts her
-void can_get_mob(uint8_t mob)
-{
- CANPAGE = (mob << 4);
-}
-
-
-// Parameter: uint32_t idm: ID-Maske in Dezimalschreibweise
-// Funktion setzt ID-Maske eines Objekts auf einen neuen Wert. In CANIDM4
-// bleiben dabei die Werte der unteren 3 Bit (RTRTAG, Reserved und IDEMSK)
-// erhalten.
-void can_set_id_mask(uint32_t idm)
-{
- //Standart identifier (11 bit)
- if(!extended_id)
- {
- CANIDM2 = (uint8_t)(idm << 5);
- CANIDM1 = (uint8_t)(idm >> 3);
- }
- //extended identifier
- else
- {
- idm <<= 3;
- idm |= 7;
-
- CANIDM4 = (int8_t) (idm);
- CANIDM3 = (int8_t) (idm>>8);
- CANIDM2 = (int8_t) (idm>>16);
- CANIDM1 = (int8_t) (idm>>24);
- }
-}
-
-// Funktion holt ID der empfangenen Nachricht
-uint32_t can_get_id(void)
-{
- uint32_t id = 0;
-
- //Standart identifier (11 bit)
- if(!extended_id)
- {
- id = (uint8_t) CANIDT2 >> 5;
- id |= (uint16_t) CANIDT1 << 3;
- }
- //extended identifier
- else
- {
- id |= ((uint32_t) CANIDT1 << 24);
- id |= ((uint32_t) CANIDT2 << 16);
- id |= ((uint32_t) CANIDT3 << 8);
- id |= (CANIDT4&0xF8);
- id >>= 3;
- }
-
- return id;
-}
-
-// Funktion setzt ID eines Objekts auf einen neuen Wert. In CANIDM4 bleiben
-// dabei die Werte der unteren 3 Bit (RTRTAG, RB1TAG und RB0TAG) erhalten.
-void can_set_id(uint32_t id)
-{
- //Standart identifier (11 bit)
- if(!extended_id)
- {
- CANIDT2 = (uint8_t)(id << 5);
- CANIDT1 = (uint8_t)(id >> 3);
- }
- //extended identifier
- else
- {
- id <<= 3;
- id &= 0xfffffff8;
- id |= (CANIDT4 & 0x07);
-
- CANIDT4 = (int8_t) (id);
- CANIDT3 = (int8_t) (id>>8);
- CANIDT2 = (int8_t) (id>>16);
- CANIDT1 = (int8_t) (id>>24);
- }
-}
-
-
-// Funktion setzt die Betriebsart des vorher gewählten Objekts.
-// Parameter: uint8_t mode:
-// - Betriebsart des Message Objekts:
-// - DISABLED - Deaktiviert
-// - TRANSMIT_DATA - Daten senden
-// - TRANSMIT_REMOTE - Anfrage senden
-// - RECEIVE_DATA - Empfangsmodus
-// - AUTO_REPLY - automatischer Antwortmodus
-int can_set_mode(uint8_t mode)
-{
- if(extended_id)
- setbit(CANCDMOB, IDE);
- else
- clearbit(CANCDMOB, IDE);
-
- switch(mode)
- {
- case CAN_MODE_DISABLED:
- clearbit(CANCDMOB, CONMOB0);
- clearbit(CANCDMOB, CONMOB1);
- clearbit(CANCDMOB, RPLV);
- clearbit(CANIDT4, RTRTAG);
- clearbit(CANIDM4, RTRMSK);
- break;
-
- case CAN_MODE_TRANSMIT_DATA:
- CANCDMOB &= ~(1 << CONMOB1 || 1 << CONMOB0 || 1 << RPLV);
- CANCDMOB |= (1 << CONMOB0 || 0 << CONMOB1);
- clearbit(CANIDT4, RTRTAG);
- break;
-
- case CAN_MODE_TRANSMIT_REMOTE:
- clearbit(CANCDMOB, CONMOB1);
- setbit(CANCDMOB, CONMOB0);
- clearbit(CANCDMOB, RPLV);
- setbit(CANIDT4, RTRTAG);
- break;
-
- case CAN_MODE_RECEIVE_DATA:
- clearbit(CANCDMOB, CONMOB0);
- setbit(CANCDMOB, CONMOB1);
- clearbit(CANCDMOB, RPLV);
- clearbit(CANIDT4, RTRTAG);
- break;
-
- case CAN_MODE_AUTO_REPLY:
- clearbit(CANCDMOB, CONMOB0);
- setbit(CANCDMOB, CONMOB1);
- setbit(CANCDMOB, RPLV);
- setbit(CANIDT4, RTRTAG);
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-
-// Funktion holt die Betriebsart des vorher gewaehlten Objekts
-uint8_t can_get_mode(void)
-{
- uint8_t mode = 0;
-
- if(!getbit(CANCDMOB, CONMOB1) && !getbit(CANCDMOB, CONMOB0))
- {
- mode = CAN_MODE_DISABLED;
- }
- else if(!getbit(CANCDMOB, CONMOB1) && getbit(CANCDMOB, CONMOB0) &&
- !getbit(CANIDT4, RTRTAG))
- {
- mode = CAN_MODE_TRANSMIT_DATA;
- }
- else if(!getbit(CANCDMOB, CONMOB1) && getbit(CANCDMOB, CONMOB0) &&
- getbit(CANIDT4, RTRTAG))
- {
- mode = CAN_MODE_TRANSMIT_REMOTE;
- }
- else if(getbit(CANCDMOB, CONMOB1) && !getbit(CANCDMOB, CONMOB0) &&
- !getbit(CANIDT4, RTRTAG))
- {
- mode = CAN_MODE_RECEIVE_DATA;
- }
- else if(getbit(CANCDMOB, CONMOB1) && !getbit(CANCDMOB, CONMOB0) &&
- getbit(CANCDMOB,RPLV) && getbit(CANIDT4, RTRTAG))
- {
- mode = CAN_MODE_AUTO_REPLY;
- }
-
- return mode;
-}
-
-
-// Funktion schreibt in das Objekt die zu uebermittelnden Daten
-void can_set_data(uint8_t length, uint8_t * data)
-{
- uint8_t i;
- uint8_t cancdmob;
-
- if(length > 8)
- length = 8;
-
- // Anzahl der Datenbytes in der Nachricht
- // scheinbar darf man das CANCDMOB register nicht beliebig oft
- // schreiben/lesen, daher speichern wir den wert dazwischen, loeschen die
- // entsprechenden bits fuer die laenge und schreiben dann unsere laenge rein
- // wie dem auch sei: so funktionierts zumindest, also vorsicht beim aufraeumen ;-)
- cancdmob = CANCDMOB;
- clearbit(cancdmob, DLC0);
- clearbit(cancdmob, DLC1);
- clearbit(cancdmob, DLC2);
- clearbit(cancdmob, DLC3);
- CANCDMOB = (cancdmob | (length << DLC0));
- for(i = 0; i < length; i++)
- CANMSG = data[i];
-}
-
-void can_get_data(int8_t *msg)
-{
- uint8_t i;
-
- for(i = 0; i < 8; i++)
- msg[i] = CANMSG;
-}
-
-// Parameter: uint8_t mob: Nummer des Objekts (0-14)
-// Funktion setzt den Interrupt für das jeweilige Objekt
-void can_set_mob_interrupt(uint8_t mob)
-{
- // bugfix von C.H.
- // http://www.mikrocontroller.net/topic/98697#1232848
- if (mob < 8) { setbit(CANIE2, iemob[mob]); }
- else { setbit(CANIE1, iemob[mob]); }
-}
-
-// Parameter: uint8_t mob: Nummer des Objekts (0-14)
-// Funktion löscht den Interrupt für das jeweilige Objekt
-void can_clear_mob_interrupt(uint8_t mob)
-{
- clearbit(CANIE2, iemob[mob]);
-}
-
-// Rückgabe: uint8_t mob: Nummer des Objekts
-// Funktion ermittelt, welches Objekt Interrupt ausgeloest hat
-uint8_t can_get_mob_interrupt(void)
-{
- uint8_t mob;
- uint16_t maske;
- maske = CANSIT2 | (CANSIT1 << 8);
-
- // Wenn alle 32 Bit der Bitmaske 0 sind dann ist ein Fehler aufgetreten
- if(maske == 0)
- return NOMOB;
-
- // Die Bitmaske wird so lange nach rechts geschoben, bis Bit0 eine 1 hat.
- // Die Anzahl der Schiebeoperatoren gibt somit die Nummer des MOBs zurück
- for(mob=0; (maske & 0x01)==0; maske >>= 1, ++mob);
-
- // Kontrolle: Wenn mob größer als die Anzahl der verfügbaren
- // Message Objects ist das Ergebnis falsch
- if(mob > 14)
- return NOMOB;
-
- return mob;
-}
-
-void can_disable_mob_usb(uint8_t mob)
-{
- answer[0] = CMD_CAN_DISABLE_MOB;
- answer[1] = (int8_t)can_disable_mob(mob);
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-// Funktion deaktiviert das gewählte Objekt
-int can_disable_mob(uint8_t mob)
-{
- // Objekt wählen
- can_get_mob(mob);
-
- // Interrupt für dieses Objekt aktivieren
- can_clear_mob_interrupt(mob);
-
- // Betriebsmodus setzen
- can_set_mode(CAN_MODE_DISABLED);
-
- return RSP_OK;
-}
-
-
-void can_send_remote_usb(uint8_t mob)
-{
- answer[0] = CMD_CAN_SEND_REMOTE;
- answer[1] = (int8_t)can_send_remote(mob);
- answer[2] = 0;
-
- CommandAnswer(3);
-}
-
-// Funktion sendet eine Anfrage (Remote Frame)
-int can_send_remote(uint8_t mob)
-{
- uint8_t mode;
-
- // Objekt wählen
- can_get_mob(mob);
-
- // Aktuelle Betriebsart sichern
- mode = can_get_mode();
-
- // Datenübertragung starten
- can_set_mode(CAN_MODE_TRANSMIT_REMOTE);
-
- // Warten bis die Datenübertragung beendet ist (TXOK-Flag von CAN-Controller
- // gesetzt)
- while (!getbit(CANSTMOB, TXOK));
-
- // TXOK-Flag von Hand löschen
- clearbit(CANSTMOB, TXOK);
-
- // Alte Betriebsart wiederherstellen
- can_set_mode(mode);
-
- return RSP_OK;
-}
-
-void can_receive_data_usb(int mob)
-{
- uint8_t i;
- answer[0] = CMD_CAN_RECEIVE_DATA;
- answer[1] = RSP_OK;
-
- // id
- answer[2] = (int8_t) (message.id);
- answer[3] = (int8_t) (message.id >> 8);
- answer[4] = (int8_t) (message.id >> 16);
- answer[5] = (int8_t) (message.id >> 24);
-
- message.id = 0;
- for(i = 0; i < 8; i++)
- {
- answer[6+i] = message.data[i];
- message.data[i] = 0;
- }
- answer[14] = 0;
-
- CommandAnswer(15);
-}
-
-// Interrupt fuer Empfang einer Nachricht
-SIGNAL(SIG_CAN_INTERRUPT1)
-{
- uint8_t save_canpage;
- uint8_t mob;
-
- // Aktuelle CANPAGE sichern
- save_canpage = CANPAGE;
-
- // Index des MOB ermitteln, der den Interrupt ausgelöst hat
- mob = can_get_mob_interrupt();
-
- // Falls es kein gültiges MOB war abbrechen
- if(mob == NOMOB)
- return;
-
- // Objekt das den Interrupt ausgelöst hat holen
- can_get_mob(mob);
-
- // Id der Nachricht holen
- message.id = can_get_id();
-
- // Daten des MOBs aus CANMSG auslesen
- can_get_data(message.data);
-
- // Id der Nachricht holen
- message.id = can_get_id();
-
- // RXOK-Flag löschen
- clearbit(CANSTMOB, RXOK);
-
- // MOB auf Empfang setzen
- can_set_mode(CAN_MODE_RECEIVE_DATA);
-
- // CANPAGE wiederherstellen
- CANPAGE = save_canpage;
-}
-
-#endif