You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
7.8 KiB
295 lines
7.8 KiB
/* Ardurail 1.0 |
|
|
|
Copyright (C) 2012 Jan Weller jan.weller@gmx.de Rewritten |
|
and reorganized 2013 by Holger Wirtz <dcoredump@googlemail.com> |
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
under the terms of the GNU General Public License as published by the Free |
|
Software Foundation; either version 3 of the License, or (at your option) |
|
any later version. |
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT |
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|
more details. |
|
|
|
*/ |
|
|
|
#ifndef _ARDURAIL_H |
|
#define _ARDURAIL_H |
|
|
|
#if ARDUINO >= 100 |
|
#include "Arduino.h" |
|
#else |
|
#include "WProgram.h" |
|
#endif |
|
|
|
#if defined(__AVR_ATmega328P__) |
|
#define __UNO__ 1 |
|
#define __BOARD__ "Arduino Uno" |
|
#elif defined(__AVR_ATmega32U4__) |
|
#define __LEONARDO__ 1 |
|
#define __BOARD__ "Arduino Leonardo" |
|
#elif defined(__AVR_ATmega2560__) |
|
#define __MEGA__ 1 |
|
#define __BOARD__ "Arduino Mega 2560" |
|
#else |
|
#warning Unsupported board. |
|
//#error Unsupported board. Please adjust library. |
|
#endif |
|
|
|
#include <avr/interrupt.h> |
|
#include <avr/io.h> |
|
|
|
// |
|
// ######################### DEFAULTS ############################# |
|
// |
|
|
|
#define __LED13__ 0 // used for debugging |
|
#define USE_S88 1 // S88 enabled |
|
#define USE_SHORT_INTERRUPT 0 // pin 2 only! |
|
|
|
|
|
// Port for S88-Module |
|
#define S88_Data A0 |
|
#define S88_Clock A1 |
|
#define S88_PS A2 |
|
#define S88_Reset A3 |
|
|
|
// setup maximum values |
|
#define MAX_REFRESH 80 // 80 locomotives |
|
#define MAX_TRACK_COMMANDS 80 // 80 commands can be buffered |
|
#define MAX_S88 31 // 31 modules of 2 bytes |
|
|
|
// |
|
// DO NOT CHANGE ANYTHING BEHIND THIS LINE IF YOU DO NOT KNOW WHAT YOU ARE |
|
// DOING!!! |
|
// |
|
|
|
// |
|
// ######################### DEFINITIONS ############################# |
|
// |
|
|
|
// States in DCC-ISR |
|
#define PREAMBLE 0 |
|
#define SEPERATOR 1 |
|
#define SENDBYTE 2 |
|
#define TERMINATOR 3 |
|
#define BREAK 4 |
|
|
|
// Status for the next telegram |
|
#define MM_LOCO 0 |
|
#define MM_DEVICE 1 |
|
#define DCC 2 |
|
|
|
|
|
enum decoder_type |
|
{ |
|
DEF, |
|
M1, |
|
M2, |
|
M2_28_80A, |
|
M2_14_256A, |
|
M2_28_256A, |
|
//MFX, |
|
DCC_28, |
|
DCC_128 |
|
}; |
|
|
|
#define M3 M2_28_80A |
|
#define M4 M2_14_256A |
|
#define M5 M2_28_256A |
|
|
|
// DCC packet |
|
struct DCC_packet |
|
{ |
|
uint8_t byte1; |
|
uint8_t byte2; |
|
uint8_t byte3; |
|
uint8_t byte4; |
|
uint8_t byte5; |
|
uint8_t byte6; |
|
uint8_t used_bytes; |
|
}; |
|
|
|
// refresh packet (packets which are sent out constantly) |
|
// and all informations abaut locos |
|
struct Refresh |
|
{ |
|
uint8_t address; |
|
uint8_t type:4; |
|
uint8_t speed; |
|
uint8_t dir:1; |
|
uint8_t changedir:1; |
|
uint8_t function:1; |
|
uint8_t f1:1; |
|
uint8_t f2:1; |
|
uint8_t f3:1; |
|
uint8_t f4:1; |
|
uint8_t f5:1; |
|
uint8_t f6:1; |
|
uint8_t f7:1; |
|
uint8_t f8:1; |
|
uint8_t f9:1; |
|
uint8_t f10:1; |
|
uint8_t f11:1; |
|
uint8_t f12:1; |
|
uint8_t f13:1; |
|
uint8_t f14:1; |
|
uint8_t f15:1; |
|
uint8_t f16:1; |
|
uint8_t ready:1; |
|
}; |
|
|
|
// packet for Trackswitch |
|
struct MMTrackswitch |
|
{ |
|
uint8_t address; |
|
uint8_t subaddress:3; |
|
uint8_t state:1; |
|
uint8_t ready:1; |
|
}; |
|
|
|
|
|
// timer frequency is 16 MHz / 8 = 2 MHz |
|
#define TIMER_MM_DEVICE 233 // 13 usec for devices |
|
#define TIMER_MM_LOCO 214 // 26 usec for locomotives |
|
|
|
#define TIMER_DCC 145 // 58 usec for dcc |
|
|
|
// wait timer definitons |
|
#define TIME_T1 40 // 1248 us between data packets (inside a double packet) |
|
#define TIME_T2 162 // 4,2 ms between two double packets |
|
#define TIME_T3 235 // 235 6,0 ms after two double packets |
|
|
|
#define TIME_DCC_BREAK 160 // 5,0 ms between two dcc packets |
|
|
|
// a set contains 8 messages (8x2 double packets) |
|
#define MAXMSG 8 |
|
|
|
// |
|
// ######################### CLASS ############################# |
|
// |
|
|
|
class Ardurail |
|
{ |
|
public: |
|
Ardurail(); |
|
void init(byte pin); |
|
void init(byte pin,byte shortcut_pin,byte go_signal_pin); |
|
void S88(void); |
|
byte get_S88(byte modul, byte area); |
|
boolean get_power(void); |
|
void set_power(boolean power); |
|
boolean get_halt(void); |
|
void set_halt(void); |
|
void set_go(void); |
|
void set_stop(void); |
|
boolean get_shortcut(void); |
|
void add_loco(byte addr); |
|
void add_loco(byte addr,byte protocol); |
|
byte get_loco(byte addr); |
|
byte get_speed(byte addr); |
|
byte get_speedsteps(byte addr); |
|
void set_speed(byte addr, byte speed); |
|
boolean get_dir(byte addr); |
|
void set_dir(byte addr, boolean direction); |
|
void change_dir(byte addr); |
|
boolean get_function(byte addr, byte function_nr); |
|
void set_function(byte addr, byte function, boolean state); |
|
void emergency_stop(byte addr); |
|
void reset_locos(void); |
|
void commit(void); |
|
void commit(byte addr); |
|
void set_track(byte addr, byte sub_addr, boolean state); |
|
static inline void handle_timer2_interrupt(void); |
|
static inline void handle_short_interrupt(void); |
|
#ifdef USE_S88 |
|
byte _s88_max_s88; |
|
#endif |
|
|
|
protected: |
|
uint8_t _shortcut_signal_pin; |
|
uint8_t _go_signal_pin; |
|
boolean _power; |
|
boolean _halt; |
|
boolean _short; |
|
volatile struct Refresh _refresh[MAX_REFRESH]; // maximum of MAX_REFRESH (80) locomotives |
|
uint8_t _refresh_max; // current number of locomotives |
|
struct MMTrackswitch tswitch[MAX_TRACK_COMMANDS]; // buffer of MAX_TRACK_COMMANDS (80) for trackswitchcommands |
|
int8_t _waiting_track_commands; |
|
|
|
#ifdef USE_S88 |
|
byte _s88_data_pin; |
|
byte _s88_clock_pin; |
|
byte _s88_ps_pin; |
|
byte _s88_reset; |
|
uint8_t _s88_state[MAX_S88 * 2]; |
|
#endif |
|
|
|
// vars for TIMER2 interrupt handler |
|
volatile boolean _break_t1; // flag for break between the data packets |
|
volatile boolean _break_t2; // flag for break between double packets |
|
volatile boolean _break_t3; // flag for break after two double packets |
|
volatile byte _step; // step counter |
|
volatile byte _bit_counter; // counts bits in each double packet (9 Trits = 18 Bits) |
|
volatile byte _packet_counter; // counter for double packets (there are every time two of them (STAR WARS) |
|
volatile byte _msg_counter; // counts the messages |
|
volatile uint8_t _timer; // timer setup value |
|
volatile uint8_t _outbit:1; // bit to write out |
|
volatile uint8_t _mode:2; // 0 = MM_LOCO 1 = MM_DEVICE 2 = DCC |
|
volatile uint8_t _dcc_state; // state of DCC: PREAMBL, SEPERATOR, SENDBYTE, TERMINATOR, BREAK |
|
|
|
volatile int8_t _refresh_pointer; // the next loco |
|
volatile int8_t _updated_loco; // the loco has new information to send out first (with priority) |
|
|
|
volatile uint32_t _msg[MAXMSG]; // MM1-5 Outputregister |
|
volatile struct DCC_packet _msg_dcc[MAXMSG]; // DCC Outputregister |
|
|
|
// vars for digital signal |
|
volatile uint8_t _digital_signal; |
|
volatile uint8_t* _digital_reg; |
|
|
|
|
|
uint8_t _s88modulcycleaddr; |
|
|
|
void _generate(byte index); |
|
void _generate_m1(byte index); |
|
void _generate_m2(byte index); |
|
void _generate_m3(byte index); |
|
void _generate_m4(byte index); |
|
void _generate_m5(byte index); |
|
void _generate_dcc_28(uint8_t index); |
|
void _generate_dcc_128(uint8_t index); |
|
void _generate_trackswitch(byte address, byte subaddress, boolean on); |
|
byte _calc_function_f4(byte speed, boolean function); |
|
byte _calc_function_f3(byte speed, boolean function); |
|
byte _calc_function_f2(byte speed, boolean function); |
|
byte _calc_function_f1(byte speed, boolean function); |
|
byte _calc_speed(byte speed); |
|
byte _calc_speed_and_direction(byte speed, boolean dir); |
|
uint8_t _calc_dcc28_speed_and_direction(uint8_t speed, uint8_t dir); |
|
uint8_t _calc_dcc128_speed(uint8_t speed); |
|
uint8_t _calc_dcc128_speed_and_direction(uint8_t speed, uint8_t dir); |
|
byte _calc_trinary_address(byte address); |
|
uint8_t _calc_dcc_address(uint8_t address); |
|
uint8_t _lsb_msb_replacement(uint8_t inbyte); |
|
void _write_mm_output_register(uint8_t message, uint8_t address, uint8_t function, uint8_t data); |
|
void _commit(byte index); |
|
int8_t _create_refresh(byte address); |
|
int8_t _find_refresh(byte address); |
|
void _timersetup(void); |
|
void _do_timer2_irq_MM(void); |
|
void _do_timer2_irq_DCC(void); |
|
void _do_update(void); |
|
static Ardurail *_active_object; |
|
}; |
|
|
|
// |
|
// ######################### FUNCTIONS ############################# |
|
// |
|
|
|
#ifdef __LED13__ |
|
inline void __led13__(boolean state); |
|
#endif |
|
#endif
|
|
|