/* 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 2 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. NMRA ACCESSORY DCC Decoder for ATMEL AtTiny45. (C) 2007, Heiko Schroeter Samples are taken every 21us interupt driven by timer0. Achtung: Auch in Makefile anpassen ! */ #define ATTiny45 /* F_CPU declared here because it is needed for delay.h */ #define F_CPU 8000000 #include #include #include #include #include #include #include #include "attiny45_accessory_014.h" /****************** INTERRUPT CAPSULATION *************************************/ void prmbl () { if(samples >= 0) { numbits = 0; // No Zero allowed in PREAMBLE } else { if(numbits >= NumPrmbl) { state++; // Advance if we have enough 'ones' } numbits++; } } void wtlo () { if(samples >= 0) // Advance if ZERO received state++; } void tstlo () { if(samples < 0) // A ONE signals end of DCC command { if(config & (1<= 0) // check if second half = first half, otherwise error { if(bitrec & (1<<0)) state=0xFF; // Reset state=0 if not equal } else { if(!(bitrec & (1<<0))) state=0xFF; // Reset state=0 if not equal } state++; } void bit12 () { if(samples >= 0) { CLC(); // Clear Carry -> ZERO received } else { SEC(); // Set Carry -> ONE received } ROL(bitrec); // Move received BIT into data container state++; // Advance state } void wtxlo () { // We have to semaphore end of DCC Command, because of Interrupt driven reception. // Jump to decode has to happen in main loop. if(numbytes > MaxNumBytes - 1) { numbytes = MaxNumBytes - 1; } dcc_data[numbytes] = bitrec; // Save the received byte numbytes++; // Count the bytes received state++; // Advance state if(samples < 0) // If a DCC One here, than End of DCC packet { config |= (1< analyze DCC stream, else keep on sampling. if((SREG & _BV(SREG_T) && (!(config & (1< 285 times // 30ms -> 857 times // Save Level for next round. Don't change ! asm volatile ("bld %0,%1" :: "r" (config), "i" (LastLevel)); // Increment the DCC stream samples samples++; } } /****************** END INTERRUPT CAPSULATION *********************************/ /****************** NO INT HERE ***********************************************/ void acknowledge(void) { unsigned char temp = PORTB; // Acknowledge // SET_ACKMASK; PORTB = 0xFF; _delay_ms(50); _delay_ms(50); _delay_ms(50); // CLR_ACKMASK; PORTB = temp; } /* RP 9.21 Extended Accessory Decoder Control Packet Format The Extended Accessory Decoder Control Packet is included for the purpose of transmitting aspect control to signal decoders or data bytes to more complex accessory decoders. Each signal head can display one aspect at a time. {preamble} 0 10AAAAAA 0 0AAA0AA1 0 000XXXXX 0 EEEEEEEE 1 XXXXX is for a single head. A value of 00000 for XXXXX indicates the absolute stop aspect. All other aspects represented by the values for XXXXX are determined by the signaling system used and the prototype being modeled. {preamble} 0 10AAAAAA 0 0AAA0AA1 0 000XXXXX 0 EEEEEEEE 1 43210 Bit4: On(1)/Off(0) Bit3-0: Number of Function */ /* Extended Decoder Control Packet address for operations mode programming 10AAAAAA 0 0AAA0AA1 Please note that the use of 0 in bit 3 of byte 2 is to ensure that this packet cannot be confused with the legacy accessory-programming packets. The resulting packet would be: {preamble} 10AAAAAA 0 0AAA0AA1 0 (1110CCVV 0 VVVVVVVV 0 DDDDDDDD) 0 EEEEEEEE 1 Signal Decoder Address (Configuration Variable Access Instruction) Error Byte 11Bit-Address as following AAA AAAAAA AA ||| Bit0-5 in Byte1 Bit1&2 in Byte2 ||| ||| |||_ ||__\ Complement and store in Byte2 Bit4-6 |___/ Complementing and Bit fiddling is done in Service Mode. Therefore we can check Byte1 and Byte2 directly during transmission. */ void decode_packet_acc() { // 11Bit extended Accessory Decoder unsigned char temp; unsigned char temp1; switch(dcc_data[2] & 0xE0) { case 0: temp = dcc_data[2]; if(((temp & 0xF) <= NumIoPins) && (temp & (1<<4))) // {preamble} 0 10AAAAAA 0 0AAA0AA1 0 000XXXXX 0 EEEEEEEE 1 CVs_ram[(temp & 0xF) + PioConfig] |= (1 << PORTSTATUS); // Semaphore On else CVs_ram[(temp & 0xF)] &= ~(1 << PORTSTATUS); // Semaphore Off config &= ~((1<> 2) { /* The defined values for Instruction type (CC) are: CC=00 Reserved for future use CC=01 Verify byte CC=11 Write byte CC=10 Bit manipulation */ case 0: break; case 1: // Verify temp = cv2sram_offset(dcc_data[3] + 1); //??????????????????? if(!(dcc_data[4] = eeprom_read_byte(&temp))) acknowledge(); break; case 2: break; case 3: // Write temp = cv2sram_offset(dcc_data[3] + 1); if(temp == 1) // CV1 --> Bits 2-7 as 0-5 in CV1, Bits0&1 as 1&2 in CV9 { temp = (dcc_data[4]>>2) & (1<<7) & ~(1<<6); temp1 = ((((dcc_data[4] & 0x3) << 1) & ~(1<<3)) | (1<<0)); eeprom_write_byte(&temp,1); eeprom_write_byte(&temp1,9); } else if(temp == 9) // CV9 --> 3MSB complemented in Bits 4-6 { temp = cv2sram(9); temp = eeprom_read_byte(&temp) & 0xF0; temp1 = (~(dcc_data[4] >> 4)) & 0xF0; temp = temp | temp1; eeprom_write_byte(&temp,9); } else { eeprom_write_byte(&dcc_data[4],temp); } acknowledge(); break; default: break; } break; default: break; } } void decode_packet_multi() { unsigned char temp1; unsigned char temp = (dcc_data[1] & 0xE0); // Isolate DCC command // Jump now DCC command routine switch(temp) { case DecodeAndConsist: /* if(dcc_data[1] == 0) { if(!(config & (1< CVs_ram[0] 00010 --> CVs_ram[1] 00100 --> CVs_ram[2] 01000 --> CVs_ram[3] 10000 --> CVs_ram[4] */ temp1 = dcc_data[1]; for(temp = num_base_cvs; temp <= num_cvs; temp += num_block_cvs) { if(temp1 & (1<<0)) { (CVs_ram[temp + PioConfig]) |= (1<>= 1; // Rotate the data byte } break; case Funktion2: /* This instruction has the format 101SDDDD S=0 -> F5-F8 S=1 -> F9-F12 */ temp1 = NumOfFields; if(dcc_data[1] & (1<<5)) // F5-F8 temp1 = 9; for(temp = num_base_cvs;temp < num_base_cvs + 4; temp++) { if((dcc_data[1] & (1<<0)) && (temp1 + temp < NumIoPins)) { (CVs_ram[temp + temp1 + PioConfig]) |= (1<>= 1; // Rotate the data byte } break; case CVAccessFunc: /* {preamble} 0 [ AAAAAAAA ] 0 {instruction-bytes} 0 EEEEEEEE 1 instruction bytes: Byte 1 Byte 2 Byte 3 1110CCAA 0 AAAAAAAA 0 DDDDDDDD The defined values for Instruction type (CC) are: CC=00 Reserved for future use CC=01 Verify byte CC=11 Write byte CC=10 Bit manipulation */ if((dcc_data[1] & 0x0C) == 4) // Verify { if(dcc_data[3] == CVs_ram[cv2sram_offset(dcc_data[2] + 1)]) { acknowledge(); } } if(config & (1<> 4) & 0xF; unsigned char temp1 = CVs_ram[step_io + PioPinnum]; // Bitmaske der PortPin Nummer // Configuration of IO Pin, Dimming, Neon, On/off etc. in low nibble // 0 -> Simple On/Off // 1 -> On/Off according to DIR // 2 -> Dimming // 3 -> Neon // 4 -> Blink switch(CVs_ram[step_io + PioConfig] & 0xF) { case 0: // Simple On/Off wird in DECODE gesetzt if(temp & (1<= DIM_ON_TIME) { DIM_DT_COUNTER = 0; TURNOFF; } } else { if(DIM_DT_COUNTER >= DIM_OFF_TIME) { DIM_DT_COUNTER = 0; TURNON; } } break; case 3: // Neon Count von 1 ist ca. 15,6 ms if(!(temp & (1<= cv2sram(NEON_ON_CV)) { NEON_COUNT = 0; NEON_STATE++; // next state 2 or 4 TURNOFF; } NEON_COUNT++; } NEON_DELAY++; break; case 2: case 4: case 6: if(NEON_DELAY == 0) { if(NEON_COUNT >= cv2sram(NEON_OFF_CV)) { NEON_COUNT = 0; NEON_STATE++; // next state 3 TURNON; } NEON_COUNT++; } NEON_DELAY++; break; default: TURNON; break; } break; case 4: // Blink. Count von 64 ist ca. 1Sek on, 1Sek off. also 2Sek tutto. if(!(temp & (1< GoDecode) is raised when a complete DCC packet is received. The Program jumps to the decoding routines. */ int main (void) { unsigned char temp; eeprom_read_block(&CVs_ram, &CVs_defaults, num_cvs); // Copy our setting to SRAM #ifdef ATTiny45 DDRB = IO_DIR_Mask_PORTB; // Set Directions on Port B #endif #ifdef ATTiny44 DDRB = IO_DIR_Mask_PORTB; // Set Directions on Port B DDRA = IO_DIR_Mask_PORTA; // Set Directions on Port A #endif // Set TIMER0 for 21us sampling TCCR0A = (1<= num_cvs) step_io = num_base_cvs; if(config & (1<