From a0b390886f158b68431162fca1e66378c9ee8a18 Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Sun, 17 Oct 2021 18:26:21 +0200 Subject: [PATCH] z21emu - and atmega sources --- .gitignore | 10 + z21emu/INSTALL | 0 z21emu/Makefile | 123 +++++++++ z21emu/atmega16_detect/Makefile | 41 +++ z21emu/atmega16_detect/eprom.c | 26 ++ z21emu/atmega16_detect/eprom.h | 18 ++ z21emu/atmega16_detect/gleiserkennung-v3.c | 284 ++++++++++++++++++++ z21emu/atmega8_detect/Makefile | 47 ++++ z21emu/atmega8_detect/eprom.c | 26 ++ z21emu/atmega8_detect/eprom.h | 18 ++ z21emu/atmega8_detect/gleiserkennung-v1.c | 247 ++++++++++++++++++ z21emu/atmega8_detect/gleiserkennung-v2.c | 250 ++++++++++++++++++ z21emu/atmega8_detect/gleiserkennung.c | 153 +++++++++++ z21emu/config.h | 14 + z21emu/debug.cc | 45 ++++ z21emu/debug.h | 16 ++ z21emu/i2csensor.cc | 105 ++++++++ z21emu/i2csensor.h | 31 +++ z21emu/udp.cc | 183 +++++++++++++ z21emu/udp.h | 55 ++++ z21emu/z21emu.cc | 286 +++++++++++++++++++++ z21emu/z21emu.conf.sample | 22 ++ z21emu/z21emu.h | 52 ++++ z21emu/z21emu.sh | 36 +++ z21emu/z21prot.cc | 268 +++++++++++++++++++ z21emu/z21prot.h | 58 +++++ 26 files changed, 2414 insertions(+) create mode 100644 .gitignore create mode 100644 z21emu/INSTALL create mode 100644 z21emu/Makefile create mode 100644 z21emu/atmega16_detect/Makefile create mode 100644 z21emu/atmega16_detect/eprom.c create mode 100644 z21emu/atmega16_detect/eprom.h create mode 100644 z21emu/atmega16_detect/gleiserkennung-v3.c create mode 100644 z21emu/atmega8_detect/Makefile create mode 100644 z21emu/atmega8_detect/eprom.c create mode 100644 z21emu/atmega8_detect/eprom.h create mode 100644 z21emu/atmega8_detect/gleiserkennung-v1.c create mode 100644 z21emu/atmega8_detect/gleiserkennung-v2.c create mode 100644 z21emu/atmega8_detect/gleiserkennung.c create mode 100644 z21emu/config.h create mode 100644 z21emu/debug.cc create mode 100644 z21emu/debug.h create mode 100644 z21emu/i2csensor.cc create mode 100644 z21emu/i2csensor.h create mode 100644 z21emu/udp.cc create mode 100644 z21emu/udp.h create mode 100644 z21emu/z21emu.cc create mode 100644 z21emu/z21emu.conf.sample create mode 100644 z21emu/z21emu.h create mode 100644 z21emu/z21emu.sh create mode 100644 z21emu/z21prot.cc create mode 100644 z21emu/z21prot.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbb6bcb --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +server/.depend +server/modelbahn-cgi +server/modelbahn-server +server/test-json +*~ +*.oo +*.o +*.elf +*.bin + diff --git a/z21emu/INSTALL b/z21emu/INSTALL new file mode 100644 index 0000000..e69de29 diff --git a/z21emu/Makefile b/z21emu/Makefile new file mode 100644 index 0000000..705831a --- /dev/null +++ b/z21emu/Makefile @@ -0,0 +1,123 @@ +# .SILENT: + +DEPENDFILE=.depend +VERSION=0.1 + +# +# default configuration +# after chaning run make config +# default ports: 21105, 21106 and 3472? +PREFIX=/usr/local +DATAPREFIX=/var/lib +RUNPID=/var/run/z21Emulation.pid +ETCPREFIX=/etc +# DEFAULT_Z21PORT=21105 +DEFAULT_Z21PORT=21104 + +# +# +# +ifndef CXX +CXX=g++ +endif +#CXX=/data/CreateImages/RaspberryPi/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-g++ +CXXFLAGS= -ggdb -fPIC -Wall -pg +LDFLAGS= -lm -lc -pg +# +# +# + +all: dep z21emu + +# install: $(OBJSLAVES) collect-master collectd +# cp -rf collectd $(PREFIX)/bin +# cp -rf collect-master $(PREFIX)/bin +# $(foreach i,$(OBJSLAVES), cp -rf $(i) $(PREFIX)/bin;) +# +# mkdir -p $(ETCPREFIX)/collect +# $(foreach i,$(shell ls *.conf.sample), cp -rvf $(i) $(ETCPREFIX)/collect/;) +# $(foreach i,$(shell ls *.map), cp -rvf $(i) $(ETCPREFIX)/collect/;) +# $(foreach i,$(shell ls *.conf), echo $(i);) +# mkdir -p $(DATAPREFIX)/collect +# +# +# installinitd: install +# cp -rf collectd.sh /etc/init.d +# ln -fs ../init.d/collectd.sh /etc/rc2.d/S20collectd.sh +# ln -fs ../init.d/collectd.sh /etc/rc0.d/K10collectd.sh +# ln -fs ../init.d/collectd.sh /etc/rc1.d/K10collectd.sh +# ln -fs ../init.d/collectd.sh /etc/rc6.d/K10collectd.sh +# +# uninstall: +# rm -rf $(PREFIX)/bin/collectd +# rm -rf $(PREFIX)/bin/collect-master +# rm -rf /etc/init.d/collectd.sh +# rm -rf /etc/rc2.d/S10collectd.sh +# rm -rf /etc/rc0.d/K10collectd.sh +# rm -rf /etc/rc1.d/K10collectd.sh +# rm -rf /etc/rc6.d/K10collectd.sh +# +# $(foreach i,$(OBJSLAVES), rm -rf $(PREFIX)/bin/$(i);) +# # rm -rf $(ETCPREFIX)/collect +# + +z21emu: z21emu.o udp.o debug.o z21prot.o i2csensor.o + $(CXX) $^ -o $@ $(LDFLAGS) + + +config: + echo "#ifndef _CONFIG_H_" > config.h + echo "#define _CONFIG_H_" >> config.h + echo "" >> config.h + echo "#define VERSION \"$(VERSION)\"" >> config.h + echo "" >> config.h + echo "#define PREFIX \"$(PREFIX)\"" >> config.h + echo "#define RUNPID \"$(RUNPID)\"" >> config.h + echo "#define DATAPREFIX \"$(DATAPREFIX)\"" >> config.h + echo "#define ETCPREFIX \"$(ETCPREFIX)\"" >> config.h + echo "" >> config.h + echo "#define DEFAULT_Z21PORT $(DEFAULT_Z21PORT)" >> config.h + echo "" >> config.h +# ifeq ($(HAVE_SIMPLEHD),1) +# echo "#define HAVE_SIMPLEHD 1" >> config.h +# else +# echo "// #define HAVE_SIMPLEHD 1" >> config.h +# endif + echo "" >> config.h + + echo "#endif" >> config.h + +rebuild: clean all + +dep: + $(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE) + +dist: + mkdir z21emu-$(VERSION) + cp -rf *.conf.sample z21emu-$(VERSION)/ + cp -rf *.cc z21emu-$(VERSION)/ + cp -rf *.h z21emu-$(VERSION)/ + cp -rf *.sh z21emu-$(VERSION)/ + cp -rf Makefile z21emu-$(VERSION)/ + cp -rf INSTALL z21emu-$(VERSION)/ + tar cvzf z21emu-$(VERSION).tgz z21emu-$(VERSION) + rm -rf z21emu-$(VERSION) + +clean: + rm *.s -rf + rm *.o -rf + rm *.oo -rf + rm *~ -rf + rm -rf .depend + rm -rf *.so + rm -rf *.so.* + rm -rf z21emu + rm -rf gmon.out + rm -rf config.h + rm -rf Makefile.rules + +cleanall: clean + +source: cleanall + +-include $(DEPENDFILE) diff --git a/z21emu/atmega16_detect/Makefile b/z21emu/atmega16_detect/Makefile new file mode 100644 index 0000000..d162a94 --- /dev/null +++ b/z21emu/atmega16_detect/Makefile @@ -0,0 +1,41 @@ +# .SILENT: + +# Atmega88 +# CFLAGS= -Os -g -Wall -mmcu=atmega16 -DF_CPU=8000000UL +# LDFLAGS= -mmcu=atmega16 + +CPUTYPE1= atmega16 +CPUTYPE2= m16 + +# Atmega32 +CFLAGS= -Os -g -Wall -mmcu=$(CPUTYPE1) -DF_CPU=16000000UL +LDFLAGS= -mmcu=$(CPUTYPE1) + +all: gleiserkennung-v3.bin + +%.o: %.c + avr-gcc $(CFLAGS) -c -o $@ $^ + +rebuild: clean all + +gleiserkennung-v3.elf: gleiserkennung-v3.o eprom.o + avr-gcc $^ -o $@ $(LDFLAGS) + + +%.bin: %.elf + avr-objcopy -j .text -j .data -O binary $^ $@ + +clean: + rm *.o -rf + rm *.bin -rf + rm *.elf -rf + rm *~ -rf + +cleanall: clean + +source: cleanall + +upload-v3: gleiserkennung-v3.bin + avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v3.bin:r + + diff --git a/z21emu/atmega16_detect/eprom.c b/z21emu/atmega16_detect/eprom.c new file mode 100644 index 0000000..f1913af --- /dev/null +++ b/z21emu/atmega16_detect/eprom.c @@ -0,0 +1,26 @@ +/* + * eprom.c + * + * Created on: 11.02.2018 + * Author: steffen + */ + + +#include "eprom.h" + +void EEPROM_write(unsigned int uiAddress, unsigned char ucData) { + while(EECR & (1< +#include + +void EEPROM_write(unsigned int uiAddress, unsigned char ucData); +unsigned char EEPROM_read(unsigned int uiAddress); + + +#endif /* ATMEGA8_DETECT_EPROM_H_ */ diff --git a/z21emu/atmega16_detect/gleiserkennung-v3.c b/z21emu/atmega16_detect/gleiserkennung-v3.c new file mode 100644 index 0000000..b4cb03e --- /dev/null +++ b/z21emu/atmega16_detect/gleiserkennung-v3.c @@ -0,0 +1,284 @@ +/************************************************************ + + * reads some dis and make them readable over i2c bus. + * + * Atmega 16 + * +-------+ + * S26 (XCK/T0) PB0 -|1 O 40|- PA0 (ADC0) S14 + * S25 (T1) PB1 -|2 39|- PA1 (ADC1) S13 + * S24 (INT2/AIN0) PB2 -|3 38|- PA2 (ADC2) S12 + * S23 (OC0/AIN1) PB3 -|4 37|- PA3 (ADC3) S11 + * S22 (SS) PB4 -|5 36|- PA4 (ADC4) S10 + * (MOSI) PB5 -|6 35|- PA5 (ADC5) S9 + * (MISO) PB6 -|7 34|- PA6 (ADC6) S8 + * (SCK) PB7 -|8 33|- PA7 (ADC7) + * RESET -|9 32|- AREF + * VCC -|10 31|- GND + * GND -|11 30|- AVCC + * XTAL2 -|12 29|- PC7 (TOSC2) S7 + * XTAL1 -|13 28|- PC6 (TOSC1) S6 + * S21 (RXD) PD0 -|14 27|- PC5 (TDI) S5 + * S20 (TXD) PD1 -|15 26|- PC4 (TDO) S4 + * S19 (INT0) PD2 -|16 25|- PC3 (TMS) S3 + * S18 (INT1) PD3 -|17 24|- PC2 (TCK) S2 + * S17 (OC1B) PD4 -|18 23|- PC1 (DSA) I2C + * S16 (OC1A) PD5 -|19 22|- PC0 (SCL) I2C + * S15 (ICP1) PD6 -|20 21|- PD7 (OC2) S1 + * +-------+ */ + +#include +#include +#include +#include + +#include +#include + +#include "eprom.h" + +#define TWCR_ACK TWCR = (1<= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) { + i2c_reg = data; + TWCR_ACK; + } + else + TWCR_NACK; + } + else { + if(i2c_reg < I2C_NUM_REGS) { + i2c_regs[i2c_reg] = data; + i2c_reg++; + TWCR_ACK; + } + else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) { + i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data; + i2c_reg++; + TWCR_ACK; + } + else TWCR_NACK; + } + break; + + case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben. + case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert + if (i2c_reg == 0xFF) { + i2c_reg = 0; + } + if (i2c_reg < I2C_NUM_REGS) { + TWDR = i2c_regs[i2c_reg]; + i2c_reg++; + TWCR_ACK; + } + else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) { + TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET]; + i2c_reg++; + TWCR_ACK; + } + else TWCR_NACK; + break; + + case TW_SR_STOP: + TWCR_ACK; + break; + + case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert + case TW_SR_DATA_NACK: // 0x88 + case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received + default: + TWCR_RESET; + break; + } +} + +///////////////////////////////////////////////////////////////////////// +// + +int main( void ) { + uint32_t cnt[32] = { 0 }; + unsigned int i; + uint32_t inval = 0; + uint32_t temp = 0; + int offdelay; + + // + // disable JTAG + MCUCSR |= (1< 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) { + i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR; + } + + i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY); + if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) { + i2c_system[I2C_SREG_DIOFFDELAY] = 0x20; + } + + i2c_slave_init (i2c_system[I2C_SREG_ADDR]); + + for (i = 0; i < 32; i++) cnt[i] = 0; + + // + // system loop + while( 1 ) { + // + // digital in registers.. + offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8; + + // S1 - S14 + i = 0; if (!(PIND & (1 << 7))) cnt[i] = offdelay; + i++; if (!(PINC & (1 << 2))) cnt[i] = offdelay; + i++; if (!(PINC & (1 << 3))) cnt[i] = offdelay; + i++; if (!(PINC & (1 << 4))) cnt[i] = offdelay; + i++; if (!(PINC & (1 << 5))) cnt[i] = offdelay; + i++; if (!(PINC & (1 << 6))) cnt[i] = offdelay; + i++; if (!(PINC & (1 << 7))) cnt[i] = offdelay; + + i++; if (!(PINA & (1 << 6))) cnt[i] = offdelay; + i++; if (!(PINA & (1 << 5))) cnt[i] = offdelay; + i++; if (!(PINA & (1 << 4))) cnt[i] = offdelay; + i++; if (!(PINA & (1 << 3))) cnt[i] = offdelay; + i++; if (!(PINA & (1 << 2))) cnt[i] = offdelay; + i++; if (!(PINA & (1 << 1))) cnt[i] = offdelay; + i++; if (!(PINA & (1 << 0))) cnt[i] = offdelay; + + // S15 - S26 + i++; if (!(PIND & (1 << 6))) cnt[i] = offdelay; + i++; if (!(PIND & (1 << 5))) cnt[i] = offdelay; + i++; if (!(PIND & (1 << 4))) cnt[i] = offdelay; + i++; if (!(PIND & (1 << 3))) cnt[i] = offdelay; + i++; if (!(PIND & (1 << 2))) cnt[i] = offdelay; + i++; if (!(PIND & (1 << 1))) cnt[i] = offdelay; + i++; if (!(PIND & (1 << 0))) cnt[i] = offdelay; + + i++; if (!(PINB & (1 << 4))) cnt[i] = offdelay; + i++; if (!(PINB & (1 << 3))) cnt[i] = offdelay; + i++; if (!(PINB & (1 << 2))) cnt[i] = offdelay; + i++; if (!(PINB & (1 << 1))) cnt[i] = offdelay; + i++; if (!(PINB & (1 << 0))) cnt[i] = offdelay; + + + // all values + for (i = 0; i < 16; i++) { + if (cnt[i] == 0) inval &= ~(1 << (i)); + else { + cnt[i]--; + inval |= (1 << (i)); + } + } + + for (i = 0; i < 16; i++) { + if (cnt[16+i] == 0) temp &= ~(1 << (i)); + else { + cnt[16+i]--; + temp |= (1 << (i)); + } + } + + i2c_regs[0] = (unsigned char) (inval & 0x000000FF); + i2c_regs[1] = (unsigned char) ((inval & 0x0000FF00) >> 8); + i2c_regs[2] = (unsigned char) (temp & 0x000000FF); + i2c_regs[3] = (unsigned char) ((temp & 0x0000FF00) >> 8); + + + // + // system registers + if (i2c_system[I2C_SREG_CMD] != 0) { + if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) { + cli(); + i2c_system[I2C_SREG_CMD] = 0; + for (i = 0; i < I2C_SREG_MAX; i++) { + i2c_system[i] = EEPROM_read(i); + } + sei(); + } + + if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) { + cli(); + i2c_system[I2C_SREG_CMD] = 0; + for (i = 0; i < I2C_SREG_MAX; i++) { + EEPROM_write(i, i2c_system[i]); + } + sei(); + } + } + i2c_system[I2C_SREG_CMD] = 0; + } + return 0; +}; + + diff --git a/z21emu/atmega8_detect/Makefile b/z21emu/atmega8_detect/Makefile new file mode 100644 index 0000000..d82c528 --- /dev/null +++ b/z21emu/atmega8_detect/Makefile @@ -0,0 +1,47 @@ +# .SILENT: + +# Atmega88 +# CFLAGS= -Os -g -Wall -mmcu=atmega16 -DF_CPU=8000000UL +# LDFLAGS= -mmcu=atmega16 + +CPUTYPE1= atmega8 +CPUTYPE2= m8 + +# Atmega32 +CFLAGS= -Os -g -Wall -mmcu=$(CPUTYPE1) -DF_CPU=16000000UL +LDFLAGS= -mmcu=$(CPUTYPE1) + +all: gleiserkennung-v1.bin gleiserkennung-v2.bin + +%.o: %.c + avr-gcc $(CFLAGS) -c -o $@ $^ + +rebuild: clean all + +gleiserkennung-v2.elf: gleiserkennung-v2.o eprom.o + avr-gcc $^ -o $@ $(LDFLAGS) + + +gleiserkennung-v1.elf: gleiserkennung-v1.o eprom.o + avr-gcc $^ -o $@ $(LDFLAGS) + +%.bin: %.elf + avr-objcopy -j .text -j .data -O binary $^ $@ + +clean: + rm *.o -rf + rm *.bin -rf + rm *.elf -rf + rm *~ -rf + +cleanall: clean + +source: cleanall + +upload-v1: gleiserkennung-v1.bin + avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v1.bin:r + +upload-v2: gleiserkennung-v2.bin + avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v2.bin:r + + diff --git a/z21emu/atmega8_detect/eprom.c b/z21emu/atmega8_detect/eprom.c new file mode 100644 index 0000000..f1913af --- /dev/null +++ b/z21emu/atmega8_detect/eprom.c @@ -0,0 +1,26 @@ +/* + * eprom.c + * + * Created on: 11.02.2018 + * Author: steffen + */ + + +#include "eprom.h" + +void EEPROM_write(unsigned int uiAddress, unsigned char ucData) { + while(EECR & (1< +#include + +void EEPROM_write(unsigned int uiAddress, unsigned char ucData); +unsigned char EEPROM_read(unsigned int uiAddress); + + +#endif /* ATMEGA8_DETECT_EPROM_H_ */ diff --git a/z21emu/atmega8_detect/gleiserkennung-v1.c b/z21emu/atmega8_detect/gleiserkennung-v1.c new file mode 100644 index 0000000..415e2e2 --- /dev/null +++ b/z21emu/atmega8_detect/gleiserkennung-v1.c @@ -0,0 +1,247 @@ +/************************************************************ + * reads some digital in and make them readable over i2c bus. + * register 0 - + * + * +-------+ + * (RESET) PC6 -|1 O 28|- PC5 (ADC5/SCL) + * S3 (RXD) PD0 -|2 27|- PC4 (ADC4/SDA) + * S2 (TXD) PD1 -|3 26|- PC3 (ADC3) + * S1 (INT0) PD2 -|4 25|- PC2 (ADC2) S12 + * S10 (INT1) PD3 -|5 24|- PC1 (ADC1) S16 + * S7 (XCK/T0)PD4 -|6 23|- PC0 (ADC0) S15 + * VCC -|7 22|- GND + * GND -|8 21|- AREF + * S8 (XTAL2/TOSC2) PB6 -|9 20|- AVCC + * S9 (XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK) + * S4 (T1) PD5 -|11 18|- PB4 (MISO) + * S5 (AIN0) PD6 -|12 17|- PB3 (MOSI(OC2) + * S6 (AIN1) PD7 -|13 16|- PB2 (SS/OC1B) S14 + * S11 (ICP1) PB0 -|14 15|- PB1 (OC1A) S13 + * +-------+ + */ + +#include +#include +#include +#include + +#include +#include + +#include "eprom.h" + +#define TWCR_ACK TWCR = (1<= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) { + i2c_reg = data; + TWCR_ACK; + } + else + TWCR_NACK; + } + else { + if(i2c_reg < I2C_NUM_REGS) { + i2c_regs[i2c_reg] = data; + i2c_reg++; + TWCR_ACK; + } + else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) { + i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data; + i2c_reg++; + TWCR_ACK; + } + else TWCR_NACK; + } + break; + + case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben. + case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert + if (i2c_reg == 0xFF) { + i2c_reg = 0; + } + if (i2c_reg < I2C_NUM_REGS) { + TWDR = i2c_regs[i2c_reg]; + i2c_reg++; + TWCR_ACK; + } + else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) { + TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET]; + i2c_reg++; + TWCR_ACK; + } + else TWCR_NACK; + break; + + case TW_SR_STOP: + TWCR_ACK; + break; + + case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert + case TW_SR_DATA_NACK: // 0x88 + case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received + default: + TWCR_RESET; + break; + } +} + +///////////////////////////////////////////////////////////////////////// +// + +int main( void ) { + long int cnt[16] = { 0 }; + unsigned int i; + unsigned short int inval = 0; + unsigned short int temp = 0; + int offdelay; + + // + // read all variables from eeprom + i2c_system[I2C_SREG_VERSION] = VERSION; + i2c_system[I2C_SREG_CMD] = 0; + + i2c_system[I2C_SREG_ADDR] = EEPROM_read(I2C_SREG_ADDR); + if (i2c_system[I2C_SREG_ADDR] > 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) { + i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR; + } + + i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY); + if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) { + i2c_system[I2C_SREG_DIOFFDELAY] = 0x20; + } + + i2c_system[I2C_SREG_DOOFFDELAY] = EEPROM_read(I2C_SREG_DOOFFDELAY); + if (i2c_system[I2C_SREG_DOOFFDELAY] == 0) { + i2c_system[I2C_SREG_DOOFFDELAY] = 0xFF; + } + + i2c_slave_init (i2c_system[I2C_SREG_ADDR]); + + // + // system loop + while( 1 ) { + // + // digital in registers.. + offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8; + + i = 0; + if (PIND & (1 << 2)) cnt[0] = offdelay; + if (PIND & (1 << 1)) cnt[1] = offdelay; + if (PIND & (1 << 0)) cnt[2] = offdelay; + if (PIND & (1 << 5)) cnt[3] = offdelay; + if (PIND & (1 << 6)) cnt[4] = offdelay; + if (PIND & (1 << 7)) cnt[5] = offdelay; + if (PIND & (1 << 4)) cnt[6] = offdelay; + if (PINB & (1 << 6)) cnt[7] = offdelay; + + if (PINB & (1 << 7)) cnt[8] = offdelay; + if (PIND & (1 << 3)) cnt[9] = offdelay; + if (PINB & (1 << 0)) cnt[10] = offdelay; + if (PINC & (1 << 2)) cnt[11] = offdelay; + if (PINB & (1 << 1)) cnt[12] = offdelay; + if (PINB & (1 << 2)) cnt[13] = offdelay; + if (PINC & (1 << 0)) cnt[14] = offdelay; + if (PINC & (1 << 1)) cnt[15] = offdelay; + + // all values + for (i = 0; i < 16; i++) { + if (cnt[i] == 0) inval &= ~(1 << (i)); + else { + cnt[i]--; + inval |= (1 << (i)); + } + } + + i2c_regs[0] = (unsigned char) (inval & 0x00FF); + i2c_regs[1] = (unsigned char) ((inval & 0xFF00) >> 8); + + temp++; + i2c_regs[2] = (unsigned char) (temp & 0x00FF); + i2c_regs[3] = (unsigned char) ((temp & 0xFF00) >> 8); + + + // + // system registers + if (i2c_system[I2C_SREG_CMD] != 0) { + if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) { + cli(); + i2c_system[I2C_SREG_CMD] = 0; + for (i = 0; i < I2C_SREG_MAX; i++) { + i2c_system[i] = EEPROM_read(i); + } + sei(); + } + + if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) { + cli(); + i2c_system[I2C_SREG_CMD] = 0; + for (i = 0; i < I2C_SREG_MAX; i++) { + EEPROM_write(i, i2c_system[i]); + } + sei(); + } + } + i2c_system[I2C_SREG_CMD] = 0; + } + return 0; +}; + + diff --git a/z21emu/atmega8_detect/gleiserkennung-v2.c b/z21emu/atmega8_detect/gleiserkennung-v2.c new file mode 100644 index 0000000..68a09df --- /dev/null +++ b/z21emu/atmega8_detect/gleiserkennung-v2.c @@ -0,0 +1,250 @@ +/************************************************************ + * reads some dis and make them readable over i2c bus. + * out of 8 registers only the register 1 is needed + * + * +-------+ + * (RESET) PC6 -|1 O 28|- PC5 (ADC5/SCL) + * Sensor 1 (RXD) PD0 -|2 27|- PC4 (ADC4/SDA) + * Sensor 2 (TXD) PD1 -|3 26|- PC3 (ADC3) Relais 1 + * Sensor 3 (INT0) PD2 -|4 25|- PC2 (ADC2) Relais 2 + * Sensor 4 (INT1) PD3 -|5 24|- PC1 (ADC1) Relais 3 + * Sensor 5 (XCK/T0) PD4 -|6 23|- PC0 (ADC0) Relais 4 + * VCC -|7 22|- GND + * GND -|8 21|- AREF + * Sen6(XTAL2/TOSC2) PB6 -|9 20|- AVCC + * Sen7(XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK) + * Sensor 8 (T1) PD5 -|11 18|- PB4 (MISO) + * (AIN0) PD6 -|12 17|- PB3 (MOSI(OC2) + * Relais 7 (AIN1) PD7 -|13 16|- PB2 (SS/OC1B) Relais 5 + * Relais 8 (ICP1) PB0 -|14 15|- PB1 (OC1A) Relais 6 + * +-------+ + */ + +#include +#include +#include +#include + +#include +#include + +#include "eprom.h" + +#define TWCR_ACK TWCR = (1<= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) { + i2c_reg = data; + TWCR_ACK; + } + else + TWCR_NACK; + } + else { + if(i2c_reg < I2C_NUM_REGS) { + i2c_regs[i2c_reg] = data; + i2c_reg++; + TWCR_ACK; + } + else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) { + i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data; + i2c_reg++; + TWCR_ACK; + } + else TWCR_NACK; + } + break; + + case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben. + case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert + if (i2c_reg == 0xFF) { + i2c_reg = 0; + } + if (i2c_reg < I2C_NUM_REGS) { + TWDR = i2c_regs[i2c_reg]; + i2c_reg++; + TWCR_ACK; + } + else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) { + TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET]; + i2c_reg++; + TWCR_ACK; + } + else TWCR_NACK; + break; + + case TW_SR_STOP: + TWCR_ACK; + break; + + case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert + case TW_SR_DATA_NACK: // 0x88 + case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received + default: + TWCR_RESET; + break; + } +} + +///////////////////////////////////////////////////////////////////////// +// + +int main( void ) { + long int cnt[8] = { 0 }; + unsigned int i; + char inval = 0; + int offdelay; + + // + // read all variables from eeprom + i2c_system[I2C_SREG_VERSION] = VERSION; + i2c_system[I2C_SREG_CMD] = 0; + + i2c_system[I2C_SREG_ADDR] = EEPROM_read(I2C_SREG_ADDR); + if (i2c_system[I2C_SREG_ADDR] > 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) { + i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR; + } + + i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY); + if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) { + i2c_system[I2C_SREG_DIOFFDELAY] = 0x20; + } + + i2c_system[I2C_SREG_DOOFFDELAY] = EEPROM_read(I2C_SREG_DOOFFDELAY); + if (i2c_system[I2C_SREG_DOOFFDELAY] == 0) { + i2c_system[I2C_SREG_DOOFFDELAY] = 0xFF; + } + + i2c_slave_init (i2c_system[I2C_SREG_ADDR]); + + DDRB |= 1 | (1<<1) | (1<<2); + DDRC |= 1 | (1<<1) | (1<<2) | (1<<3); + DDRD |= (1<<7); + + // + // system loop + while( 1 ) { + // + // digital in registers.. + offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8; + + if (PIND & 0x01) cnt[0] = offdelay; + if (PIND & 0x02) cnt[1] = offdelay; + if (PIND & 0x04) cnt[2] = offdelay; + if (PIND & 0x08) cnt[3] = offdelay; + if (PIND & 0x10) cnt[4] = offdelay; + if (PINB & 0x40) cnt[5] = offdelay; + if (PINB & 0x80) cnt[6] = offdelay; + if (PIND & 0x20) cnt[7] = offdelay; + + for (i = 0; i < 8; i++) { + if (cnt[i] == 0) inval &= ~(1 << (i)); + else { + cnt[i]--; + inval |= (1 << (i)); + } + } + i2c_regs[0] = inval; + + // + // digital out registers.. + if (i2c_regs[1] & 0x01) PORTC |= (1 << 3); + else PORTC &= ~(1 << 3); + if (i2c_regs[1] & 0x02) PORTC |= (1 << 2); + else PORTC &= ~(1 << 2); + if (i2c_regs[1] & 0x04) PORTC |= (1 << 1); + else PORTC &= ~(1 << 1); + if (i2c_regs[1] & 0x08) PORTC |= 1; + else PORTC &= ~1; + if (i2c_regs[1] & 0x10) PORTB |= (1 << 2); + else PORTB &= ~(1 << 2); + if (i2c_regs[1] & 0x20) PORTB |= (1 << 1); + else PORTB &= ~(1 << 1); + if (i2c_regs[1] & 0x40) PORTD |= (1 << 7); + else PORTD &= ~(1 << 7); + if (i2c_regs[1] & 0x80) PORTB |= 1; + else PORTB &= ~1; + + // + // system registers + if (i2c_system[I2C_SREG_CMD] != 0) { + if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) { + cli(); + i2c_system[I2C_SREG_CMD] = 0; + for (i = 0; i < I2C_SREG_MAX; i++) { + i2c_system[i] = EEPROM_read(i); + } + sei(); + } + + if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) { + cli(); + i2c_system[I2C_SREG_CMD] = 0; + for (i = 0; i < I2C_SREG_MAX; i++) { + EEPROM_write(i, i2c_system[i]); + } + sei(); + } + } + i2c_system[I2C_SREG_CMD] = 0; + } + return 0; +}; + + diff --git a/z21emu/atmega8_detect/gleiserkennung.c b/z21emu/atmega8_detect/gleiserkennung.c new file mode 100644 index 0000000..2315024 --- /dev/null +++ b/z21emu/atmega8_detect/gleiserkennung.c @@ -0,0 +1,153 @@ +/************************************************************ + * reads some dis and make them readable over i2c bus. + * out of 8 registers only the register 1 is needed + * + * +-------+ + * (RESET) PC6 -|1 O 28|- PC5 (ADC5/SCL) + * (RXD) PD0 -|2 27|- PC4 (ADC4/SDA) + * (TXD) PD1 -|3 26|- PC3 (ADC3) + * (INT0) PD2 -|4 25|- PC2 (ADC2) + * (INT1) PD3 -|5 24|- PC1 (ADC1) Sensor 4 + * (XCK/T0) PD4 -|6 23|- PC0 (ADC0) Sensor 3 + * VCC -|7 22|- GND + * GND -|8 21|- AREF + * (XTAL2/TOSC2) PB6 -|9 20|- AVCC + * (XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK) + * Sensor 8 (T1) PD5 -|11 18|- PB4 (MISO) + * Sensor 7 (AIN0) PD6 -|12 17|- PB3 (MOSI(OC2) + * Sensor 6 (AIN1) PD7 -|13 16|- PB2 (SS/OC1B) Sensor 2 + * Sensor 5 (ICP1) PB0 -|14 15|- PB1 (OC1A) Sensor 1 + * +-------+ + */ + +#include +#include +#include +#include + +#include +#include + +#define TWCR_ACK TWCR = (1< +#include +#include + +#include "debug.h" + +char *int2hex (int val, char *buf, int len) { + char tmp[] = "0123456789ABCDEF"; + int i; + unsigned int v; + + if (buf == NULL) return NULL; + + memset (buf, '0', len-1); + buf[len-1] = 0; + for (v = val, i = 0; i < len-1; i++) { + buf[len-2-i] = tmp[v % 16]; + v = v >> 4; + } + + return buf; +} + +void debug_mem (char *c, int len) { + int i; + int v; + char _hexpos[32]; + char _hexval[32]; + + for (i = 0; i < len; i++) { + if (i > 0 && (i % 16) == 0) printf ("\n"); + if ((i % 16) == 0) + printf (" 0x%s ", int2hex(i, _hexpos, 5)); + if ((i % 8) == 0) printf (" "); + v = (unsigned char) c[i]; + printf ("%s ", int2hex(v, _hexval, 3)); + } + printf ("\n"); +}; diff --git a/z21emu/debug.h b/z21emu/debug.h new file mode 100644 index 0000000..a9dffa7 --- /dev/null +++ b/z21emu/debug.h @@ -0,0 +1,16 @@ +/* + * debug.h + * + * Created on: 15.12.2017 + * Author: steffen + */ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + + +void debug_mem (char *c, int len); +char *int2hex (int val, char *buf, int len); + + +#endif /* DEBUG_H_ */ diff --git a/z21emu/i2csensor.cc b/z21emu/i2csensor.cc new file mode 100644 index 0000000..ff9c69a --- /dev/null +++ b/z21emu/i2csensor.cc @@ -0,0 +1,105 @@ +/* + * i2csensor.cc + * + * Created on: 18.12.2017 + * Author: steffen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2csensor.h" + + +#define LEN_FILENAME 255 +#define LEN_BUFFER 32 + +I2C::I2C () { + i2cdev = 1; +}; + +I2C::~I2C () { +}; + +bool I2C::ReadByte(int addr, int reg, uint8_t *readval) { + int file; + char filename[LEN_FILENAME]; + unsigned char buffer[LEN_BUFFER]; + + if (readval == NULL) return false; + // i2c device + snprintf(filename, 255, "/dev/i2c-%d", i2cdev); + file = open(filename, O_RDWR); + if (file < 0) { + return false; + } + + // setup slave addresse + if (ioctl(file, I2C_SLAVE, addr) < 0) { + close (file); + return false; + } + + usleep (10000); + + // write register + buffer[0] = reg; + if (write(file, buffer, 1) != 1) { + close (file); + return false; + } + + // read value + if (read(file, buffer, 1) != 1) { + close (file); + return false; + } + + *readval = buffer[0]; + close (file); + + return true; +}; + +bool I2C::SendByte(int addr, int reg, uint8_t data) { + int file; + char filename[LEN_FILENAME]; + unsigned char buffer[LEN_BUFFER]; + + // i2c device + snprintf(filename, 255, "/dev/i2c-%d", i2cdev); + file = open(filename, O_RDWR); + if (file < 0) { + return false; + } + + // setup slave addresse + if (ioctl(file, I2C_SLAVE, addr) < 0) { + close (file); + return false; + } + + usleep (10000); + + // write register and value + buffer[0] = reg; + buffer[1] = data; + if (write(file, buffer, 2) != 2) { + close (file); + return false; + } + close (file); + + return true; +}; + + + diff --git a/z21emu/i2csensor.h b/z21emu/i2csensor.h new file mode 100644 index 0000000..9040e7c --- /dev/null +++ b/z21emu/i2csensor.h @@ -0,0 +1,31 @@ +/* + * i2csensor.h + * + * Created on: 18.12.2017 + * Author: steffen + */ + +#ifndef I2CSENSOR_H_ +#define I2CSENSOR_H_ + +#include +#include +#include +#include +#include + +using namespace std; + +class I2C { +private: + int i2cdev; + +public: + I2C (); + ~I2C (); + bool ReadByte(int addr, int reg, uint8_t *readval); + bool SendByte(int addr, int reg, uint8_t data); +}; + + +#endif /* I2CSENSOR_H_ */ diff --git a/z21emu/udp.cc b/z21emu/udp.cc new file mode 100644 index 0000000..17c945e --- /dev/null +++ b/z21emu/udp.cc @@ -0,0 +1,183 @@ +/* + * + */ + +#include +#include +#include +#include +#include +#include +#include /* close() */ +#include /* memset() */ + +#include "udp.h" + +char dnsip[NET_HOSTLEN]; + +int dns_filladdr (string host, string port, int ai_family, struct sockaddr_in *sAddr) { + struct addrinfo hints, *res; + int err; + + /* we have to complete the sAddr struct */ + bzero (&hints, sizeof (struct addrinfo)); + hints.ai_family = ai_family; + hints.ai_socktype = SOCK_DGRAM; + + if ((err = getaddrinfo (host.c_str(), port.c_str(), &hints, &res)) < 0) { + fprintf (stdout, "dns_filladdr (getaddrinfo):%s\n", gai_strerror (err)); + return -1; + } + + memcpy (sAddr, res->ai_addr, res->ai_addrlen); + freeaddrinfo (res); + + return 1; +}; + + +UDPConnection::UDPConnection() { + sock = -1; + port = ""; + writecnt = 0; + readcnt = 0; +}; + + +UDPConnection::~UDPConnection() { + Close(); +} + + +void UDPConnection::Close () { + if (sock > -1) close (sock); + sock = -1; +} + + +int UDPConnection::Listen(int port) { + struct sockaddr_in servAddr; + + /* socket creation */ + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("%s: socket error: %s \n",__FUNCTION__, strerror(errno)); + return 0; + } + + /* bind local server port */ + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(port); + if (bind (sock, (struct sockaddr *) &servAddr,sizeof(servAddr)) < 0) { + printf("%s: bind error: %s \n",__FUNCTION__, strerror(errno)); + return 0; + } + return 1; +} + + +int UDPConnection::Listen(string port) { + return Listen (atoi(port.c_str())); +} + + +long int UDPConnection::ReadTimeout(string *source, char *buffer, long int len, int timeout) { + int i; + + i = isData(timeout); + if (i > 0) { + return Read (source, buffer, len); + } + else + return i; +} + +long int UDPConnection::Read(string *source, char *buffer, long int len) { + int n; + socklen_t addrlen; + sockaddr_in srcAddr; + + if (!isListen()) return -1; + + memset(buffer, 0x0, len); + + addrlen = sizeof(srcAddr); + n = recvfrom(sock, buffer, len, 0, (sockaddr *) &srcAddr, &addrlen); + if(n<0) { + printf("%s: recvfrom error:%s\n",__FUNCTION__, strerror(errno)); + return -1; + } + + /* print received message */ + char addr[NET_HOSTLEN]; + snprintf (addr, NET_HOSTLEN, "%s:%d", inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port)); + (*source) = (char*)addr; + + return n; +} + + +long int UDPConnection::Send(string destaddr, char *buffer, long int len) { + int s; + int addrlen = sizeof (struct sockaddr_in); + sockaddr_in dstAddr; + string host; + string port; + + if (!isListen()) { + /* socket creation */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("%s: socket error: %s \n",__FUNCTION__, strerror(errno)); + return -1; + } + } + else s = sock; + + int pos = destaddr.rfind(':', destaddr.length()); + if (pos == -1) { + port = "NET_PORT"; + host = destaddr; + } + else { + port = destaddr.substr (pos+1, destaddr.length() - pos); + host = destaddr.substr (0, pos); + } + + dns_filladdr (host, port, PF_INET, &dstAddr); + if (sendto (s, buffer, len, 0, (sockaddr *) &dstAddr, addrlen) == -1) { + printf("%s: sendto error: %s \n",__FUNCTION__, strerror(errno)); + return -1; + } + + if (!isListen()) close (s); + + return 1; +} + +int UDPConnection::isListen() { + return (sock != -1); +} + +int UDPConnection::isData(int timeout) { + fd_set sockset; + struct timeval tval; + + if (sock <= 0) { + printf ("isData:socket error\n"); + return -1; + } + + FD_ZERO (&sockset); + FD_SET (sock, &sockset); + tval.tv_sec = timeout / 1000; + tval.tv_usec = (timeout % 1000); + + if (select (sock + 1, &sockset, NULL, NULL, &tval) >= 0) { + if (FD_ISSET (sock, &sockset)) { + return 1; + } + } + return 0; +} + + diff --git a/z21emu/udp.h b/z21emu/udp.h new file mode 100644 index 0000000..225d6ac --- /dev/null +++ b/z21emu/udp.h @@ -0,0 +1,55 @@ + +#ifndef _SP_UDP_H_ +#define _SP_UDP_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "config.h" + +using namespace std; + +#define NET_HOSTLEN 128 +#define NET_PORTLEN 6 +#define NET_BUFFERSIZE 1024 + + +class UDPConnection { +private: + string port; + int sock; + size_t readcnt; + size_t writecnt; +public: + UDPConnection(); + ~UDPConnection(); + + int Listen(int port); + int Listen(string port); + + long int ReadTimeout(string *srcaddr, char *buffer, long int len, int timeout); + long int Read(string *srcaddr, char *buffer, long int len); + long int Send(string destaddr, char *buffer, long int len); + + void Close(); + int isListen(); + int isData(int timeout); // timeout in ms; + + int getSocket() { return sock; }; + void setSocket(int s); +}; + +#endif diff --git a/z21emu/z21emu.cc b/z21emu/z21emu.cc new file mode 100644 index 0000000..4917102 --- /dev/null +++ b/z21emu/z21emu.cc @@ -0,0 +1,286 @@ +#include +#include +#include + +#include "config.h" +#include "udp.h" +#include "debug.h" +#include "z21prot.h" +#include "z21emu.h" +#include "i2csensor.h" + +using namespace std; + +struct s_rbussensor rbus[RBUS_MAXSENSORBYTES] = { 0 }; +struct s_xlanturnout xlturn[XLAN_TURNOUT_MAX] = { 0 }; + +void i2cloop(I2C *i2c); +void i2cscan(I2C *i2c); +void i2ccfgprint(); +int i2ccfgload(const char *fname); +void help(); + + +int main (int argc, char **argv) { +// time_t t1, t2; + string cfgfile = DEFAULT_CONFIG; + Z21Server z21server; + I2C i2c; + int i; + int numofclients = 0; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "-help") == 0) { + help(); + exit (0); + } + + if (strcmp (argv[i], "-scan") == 0) { + i2cscan(&i2c); + i2ccfgprint(); + exit (0); + } + + if (strcmp (argv[i], "-config") == 0) { + i++; + cfgfile = argv[i]; + printf ("using configfile: %s\n", cfgfile.c_str()); + } + } + + + if (i2ccfgload(cfgfile.c_str()) == 0) { + i2cscan(&i2c); + } + + z21server.Start(); + + while ( 1 ) { + // + // for detection of changed values + for (i = 0; i < RBUS_MAXSENSORBYTES; i++) + rbus[i].last = rbus[i].status; + +/* t2 = time (NULL); + if (t2-t1 > 1) { + rbus_status[2]++; + rbus_status[15]--; + t1 = t2; + } +*/ + if (numofclients > 0) i2cloop (&i2c); + + numofclients = z21server.Loop(); + usleep(25000); + }; + + return 0; +}; + + +void i2cloop (I2C *i2c) { + int index; // sensorbox number --> sbox + 0x30 = i2c address + + // + // digital in + for (index = 0; index < RBUS_MAXSENSORBYTES; index++) { + if (rbus[index].i2c_addr != 0) { + if (!i2c->ReadByte(rbus[index].i2c_addr, rbus[index].i2c_reg, &rbus[index].status)) + rbus[index].status = 0xFF; // error + } + } + + // + // digital out + for (index = 0; index < XLAN_TURNOUTBYTES; index++) { + if (xlturn[index].last != xlturn[index].output) { + // ignore if addr is not set + if (xlturn[index].i2c_addr == 0) xlturn[index].last = xlturn[index].output; + + // send data + else if (i2c->SendByte(xlturn[index].i2c_addr, xlturn[index].i2c_reg, xlturn[index].output)) { + xlturn[index].last = xlturn[index].output; + } + } + } +} + + +// +// scan all i2c devices read version and create configuration +void i2cscan(I2C *i2c) { + int dicnt; + int docnt; + int addr; + unsigned char ver; + + for (dicnt = 0, docnt = 0, addr = 0x20; addr < 0x7f; addr++) { + + if (i2c->ReadByte(addr, 0x20, &ver)) { + if (ver == 1) { + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x0; + dicnt++; + } + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x1; + dicnt++; + } + } + else if (ver == 2) { + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x0; + dicnt++; + } + if (docnt < RBUS_MAXSENSORBYTES) { + xlturn[docnt].i2c_addr = addr; + xlturn[docnt].i2c_reg = 0x1; + docnt++; + } + } + else if (ver == 3) { + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x0; + dicnt++; + } + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x1; + dicnt++; + } + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x2; + dicnt++; + } + if (dicnt < RBUS_MAXSENSORBYTES) { + rbus[dicnt].i2c_addr = addr; + rbus[dicnt].i2c_reg = 0x3; + dicnt++; + } + } + } + } +}; + +void i2ccfgprint() { + int i; + printf ("# autoscan configuration\n"); + printf ("#\n"); + printf ("# digital input configuration\n"); + printf ("#\n"); + printf ("# di NUM addr ADDR reg REG\n"); + + for (i = 0; i < RBUS_MAXSENSORBYTES; i++) if (rbus[i].i2c_addr != 0) + printf ("di %d addr %x reg %x\n", i, rbus[i].i2c_addr, rbus[i].i2c_reg); + + printf ("#\n"); + printf ("# digital output configuration\n"); + printf ("#\n"); + printf ("# do NUM addr ADDR reg REG\n"); + + for (i = 0; i < XLAN_TURNOUTBYTES; i++) if (xlturn[i].i2c_addr != 0) + printf ("do %d addr %x reg %x\n", i, xlturn[i].i2c_addr, xlturn[i].i2c_reg); +}; + + +#define STR_TOK_NOSPACE(_pnt_) while (_pnt_[0] != 0 && (_pnt_[0] == ' ' || _pnt_[0] == '\t')) _pnt_++ +#define STR_TOK_NEXT(_pnt_) while (_pnt_[0] != 0 && _pnt_[0] != ' ' && _pnt_[0] != '\t') _pnt_++ +int i2ccfgload(const char *fname) { + FILE *f; + char buf[1024]; + char *pos; + int tmp; + int index = -1; + int type; + int addr; + int reg; + + printf ("loading file: %s\n", fname); + f = fopen (fname, (char*)"r"); + if (f == NULL) { + printf ("error:%s\n", strerror(errno)); + return 0; + } + + while (fgets (buf, sizeof (buf), f) != NULL) { + pos = buf; + if (pos[0] == '#') continue; + type = I2CREGTYPE_UNDEF; + addr = 0; + reg = 0; + index = -1; + + while (pos != NULL && pos[0] != 0) { + STR_TOK_NOSPACE(pos); + if (strncmp ("di", pos, strlen ("di")) == 0) { + STR_TOK_NEXT(pos); + sscanf (pos, "%d", &index); + type = I2CREGTYPE_DI; + printf (" di %d", index); + } + if (strncmp ("do", pos, strlen ("do")) == 0) { + STR_TOK_NEXT(pos); + sscanf (pos, "%d", &index); + type = I2CREGTYPE_DO; + printf (" do %d", index); + } + if (strncmp ("addr", pos, strlen ("addr")) == 0) { + STR_TOK_NEXT(pos); + sscanf (pos, "%x", &addr); + printf (" addr %x", addr); + } + if (strncmp ("reg", pos, strlen ("reg")) == 0) { + STR_TOK_NEXT(pos); + sscanf (pos, "%x", ®); + printf (" reg %x", reg); + } + else STR_TOK_NEXT(pos); + } + + if (type == I2CREGTYPE_DI && index >= 0 && index < RBUS_MAXSENSORBYTES) { + rbus[index].i2c_addr = addr; + rbus[index].i2c_reg = reg; + printf ("--> DI (%d) OK\n", index); + } + else if (type == I2CREGTYPE_DO && index >= 0 && index < XLAN_TURNOUTBYTES) { + xlturn[index].i2c_addr = addr; + xlturn[index].i2c_reg = reg; + printf ("--> DO (%d) OK\n", index); + } + else { + printf (" error\n"); + } + } + fclose (f); + return 0; +}; +#undef STR_TOK_NEXT + + +void help () { + printf ("z21emu:\n"); + printf ("=======\n"); + printf ("\n"); + printf ("parameters: without any parameters the config will be read from file.\n"); + printf (" if no file is found, autoscan is used first.\n"); + printf (" -scan scanning i2c bus and print out a sample device config\n"); + printf (" -config FILE finename used for configuration (default %s/\n", DEFAULT_CONFIG); + printf ("\n"); +} + +void xlan_turnout (int addr, bool enable) { + int addrbyte = (addr-1)/8; + int bit = (addr-1)%8; + + if (addr == 0) return; + if (addrbyte < 0 || addrbyte >= XLAN_TURNOUTBYTES) return; + if (enable) xlturn[addrbyte].output |= (1 << bit); + else xlturn[addrbyte].output &= ~(1 << bit); +} + + diff --git a/z21emu/z21emu.conf.sample b/z21emu/z21emu.conf.sample new file mode 100644 index 0000000..a2be3d8 --- /dev/null +++ b/z21emu/z21emu.conf.sample @@ -0,0 +1,22 @@ +# autoscan configuration +# sensor NUM addr ADDR reg REG +sbox 0 addr 30 reg 0 +sbox 1 addr 31 reg 0 +sbox 2 addr 31 reg 1 +sbox 3 addr 0 reg 0 +sbox 4 addr 0 reg 0 +sbox 5 addr 0 reg 0 +sbox 6 addr 0 reg 0 +sbox 7 addr 0 reg 0 +sbox 8 addr 0 reg 0 +sbox 9 addr 0 reg 0 +sbox 10 addr 0 reg 0 +sbox 11 addr 0 reg 0 +sbox 12 addr 0 reg 0 +sbox 13 addr 0 reg 0 +sbox 14 addr 0 reg 0 +sbox 15 addr 0 reg 0 +sbox 16 addr 0 reg 0 +sbox 17 addr 0 reg 0 +sbox 18 addr 0 reg 0 +sbox 19 addr 0 reg 0 diff --git a/z21emu/z21emu.h b/z21emu/z21emu.h new file mode 100644 index 0000000..dea348f --- /dev/null +++ b/z21emu/z21emu.h @@ -0,0 +1,52 @@ +/* + * z21emu.h + * + * Created on: 16.12.2017 + * Author: steffen + */ + +#ifndef Z21EMU_H_ +#define Z21EMU_H_ + +#include "config.h" + +#define DEFAULT_CONFIG ETCPREFIX"/z21emu.conf" + +#define RBUS_BYTESPERGROUP 10 +#define RBUS_GROUPS 2 +#define RBUS_MAXSENSORBYTES (RBUS_GROUPS*RBUS_BYTESPERGROUP) + +#define XLAN_TURNOUT_MAX 1024 +#define XLAN_TURNOUTBYTES (XLAN_TURNOUT_MAX / 8) + +enum { + I2CREGTYPE_UNDEF, + I2CREGTYPE_DI, + I2CREGTYPE_DO +}; + +struct s_rbussensor { + unsigned char status; // current value + unsigned char last; // last value + + unsigned char i2c_addr; // i2c address + unsigned char i2c_reg; // i2c register +}; + +extern struct s_rbussensor rbus[RBUS_MAXSENSORBYTES]; + +struct s_xlanturnout { + unsigned char i2c_addr; // i2c address + unsigned char i2c_reg; // i2c register + + unsigned char output; // current value + unsigned char last; // last value +}; + +extern struct s_xlanturnout xlturn[XLAN_TURNOUT_MAX]; + + +void xlan_turnout (int addr, bool enable); + + +#endif /* Z21EMU_H_ */ diff --git a/z21emu/z21emu.sh b/z21emu/z21emu.sh new file mode 100644 index 0000000..68a2b53 --- /dev/null +++ b/z21emu/z21emu.sh @@ -0,0 +1,36 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: z21emu +# Required-Start: +# Required-Stop: +# Should-Start: +# Default-Start: +# Default-Stop: +# Short-Description: z21 wrapper to support i2c sensors +# Description: z21 is a control device for model trains. this software implements a wrapper onto the z21 protocoll so you can connect some i2c devices to the rocrail or any other model train controlling software supporting z21. +### END INIT INFO + +PATH=/sbin:/bin:/usr/local/bin:/usr/bin:/usr/sbin + +case "$1" in + start) + /usr/local/bin/z21emu >&2 > /dev/null & + ;; + restart|reload|force-reload) + echo "not pupported yet" >&2 + exit 3 + ;; + stop) + killall z21emu + ;; + status) + ps xa -H | grep z21emu + exit $? + ;; + *) + echo "Usage: z21emu.sh [start|stop|status]" >&2 + exit 3 + ;; +esac + +: diff --git a/z21emu/z21prot.cc b/z21emu/z21prot.cc new file mode 100644 index 0000000..dfaae11 --- /dev/null +++ b/z21emu/z21prot.cc @@ -0,0 +1,268 @@ +/* + * z21prot.cc + * + * Created on: 15.12.2017 + * Author: steffen + */ + +#include "config.h" +#include "z21prot.h" +#include "z21emu.h" +#include "debug.h" + +Z21Client::Z21Client() { +// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); +}; + +Z21Client::~Z21Client() { +// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); +}; + +bool Z21Client::LoopData (UDPConnection *udp, char *buffer, size_t len) { + short unsigned int pktlen = le16toh(bufgetint16(buffer, 0)); + short int pktheader = le16toh(bufgetint16(buffer, 2)); + int i, k; + + // LAN_GET_SERIAL_NUMBER + if (pktlen == 4 && pktheader == 0x10) { + bufsetint16 (outbuf, 0, htole16(8)); + bufsetint16 (outbuf, 2, htole16(0x10)); + bufsetint32 (outbuf, 4, htole32(55555953)); + udp->Send(source, outbuf, 8); + } + + // LAN_LOGOFF + else if (pktlen == 4 && pktheader == 0x0030) { + return false; + } + + // LAN_X_ Commandos + else if (pktheader == 0x0040) { + if (pktlen > len) { + printf ("ERROR: got broken udp paket? pktlen(%d) > len(%ld)\n", pktlen, len); + } else { + Z21_lan_x_data xdata; + int pos = 4; + int chksum; + char db; + + while (pos < pktlen) { + xdata.xheader = buffer[pos++]; + for (i = 0; i < Z21_X_LEN && (unsigned int) i+pos < len; i++) + xdata.db[i] = buffer[pos+i]; + + // LAN_X_GET_VERSION + if (xdata.xheader == 0x21 && + xdata.db[0] == 0x21 && xdata.db[1] == 0x00) { + printf ("LAN_X_GET_VERSION\n"); + pos += 2; + + bufsetint16 (outbuf, 0, htole16(9)); + bufsetint16 (outbuf, 2, htole16(0x40)); + + k = 4; + bufsetint8 (outbuf, k++, db=0x63); // XHeader + chksum = db; + + bufsetint8 (outbuf, k++, db=0x21); // DB0 + chksum = chksum ^ db; + + bufsetint8 (outbuf, k++, db=0x30); // DB1 + chksum = chksum ^ db; + + bufsetint8 (outbuf, k++, db=0x12); // DB2 + chksum = chksum ^ db; + + bufsetint8 (outbuf, k++, chksum); // XOR-Byte + // debug_mem(outbuf, k); + udp->Send(source, outbuf, k); + } + + // LAN_X_GET_FIRMWARE_VERSION + else if (xdata.xheader == 0xF1 && + xdata.db[0] == 0x0A && xdata.db[1] == 0xFB) { + printf ("LAN_X_GET_FIRMWARE_VERSION\n"); + pos += 3; + + bufsetint16 (outbuf, 0, htole16(9)); // LEN + bufsetint16 (outbuf, 2, htole16(0x40)); // X_CMD + + k = 4; + bufsetint8 (outbuf, k++, db=0xF3); // XHeader + chksum = db; + + bufsetint8 (outbuf, k++, db=0x0A); // DB0 + chksum = chksum ^ db; + + bufsetint8 (outbuf, k++, db=0x01); // DB1 + chksum = chksum ^ db; + + bufsetint8 (outbuf, k++, db=0x20); // DB2 + chksum = chksum ^ db; + + bufsetint8 (outbuf, k++, chksum); // XOR-Byte + // debug_mem(outbuf, k); + udp->Send(source, outbuf, k); + } + + // LAN_X_SET_TURNOUT + else if (xdata.xheader == 0x53) { + int addr = (xdata.db[0] << 8) + xdata.db[1]; + int cmd = xdata.db[2]; + int cmd_q = cmd & 0x20; + int cmd_a = cmd & 0x08; + int cmd_p = cmd & 0x01; + pos += 4; + printf ("LAN_X_SETTURNOUT addr: %d cmd: %x (q:%d a:%d p:%d)\n", addr, cmd, cmd_q, cmd_a, cmd_p); + xlan_turnout (addr, (cmd_a != 0)); + } + + else { + printf ("LAN_X command not understood: %x\n", xdata.xheader); + } + } + } + } + + // LAN_RMBUS_GETDATA --> send LAN_RMBUS_DATACHANGED + else if (pktheader == 0x0081 && pktlen == 5) { + unsigned char rmbus_grpidx = bufgetint8(buffer, 4); + printf ("LAN_RMBUS_GETDATA\n"); + Send_LAN_RMBUS_DATACHANGED(udp, rmbus_grpidx); + } + + else { + printf ("unknown command: "); +// debug_mem (buffer, len); + } + + return true; +} + + +void Z21Client::Send_LAN_RMBUS_DATACHANGED (UDPConnection *udp, unsigned char grpidx) { + int k, i; + + printf ("Send LAN_RMBUS_DATACHANGED\n"); + if (grpidx >= RBUS_GROUPS) { + printf (" giving group (%d) is not supported.\n", grpidx); + return; + } + bufsetint16 (outbuf, 0, htole16(15)); // LEN + bufsetint16 (outbuf, 2, htole16(0x80)); // X_CMD + + k = 4; + bufsetint8 (outbuf, k++, grpidx); // Gruppenindex + + for (i = 0; i < RBUS_BYTESPERGROUP; i++) + bufsetint8 (outbuf, k++, rbus[grpidx*RBUS_BYTESPERGROUP + i].status); + + udp->Send(source, outbuf, k); +} + +/************************************************************************/ + +Z21Server::Z21Server () { +// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); +}; + +Z21Server::~Z21Server () { +// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); +}; + +void Z21Server::Start() { +// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + udp.Listen(DEFAULT_Z21PORT); +}; + + +int Z21Server::Loop() { + string source; + size_t len; + int newclient = 1; + list::iterator iter; + int i, grp; + + if (udp.isListen()) { + // + // read new data from UDP + len = udp.ReadTimeout(&source, buffer, NET_BUFFERSIZE, 25); // timeout 25ms + if (len > 0) { + // + // check known connection + newclient = 1; + iter = clients.begin(); + while (iter != clients.end()) { + if ((*iter)->isSource(source)) { + newclient = 0; + if (!((*iter)->LoopData(&udp, buffer, len))) { + printf ("remove client: '%s' count:%ld\n", source.c_str(), clients.size()); + iter = clients.erase(iter); + } + break; + } + iter++; + } + + // + // new connection + if (newclient && iter == clients.end()) { + Z21Client *client; + client = new Z21Client(); + client->setSource(source); + if (client->LoopData(&udp, buffer, len)) { + clients.push_back(client); + printf ("add client: '%s' count:%ld\n", source.c_str(), clients.size()); + } + } + } + + // + // broadcast changed values + for (grp = 0; grp < RBUS_GROUPS; grp++) { + for (i = 0; i < RBUS_BYTESPERGROUP; i++) + if (rbus[grp*RBUS_BYTESPERGROUP+i].status != rbus[grp*RBUS_BYTESPERGROUP+i].last) break; + if (i != RBUS_BYTESPERGROUP) { + // + // send broadcast to all clients + for (iter = clients.begin(); iter != clients.end(); iter++) + (*iter)->Send_LAN_RMBUS_DATACHANGED(&udp, grp); + } + } + } + + return clients.size(); +}; + +/************************************************************************/ + +uint8_t bufgetint8 (char *buf, int pos) { + int8_t i; + memcpy (&i, buf+pos, 1); + return i; +}; + +uint16_t bufgetint16 (char *buf, int pos) { + int16_t i; + memcpy (&i, buf+pos, 2); + return i; +}; + +uint32_t bufgetint32 (char *buf, int pos) { + int32_t i; + memcpy (&i, buf+pos, 4); + return i; +}; + +void bufsetint8 (char *buf, int pos, uint8_t i) { + memcpy (buf+pos, &i, 1); +}; + +void bufsetint16 (char *buf, int pos, uint16_t i) { + memcpy (buf+pos, &i, 2); +}; + +void bufsetint32 (char *buf, int pos, uint32_t i) { + memcpy (buf+pos, &i, 4); +}; + diff --git a/z21emu/z21prot.h b/z21emu/z21prot.h new file mode 100644 index 0000000..5dd94bd --- /dev/null +++ b/z21emu/z21prot.h @@ -0,0 +1,58 @@ +/* + * z21prot.h + * + * Created on: 15.12.2017 + * Author: steffen + */ + +#ifndef Z21PROT_H_ +#define Z21PROT_H_ + +#include +#include "udp.h" + +#define Z21_X_LEN 16 + +struct { + unsigned char xheader; + unsigned char db[Z21_X_LEN]; +} typedef Z21_lan_x_data; + +// +// work around for memory alignment on some CPUs/PocketPCs +uint8_t bufgetint8 (char *buf, int pos); +uint16_t bufgetint16 (char *buf, int pos); +uint32_t bufgetint32 (char *buf, int pos); +void bufsetint8 (char *buf, int pos, uint8_t i); +void bufsetint16 (char *buf, int pos, uint16_t i); +void bufsetint32 (char *buf, int pos, uint32_t i); + +class Z21Client { +private: + char outbuf[NET_BUFFERSIZE]; + string source; +public: + Z21Client(); + ~Z21Client(); + + void setSource(string newsrc) { source = newsrc; }; + string getSource() { return source; }; + bool isSource(string srcaddr) { return (source.compare(srcaddr) == 0); }; + bool LoopData (UDPConnection *udp, char *buffer, size_t len); + void Send_LAN_RMBUS_DATACHANGED (UDPConnection *udp, unsigned char grpidx); +}; + +class Z21Server{ +private: + list clients; + UDPConnection udp; + char buffer[NET_BUFFERSIZE]; +public: + Z21Server (); + ~Z21Server (); + + int Loop(); // returns number of connections + void Start(); +}; + +#endif /* Z21PROT_H_ */