Compare commits

..

45 Commits

Author SHA1 Message Date
Steffen Pohle 519b59e215 do profile data
9 months ago
Steffen Pohle d6c4907557 Lock and Unlock fixed: in case of an error the train is stopped and put on manual mode.
2 years ago
Steffen Pohle b370dbf930 AutoCheckWaySingleStep: stops preparing way at next block
2 years ago
Steffen Pohle 63e9778929 AutoCheckWaySingleStep and some uninitialized memory fixed.
2 years ago
Steffen Pohle 4a4735ab33 BlockEnterNext is not working correctly
2 years ago
Steffen Pohle 48922c20ea fixed: FindWay will check for loops between two blocks
2 years ago
Steffen Pohle b24a76aa72 split block are working. fixed way finding issues.
2 years ago
Steffen Pohle 4990065ada forgot to delete destination if assign and dest are equal
2 years ago
Steffen Pohle f0bf67f740 sensors are working again, split blocks should finally work
2 years ago
Steffen Pohle 2df7d6e032 LockWay and UnLockWay is working with split blocks now.
2 years ago
Steffen Pohle 0845f417d2 working on short trains and split blocks
2 years ago
Steffen Pohle 1018ec5990 working on split blocks and short trains..
2 years ago
Steffen Pohle 54e3342a5e working on split blocks
2 years ago
Steffen Pohle d4efc193c7 another work on the split blocks. long trains wont go into split blocks. Some final checks are still needed
2 years ago
Steffen Pohle 0c73a38dc8 litte detail display on track information is working.
2 years ago
Steffen Pohle db27a5a02a prepare shortstop and split tracks
3 years ago
Steffen Pohle 67c73836f8 fixed AUTO->MAN stop mode is working on trains.
3 years ago
Steffen Pohle 0a446a26df fixing stuff. The child class did not work as expexted.
4 years ago
Steffen Pohle 9b1eb38f29 InterfaceZ21 is now a subclass of Interface
4 years ago
Steffen Pohle 206871b2c0 InterfaceZ21 is now a subclass of Interface
4 years ago
Steffen Pohle 8ce86bbbee adding to move an area of the track
4 years ago
Steffen Pohle 27d89c3ffa description
4 years ago
Steffen Pohle 115615e853 adding debugging messages
4 years ago
Steffen Pohle a82dc79ea8 PINC is not used, missed to setup PINB - should work now
4 years ago
Steffen Pohle 5e1142e4e2 adding support for buttons, fixed serval issues with the display. Fixed all compile warnings.
4 years ago
Steffen Pohle 8d44d32e6b adding sensor context menu for simulation purpose.
4 years ago
Steffen Pohle 4ae0036c4f Adding at last one Screenshot
4 years ago
Steffen Pohle 0bdaeaa5e4 adding scheduled routes, and fixed some update issues with locomotives
4 years ago
Steffen Pohle 0b0339b924 working on auto and manual mode
4 years ago
Steffen Pohle 47ebbf3ada mark blocks as onlyCARGO or onlyPESSANGER is working
4 years ago
Steffen Pohle 0e75d05c14 debug messaged will be print to the console.
4 years ago
Steffen Pohle 1c5c98752d contectmenu is not displayed out of the screen
4 years ago
Steffen Pohle 936fb74dcd disable debug...
4 years ago
Steffen Pohle abafaec083 adding new model of sensorbox
4 years ago
Steffen Pohle ad14dc0428 ignore more files
4 years ago
Steffen Pohle c16145bedb add Makefile in root tree. Needed for some IDEs
4 years ago
Steffen Pohle 23253e6840 fixed, compare pointer with integer
4 years ago
Steffen Pohle 574552eae8 Merge branch 'master' of steffen.gulpe.de:steffen/Modelbahn
4 years ago
Steffen Pohle 5f41ef2ec5 Delete 'documentation.odt'
4 years ago
Steffen Pohle 1fa6c2f02f Update 'Readme.md'
4 years ago
Steffen Pohle 4ae0eb60e8 Delete 'Readme.txt'
4 years ago
Steffen Pohle e13f9dec8b delete
4 years ago
Steffen Pohle deadf57961 Add 'Readme.md'
4 years ago
Steffen Pohle 30eff69499 little changes
4 years ago
Steffen Pohle a0b390886f z21emu - and atmega sources
4 years ago

24
.gitignore vendored

@ -0,0 +1,24 @@
.cproject
.project
.settings
gmon.out
*/.depend
server/gmon.out
server/modelbahn-cgi
server/modelbahn-server
server/test-json
z21emu/gmon.out
z21emu/config.h
z21emu/z21emu
*~
*.oo
*.o
*.elf
*.bin
track.json
track.json.backup.*
Modelbahn.anjuta
*.track.json
Backup/
.anjuta_sym_db.db
.anjuta/

@ -1,3 +1,51 @@
2024-01-04:
- fixed: AutoCheckWaySingleStep: stops preparing way at next block
2024-01-16:
- fixed: not all pthread_mutexes has been initialization.
2023-12-30:
- fixed: FindWay will check for loops between two blocks
2023-12-27:
- split blocks do work.
- fixed issues with the way finding routine
2023-05-01:
- another work on the split blocks. long trains wont go into split blocks. Some final
checks are still needed to implement.
2023-04-02:
- fixed: track infomation is fixed.
- removed unneded debug file
2023-03-13:
- prepared split and short tracks. - needs to be tested completly.
2022-04-17:
- added "-simulation" parmeter for debugging purpose.
needed to simulate turnout manipulation
- fixed: locomotive AUTO->MAN mode is working if searching for a new way.
2022-02-13:
- Interfaces are now virtual classes.
2021-12-19:
- adding sensor context menu for sensor simulation
2021-12-10:
- adding support for scheduling ways
- fixed: webinterface, update on loco will now change its detail display
2021-12-02:
- mark blocks as onlyCARGO or onlyPESSANGER, random-automode looks nice now.
- webinterface: debug messages will be print to the console.
- webinterface: contextmenu will be displayed inside the visible area
2021-11-06:
- fixed: compiling error on compare with pointer
2021-03-09:
- changed: passenger trains (no cargo flag set) will always stop at stations.
- added station flag to blocks
@ -12,7 +60,7 @@
2021-01-31:
- automtic mode is improving, manual setting of destination
autoatic routing and moving the train to the destination.
automatic routing and moving the train to the destination.
- locked turnouts can not anymore been set.
- assign loco and set destination is working now.

@ -0,0 +1,9 @@
TOPTARGETS := all clean
SUBDIRS := server
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(SUBDIRS)

@ -0,0 +1,34 @@
# Modelbahn
## Requirements:
Webserver with CGI enabled
## Installation:
+ copy the webinterface files to your location of the webserver
+ compile the server
+ copy the modelbahn-cgi binary to the cgi folder of the webserver
+ run the modelbahn-server application.
![Screenshot](https://steffen.gulpe.de/progs/modelbahn.png)
## Z21EMU and ATmega Sensors
Per default all devices get the same I2C defive address. As soon as the device is connected you should set up a new address for them. The following commands will set the device [0x2f] to address 0x31 and save this setting in the EPROM.
i2cset -y 1 0x2f 0x22 0x31
i2cset -y 1 0x2f 0x21 0x02
The following registers are used:
0x00 .. 0x08 INPUT and OUTPUT registers dependung on device
0x20 VERSION of the device
0x21 Command Register
0 no command
1 EEPROM read
2 EEPORM write
0x22 I2C Address
0x23 Input Off Delay

@ -1,11 +0,0 @@
Requirements:
- Webserver with CGI enabled
Installation:
- copy the webinterface files to your location of the webserver
- compile the server
- copy the modelbahn-cgi binary to the cgi folder of the webserver
- run the modelbahn-server application.

Binary file not shown.

@ -9,16 +9,16 @@ ETCPREFIX=/etc
DISTNAME=modelbahn
CXX=g++
CXXFLAGS= -ggdb -fPIC -Wno-write-strings -g -ggdb -std=c++11 -pg
CXXFLAGS= -Wall -ggdb -fPIC -Wno-write-strings -g -ggdb -std=c++11 -pg
LDFLAGS= -lm -lc -lpthread -L/usr/local/lib -g -ggdb -pg
LDFLAGS_CGI= -lm -lc -lpthread -L/usr/local/lib -g -ggdb -pg
LDFLAGS_CGI= -lm -lc -lpthread -L/usr/local/lib -g -ggdb
DEPENDFILE=.depend
TARGET=modelbahn-server
SERVEROBJ=server.o network.o session.o server-loadsave.o debug.o \
json.o main.o sensor.o turnout.o railway.o interface.o locomotive.o \
block.o interface-z21.o
json.o main.o sensor.o turnout.o railway.o interfaces.o locomotive.o \
block.o interface.o interface-z21.o
CURDIR=`pwd`

@ -1,12 +1,19 @@
#include <string>
#include "modelbahn.h"
#include "block.h"
#include <list>
#include <string>
#include <string.h>
using namespace std;
Blocks::Blocks () {
pthread_mutex_init(&mtx, NULL);
changed = 0;
blocks = (Block*) malloc(sizeof(Block)*SENSORS_MAX);
memset (blocks, 0x0, sizeof(Block)*SENSORS_MAX);
max = BLOCKS_MAX;
last_blockidx = -1;
};
@ -35,16 +42,24 @@ int Blocks::UnLock() {
JSONParse Blocks::_GetJSON(Block *bl) {
JSONParse json;
JSONElement je;
string s = "";
json.Clear();
s = bl->name; json.AddObject("name", s);
json.AddObject("name", bl->name);
json.AddObject("flags", bl->flags);
json.AddObject("lockedby", bl->lockedby);
json.AddObject("sensor_pos_1", bl->s_pos_1);
json.AddObject("sensor_center", bl->s_center);
json.AddObject("sensor_neg_1", bl->s_neg_1);
json.AddObject("sensor_enter_0", bl->s_enter[0]);
json.AddObject("sensor_slow_0", bl->s_slow[0]);
json.AddObject("sensor_stop_0", bl->s_stop[0]);
json.AddObject("sensor_shortstop_0", bl->s_shortstop[0]);
json.AddObject("sensor_enter_1", bl->s_enter[1]);
json.AddObject("sensor_slow_1", bl->s_slow[1]);
json.AddObject("sensor_stop_1", bl->s_stop[1]);
json.AddObject("sensor_shortstop_1", bl->s_shortstop[1]);
json.AddObject("secondblock", bl->secondblock);
return json;
};
@ -97,23 +112,50 @@ Block Blocks::GetBlockFromJSON(JSONParse *j) {
string s;
bl.name[0] = 0;
bl.secondblock[0] = 0;
bl.flags = 0;
bl.lockedby[0] = 0;
j->GetValue("name", &s);
strncpy (bl.name, s.c_str(), REFERENCENAME_LEN);
j->GetValueInt("flags", &bl.flags);
// j->GetValue("lockedby", &s);
// strncpy (bl.lockedby, s.c_str(), REFERENCENAME_LEN);
s = ""; j->GetValue("sensor_pos_1", &s);
strncpy (bl.s_pos_1, s.c_str(), REFERENCENAME_LEN);
s = ""; j->GetValue("sensor_center", &s);
strncpy (bl.s_center, s.c_str(), REFERENCENAME_LEN);
s = ""; j->GetValue("sensor_neg_1", &s);
strncpy (bl.s_neg_1, s.c_str(), REFERENCENAME_LEN);
printf ("%s:%d block: %s flags: %d\n", __FILE__, __LINE__, bl.name, bl.flags);
//
// old version input data
//
s = "";
if (j->GetValue("sensor_pos_1", &s)) {
strncpy (bl.s_enter[0], s.c_str(), REFERENCENAME_LEN);
strncpy (bl.s_stop[1], s.c_str(), REFERENCENAME_LEN);
}
s = "";
if (j->GetValue("sensor_center", &s)) {
strncpy (bl.s_shortstop[0], s.c_str(), REFERENCENAME_LEN);
strncpy (bl.s_shortstop[1], s.c_str(), REFERENCENAME_LEN);
}
s = "";
if (j->GetValue("sensor_neg_1", &s)) {
strncpy (bl.s_enter[1], s.c_str(), REFERENCENAME_LEN);
strncpy (bl.s_stop[0], s.c_str(), REFERENCENAME_LEN);
}
//
// new version
//
s = ""; if (j->GetValue("sensor_enter_0", &s)) strncpy (bl.s_enter[0], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_enter_1", &s)) strncpy (bl.s_enter[1], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_slow_0", &s)) strncpy (bl.s_slow[0], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_slow_1", &s)) strncpy (bl.s_slow[1], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_stop_0", &s)) strncpy (bl.s_stop[0], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_stop_1", &s)) strncpy (bl.s_stop[1], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_shortstop_0", &s)) strncpy (bl.s_shortstop[0], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("sensor_shortstop_1", &s)) strncpy (bl.s_shortstop[1], s.c_str(), REFERENCENAME_LEN);
s = ""; if (j->GetValue("secondblock", &s)) strncpy (bl.secondblock, s.c_str(), REFERENCENAME_LEN);
printf ("%s:%d block: %s flags: %d\n", __FILE__, __LINE__, bl.name, bl.flags);
return bl;
};
@ -211,7 +253,7 @@ int Blocks::SetLockedby (string blname, string lockedby, int lock_onoff) {
Block *bl = NULL;
JSONParse jp;
int res = -1;
int x, y;
int x, y, cnt;
debug (0, "Blocks::SetLockedby block:'%s' locked for '%s' locked:%d", blname.c_str(), lockedby.c_str(), lock_onoff);
@ -224,7 +266,8 @@ int Blocks::SetLockedby (string blname, string lockedby, int lock_onoff) {
if(network) network->ChangeListPushToAll(jp.ToString());
x = -1; y = -1;
while (server->railways.FindReference(&x, &y, blname)) {
cnt = 0;
while (server->railways.FindReference(&x, &y, blname, (cnt++))) {
server->railways.SetLockedby(x, y, lockedby, lock_onoff);
}
@ -260,6 +303,22 @@ string Blocks::GetLockedby (string blname) {
};
string Blocks::GetSecondBlock(string block) {
Block *bl = NULL;
string sb;
Lock();
if ((bl = FindBlock(block)) != NULL) {
sb = bl->secondblock;
UnLock();
return sb;
}
UnLock();
return "";
}
Block* Blocks::FindBlock(string name) {
Block *bl = NULL;
@ -324,43 +383,125 @@ int Blocks::GetFlags (string blname) {
};
string Blocks::GetSensorMinus (string blname) {
string res = "";
/*
* return a pointer to the blockdata in case of split blocks also return the second block
*/
int Blocks::GetBlocksPtr (string blname, Block **b1, Block **b2) {
int i;
(*b1) = NULL;
(*b2) = NULL;
for (i = 0; i < max; i++) if (blname.compare(blocks[i].name) == 0) {
(*b1) = &blocks[i];
}
if ((*b1) == NULL) {
debug (0, "Blocks::%s Could not find block: %s", __FUNCTION__, blname.c_str());
return 0;
}
if ((*b1)->flags & BLOCK_F_SPLIT) {
for (i = 0; i < max; i++) if (strcmp ((*b1)->secondblock, blocks[i].name) == 0) {
(*b2) = &blocks[i];
}
if ((*b2) == NULL) {
debug (0, "Blocks::%s Could not find second block: %s", __FUNCTION__, (*b1)->secondblock);
return 0;
}
}
return 1;
}
string Blocks::GetSensorEnter (int direction, string blname, int locoflags) {
string res = "";
JSONParse jp;
Block *b1 = NULL;
Block *b2 = NULL;
Lock();
for (i = 0; i < max; i++) if (blname.compare(blocks[i].name) == 0) {
res = blocks[i].s_neg_1;
if (!GetBlocksPtr(blname, &b1, &b2)) return res;
if (!(locoflags & LOCO_F_SHORTTRAIN) && (b1->flags & BLOCK_F_SPLIT)) {
if (direction == 0) {
if (b1->flags & BLOCK_F_SPLITPOS) res = b1->s_enter[direction];
else res = b2->s_enter[direction];
}
else {
if (b1->flags & BLOCK_F_SPLITPOS) res = b2->s_enter[direction];
else res = b1->s_enter[direction];
}
}
if (res.length() == 0) {
res = b1->s_enter[direction];
}
UnLock();
return res;
};
string Blocks::GetSensorCenter (string blname) {
string Blocks::GetSensorSlow (int direction, string blname, int locoflags) {
string res = "";
int i;
JSONParse jp;
Block *b1 = NULL;
Block *b2 = NULL;
Lock();
for (i = 0; i < max; i++) if (blname.compare(blocks[i].name) == 0) {
res = blocks[i].s_center;
if (!GetBlocksPtr(blname, &b1, &b2)) return res;
if (!(locoflags & LOCO_F_SHORTTRAIN) && (b1->flags & BLOCK_F_SPLIT)) {
if (direction == 0) {
if (b1->flags & BLOCK_F_SPLITPOS) res = b2->s_slow[direction];
else res = b1->s_slow[direction];
}
else {
if (b1->flags & BLOCK_F_SPLITPOS) res = b1->s_slow[direction];
else res = b2->s_slow[direction];
}
}
if (res.length() == 0) {
res = b1->s_slow[direction];
}
if (res.length() == 0) {
res = b1->s_enter[direction];
}
UnLock();
return res;
};
string Blocks::GetSensorPlus (string blname) {
string Blocks::GetSensorStop (int direction, string blname, int locoflags) {
string res = "";
int i;
JSONParse jp;
Block *b1 = NULL;
Block *b2 = NULL;
Lock();
for (i = 0; i < max; i++) if (blname.compare(blocks[i].name) == 0) {
res = blocks[i].s_pos_1;
if (!GetBlocksPtr(blname, &b1, &b2)) return res;
if ((locoflags & LOCO_F_SHORTTRAIN) && b1->s_shortstop[direction][0] != 0)
res = b1->s_shortstop[direction];
if (!(locoflags & LOCO_F_SHORTTRAIN) && (b1->flags & BLOCK_F_SPLIT)) {
if (direction == 0) {
if (b1->flags & BLOCK_F_SPLITPOS) res = b2->s_stop[direction];
else res = b1->s_stop[direction];
}
else {
if (b1->flags & BLOCK_F_SPLITPOS) res = b1->s_stop[direction];
else res = b2->s_stop[direction];
}
}
if (res.length() == 0) {
res = b1->s_stop[direction];
}
UnLock();
return res;
};

@ -2,22 +2,55 @@
#ifndef _BLOCK_H_
#define _BLOCK_H_
#include <list>
#include <string>
#include <string.h>
using namespace std;
#include "modelbahn.h"
#include "server.h"
#define BLOCK_F_OFF 0x0001
#define BLOCK_F_SPLIT 0x0002 // is this a split block? only works for short
#define BLOCK_F_SPLITPOS 0x0004 // is this a split block? only works for short
#define BLOCK_F_SHORT 0x0010
#define BLOCK_F_LONG 0x0020
#define BLOCK_F_ENDSTATION 0x0040
#define BLOCK_F_STATION 0x0080
#define BLOCK_F_SPEEDLIMIT 0x0100
#define BLOCK_F_ONLYCARGO 0x0200
#define BLOCK_F_ONLYPASSENGER 0x0400
/*
* FIXME: long trains on split blocks
* FIXME: sample how to set up positive entry side
*
* Dirction Pos: from Left to Right Neg: from Right to Left
* Dirction Pos: from Top to Bottom Neg: from Bottom to Top
*
* pos SPLIT BLOCK neg SPLIT BLOCK
* F_SPLIT | F_SPLITPOS F_SPLIT
* >----o-------------o------o-------------o---> entry direction
*
* ^ ^ ^
* | | |
* s_enter[0] s_shortstop[0] | positive_block
* s_stop[0] negative block
*/
struct s_Block {
char name[REFERENCENAME_LEN];
char s_pos_1[REFERENCENAME_LEN]; //
char s_center[REFERENCENAME_LEN];
char s_neg_1[REFERENCENAME_LEN];
// default sensors [0].. positive side [1] negative side
char s_enter[2][REFERENCENAME_LEN];
char s_slow[2][REFERENCENAME_LEN];
char s_stop[2][REFERENCENAME_LEN];
char s_shortstop[2][REFERENCENAME_LEN];
char secondblock[REFERENCENAME_LEN]; // short two blocks segment.
int flags;
char lockedby[REFERENCENAME_LEN]; // element locked by locreference (only set by server, not by JSON/Webinterface)
@ -39,6 +72,7 @@ class Blocks {
int last_blockidx; // to speed up things
Block* FindBlock(string name);
int GetBlocksPtr(string blname, Block **b1, Block **b2);
public:
Blocks();
~Blocks();
@ -56,10 +90,11 @@ class Blocks {
int SetOff(string blname);
int IsOff(string blname);
string GetSensorMinus (string blname);
string GetSensorCenter (string blname);
string GetSensorPlus (string blname);
string GetSensorEnter (int direction, string blname, int locoflags);
string GetSensorSlow (int direction, string blname, int locoflags);
string GetSensorStop (int direction, string blname, int locoflags);
int GetFlags (string blname);
string GetSecondBlock(string block);
int SetLockedby (string blname, string lockedby, int lock_onoff);
string GetLockedby (string blname);

@ -2,32 +2,49 @@
// #define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/time.h>
#include "modelbahn.h"
#define DEBUG_FILE "/tmp/modelbahn-server.log"
#define LEN_TEXT 256
int _debuglevel = 0xff;
pid_t gettid();
void debug (int type, char *fmt,...) {
va_list args;
char texttime[LEN_TEXT];
char text1[DEBUG_TEXT1LEN];
char text2[DEBUG_TEXT2LEN];
pid_t pid = gettid();
int tms;
struct timeval tv;
struct tm tmp;
struct tm *tmptr = NULL;
va_start (args, fmt);
vsnprintf (text1, (DEBUG_TEXT1LEN-1), fmt, args);
va_end (args);
texttime[0] = 0;
text1[DEBUG_TEXT1LEN-1] = 0;
text2[DEBUG_TEXT2LEN-1] = 0;
if (type > 0) snprintf (text2, DEBUG_TEXT2LEN-1, "(%d)%d: %s", pid, type, text1);
else snprintf (text2, DEBUG_TEXT2LEN-1, "(%d) %s", pid, text1);
gettimeofday (&tv, NULL);
tmptr = localtime_r(&tv.tv_sec, &tmp);
if (tmptr != NULL)
strftime(texttime, LEN_TEXT, "%H:%M:%S", &tmp);
if (type > 0) snprintf (text2, DEBUG_TEXT2LEN-1, "(%d, %s.%03d) %d : %s", pid, texttime, tv.tv_usec/1000, type, text1);
else snprintf (text2, DEBUG_TEXT2LEN-1, "(%d, %s.%03d) : %s", pid, texttime, tv.tv_usec/1000, text1);
if (type == 0 || (type & _debuglevel) != 0) {
FILE *f;

@ -33,11 +33,14 @@ static unsigned char RX_RMBUS_DATACHANGED[] { 0x0F, 0x00, 0x80, 0x00 };
#define Z21_IDX_SETTURNOUT_CHK 8
InterfaceZ21::InterfaceZ21 () {
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21:%s", __FUNCTION__);
status_connected = false;
status_poweron = false;
status_programmingmode = false;
status_shortcircuit = false;
status_emergencystop = false;
timer_start(&turnouttimeout);
send_logon = false;
@ -45,7 +48,6 @@ InterfaceZ21::InterfaceZ21 () {
rmsensorinit = 0;
serial = "";
hostname = "";
timeout = time(NULL);
rmgetdatatimeout = time(NULL) - INTF_Z21_RMGETDATA_TIMEOUT;
};
@ -55,11 +57,11 @@ InterfaceZ21::~InterfaceZ21() {
};
void InterfaceZ21::Connect (string destination) {
debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Connect to: %s", __FILE__, __LINE__, destination.c_str());
void InterfaceZ21::Connect () {
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21: Connect %s to: %s", name, host);
if (status_connected) Disconnect();
hostname = destination;
if (udp.Listen(0) == 0) {
debug (DEBUG_ERROR | DEBUG_IFACE, "%s:%d Error could not bind UDP socket (%s)",
@ -97,12 +99,18 @@ void InterfaceZ21::Disconnect() {
//
// check if we are connected and for timeouts.
// read and go through incoming data
int InterfaceZ21::Loop(string interfacename) {
int InterfaceZ21::Loop() {
time_t curtime = time(NULL);
string source;
int inlen;
int i;
int update = false;
// debug (DEBUG_INFO | DEBUG_IFACE, "* InterfaceZ21 (%s) Loop", name);
flags &= ~(INTF_F_CONNECTED | INTF_F_POWER | INTF_F_STOP | INTF_F_SHORT_CIRCUIT | INTF_F_PROGRAMMING);
if (needs_update) {
needs_update = 0;
}
if (status_connected) {
//
@ -110,14 +118,14 @@ int InterfaceZ21::Loop(string interfacename) {
if ((timeout + 2 * INTF_Z21_TIMEOUT) < curtime) {
debug (DEBUG_ERROR | DEBUG_IFACE, "%s:%d connection timed out (%d)", __FILE__, __LINE__, curtime-(timeout + 2 * INTF_Z21_TIMEOUT));
Disconnect();
update = true;
needs_update = true;
}
else if (send_logon == false && (timeout + INTF_Z21_TIMEOUT) < curtime) {
send_logon = true;
send_GET_SERIAL_NUMBER();
send_SET_BROADCASTFLAGS();
timeout = time(NULL);
update = true;
needs_update = true;
}
//
@ -136,7 +144,7 @@ int InterfaceZ21::Loop(string interfacename) {
if ((inlen = udp.ReadTimeout(&source, inbuffer, INTF_Z21_INBUFFER, 10)) > 0) {
//
// got some data
debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d [%s] got some data.", __FILE__, __LINE__, name);
//
// check for LAN_SYSTEMSTATE_DATACHANGED
if (memcmp (inbuffer, RX_GET_SERIAL_NUMBER, sizeof(RX_GET_SERIAL_NUMBER)) == 0) {
@ -149,13 +157,13 @@ int InterfaceZ21::Loop(string interfacename) {
if (memcmp (inbuffer, RX_X_GET_TURNOUT_INFO, sizeof(RX_X_GET_TURNOUT_INFO)) == 0) {
// got turnout information
int addr = 0;
addr = ((unsigned char)inbuffer[Z21_IDX_SETTURNOUT_ADRH] << 8) + (unsigned char)inbuffer[Z21_IDX_SETTURNOUT_ADRL];
debug (0, "%s:%d Interface-Z21: TurnoutInformation Addr:%d", __FILE__, __LINE__, addr);
if (inbuffer[Z21_IDX_SETTURNOUT_MODE] == 2)
server->TurnoutAddrMode(interfacename, addr, 1);
server->TurnoutAddrMode(name, addr, 1);
else if (inbuffer[Z21_IDX_SETTURNOUT_MODE] == 1)
server->TurnoutAddrMode(interfacename, addr, 0);
server->TurnoutAddrMode(name, addr, 0);
}
@ -166,20 +174,14 @@ int InterfaceZ21::Loop(string interfacename) {
int cs = (unsigned char) inbuffer[16];
int csex = (unsigned char) inbuffer[17];
bool old_poweron = status_poweron;
bool old_shortcircuit = status_shortcircuit;
bool old_programmingmode = status_programmingmode;
bool old_connected = status_connected;
bool old_emergencystop = status_emergencystop;
status_emergencystop = (cs & INTF_Z21_CS_EmergencyStop);
status_poweron = (cs & INTF_Z21_CS_TrackVoltageOff);
status_shortcircuit = (cs & INTF_Z21_CS_ShortCircuit);
status_programmingmode = (cs & INTF_Z21_CS_ProgModeActive);
debug (0, "%s:%d cs:%d csex:%d", __FILE__, __LINE__, cs, csex);
debug (0, "%s:%d Name:%s cs:%d csex:%d", __FILE__, __LINE__, name, cs, csex);
update = true;
needs_update = true;
//if ( old_poweron != status_poweron ||
// old_shortcircuit != status_shortcircuit ||
// old_programmingmode != status_programmingmode ||
@ -216,7 +218,7 @@ int InterfaceZ21::Loop(string interfacename) {
debug (0, "%s:%d Loc:%d Speed:%d", __FILE__, __LINE__, loconet_map[inloc].addr, inspeed);
if (loconet_map[inloc].addr > 0) {
int speed = inspeed;
server->LocomotiveAddrSpeed(interfacename, loconet_map[inloc].addr, speed);
server->LocomotiveAddrSpeed(name, loconet_map[inloc].addr, speed);
}
}
loconet_last.addr = 0;
@ -235,7 +237,7 @@ int InterfaceZ21::Loop(string interfacename) {
debug (0, "%s:%d Loc:%d Function:%d", __FILE__, __LINE__, loconet_map[inloc].addr, infunc);
if (loconet_map[inloc].addr > 0) {
server->LocomotiveAddrFunction(interfacename, loconet_map[inloc].addr, infunc);
server->LocomotiveAddrFunction(name, loconet_map[inloc].addr, infunc);
}
loconet_last.addr = 0;
@ -246,9 +248,9 @@ int InterfaceZ21::Loop(string interfacename) {
// check for LAM_RMBUS_DATACHANGED
else if (memcmp (inbuffer, RX_RMBUS_DATACHANGED, sizeof(RX_RMBUS_DATACHANGED)) == 0) {
int group = (unsigned char)inbuffer[4];
int idx, bit;
int idx;
printf ("LAN_RMBUS_DATA_CHANGE[%s] ", interfacename.c_str());
printf ("LAN_RMBUS_DATA_CHANGE[%s] ", name);
for (idx = 0; idx < INTF_Z21_RMSENSOR_BYTES * INTF_Z21_RMSENSOR_GROUPS; idx++) {
printf ("%x ", (unsigned char) inbuffer[4+idx]);
}
@ -265,9 +267,9 @@ int InterfaceZ21::Loop(string interfacename) {
for (idx = 0; idx < INTF_Z21_RMSENSOR_GROUPS*INTF_Z21_RMSENSOR_BYTES; idx++) {
if (rmsold[idx]^rmsensors[idx]) {
for (i = 0; i < 8; i++) if (rmsensorinit || (rmsold[idx] & 1 << i) != (rmsensors[idx] & 1 << i)) {
debug (0, "Sendor Data Changed: %s[%d]", interfacename.c_str(), idx*8+i);
if (rmsensors[idx] & 1 << i) server->SensorAddrChange(interfacename, idx*8+i, 1);
else server->SensorAddrChange(interfacename, idx*8+i, 0);
debug (0, "Sendor Data Changed: %s[%d]", name, idx*8+i);
if (rmsensors[idx] & 1 << i) server->SensorAddrChange(name, idx*8+i, 1);
else server->SensorAddrChange(name, idx*8+i, 0);
}
}
}
@ -276,7 +278,7 @@ int InterfaceZ21::Loop(string interfacename) {
}
else {
printf ("InterfaceZ21(%s) Got some Data:", interfacename.c_str());
printf ("InterfaceZ21(%s) Got some Data:", name);
for (i = 0; i < inlen; i++) {
int z = (unsigned char) inbuffer[i];
printf ("%02x:", z);
@ -292,7 +294,12 @@ int InterfaceZ21::Loop(string interfacename) {
}
}
return update;
if (IsConnected()) flags |= INTF_F_CONNECTED;
if (IsPoweron()) flags |= INTF_F_POWER;
if (IsEmergencyStop()) flags |= INTF_F_STOP;
if (IsSortCircuit()) flags |= INTF_F_SHORT_CIRCUIT;
return needs_update;
};
@ -300,14 +307,14 @@ int InterfaceZ21::Loop(string interfacename) {
// send_SET_BROADCASTFLAGS();
void InterfaceZ21::send_SET_BROADCASTFLAGS() {
unsigned char buffer[] = { 0x08, 0x00, 0x50, 0x00, 0x0F, 0x01, 0x00, 0x03 };
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
//
// send_GET_SERIAL_NUMBER
void InterfaceZ21::send_GET_SERIAL_NUMBER() {
unsigned char buffer[] = { 0x04, 0x00, 0x10, 0x00 };
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
@ -317,7 +324,7 @@ void InterfaceZ21::send_RM_GETDATA(int group) {
unsigned char buffer[] = { 0x05, 0x00, 0x81, 0x00, 0x00 };
if (group < INTF_Z21_RMSENSOR_GROUPS) {
buffer[4] = (unsigned char)group;
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
}
@ -328,7 +335,7 @@ void InterfaceZ21::send_LOGOFF() {
if (status_connected == false) return;
unsigned char buffer[] = { 0x04, 0x00, 0x30, 0x00 };
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
@ -380,16 +387,16 @@ void InterfaceZ21::SetLocoSpeed(Locomotive *l, int step) {
//
// XOR Byte
for (int i = 4; i < sizeof (buffer)-1; i++)
for (int i = 4; i < (int) sizeof (buffer)-1; i++)
buffer[Z21_IDX_SETLOCO_DRIVE_CHK] = (unsigned char)buffer[Z21_IDX_SETLOCO_DRIVE_CHK] xor (unsigned char)buffer[i];
printf ("Send Data:");
for (int i = 0; i < sizeof (buffer); i++) {
for (int i = 0; i < (int)sizeof (buffer); i++) {
int z = (unsigned char) buffer[i];
printf ("%02x:", z);
}
printf ("\n");
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
loconet_last.addr = l->addr;
loconet_last.dir = l->flags & LOCO_F_REVERSE;
loconet_last.speed = l->speed;
@ -407,9 +414,19 @@ void InterfaceZ21::SetLocoFunction(Locomotive *l, int func, int value) {
//
// Set Turnout
void InterfaceZ21::SetTurnout(Turnout *t, int activate, int motoractive) {
void InterfaceZ21::SetTurnout(Turnout *t, int activate, int outputactive) {
unsigned char buffer[] = { 0x09, 0x00, 0x40, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00 };
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21 (%s) SetTurnout Addr:%d Acitve:%d Output:%d", name,
t->addr, activate, outputactive);
//
//
if (outputactive == 1 && timer_get(&turnouttimeout) < 100) {
debug (0, "%s:%d Interface need to wait between two turnout commands", __FILE__, __LINE__);
return;
}
timer_start(&turnouttimeout);
//
// setup turnout addr
buffer[Z21_IDX_SETTURNOUT_ADRL] = (unsigned char) (t->addr & 0xFF);
@ -419,20 +436,21 @@ void InterfaceZ21::SetTurnout(Turnout *t, int activate, int motoractive) {
// setup steps and selected step
buffer[Z21_IDX_SETTURNOUT_MODE] = 0x80;
if (activate) buffer[Z21_IDX_SETTURNOUT_MODE] |= 1;
if (motoractive) buffer[Z21_IDX_SETTURNOUT_MODE] |= 8;
if (outputactive) buffer[Z21_IDX_SETTURNOUT_MODE] |= 8;
//
// XOR Byte
for (int i = 4; i < sizeof (buffer)-1; i++)
for (int i = 4; i < (int) sizeof (buffer)-1; i++)
buffer[Z21_IDX_SETTURNOUT_CHK] = (unsigned char)buffer[Z21_IDX_SETTURNOUT_CHK] xor (unsigned char)buffer[i];
printf ("Send Data:");
for (int i = 0; i < sizeof (buffer); i++) {
int z = (unsigned char) buffer[i];
printf ("%02x:", z);
}
printf ("\n");
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
//
// set the output flag
if (outputactive) t->flags |= TURNOUT_F_ACTIVE;
else t->flags &= ~TURNOUT_F_ACTIVE;
gettimeofday (&t->activatetime, NULL);
};
@ -441,11 +459,11 @@ void InterfaceZ21::SetTurnout(Turnout *t, int activate, int motoractive) {
// send_X_SET_TRACK_POWER_ON(); send_X_SET_TRACK_POWER_ON();
void InterfaceZ21::PowerOnOff(int onoff) {
if (status_connected == false) return;
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21::PowerOnOff onoff:%d", onoff);
if (onoff) {
udp.Write(hostname, (char*)TX_X_SET_TRACK_POWER_ON, sizeof (TX_X_SET_TRACK_POWER_ON));
udp.Write(host, (char*)TX_X_SET_TRACK_POWER_ON, sizeof (TX_X_SET_TRACK_POWER_ON));
}
else {
udp.Write(hostname, (char*)TX_X_SET_TRACK_POWER_OFF, sizeof (TX_X_SET_TRACK_POWER_OFF));
udp.Write(host, (char*)TX_X_SET_TRACK_POWER_OFF, sizeof (TX_X_SET_TRACK_POWER_OFF));
}
};

@ -28,9 +28,8 @@ struct s_loconet_map{
int maxspeed;
};
class InterfaceZ21 {
class InterfaceZ21: public Interface {
private:
string hostname;
string serial;
char inbuffer[INTF_Z21_INBUFFER];
struct s_loconet_map loconet_map[INTF_Z21_LOCONET_MAXADDR];
@ -39,6 +38,7 @@ class InterfaceZ21 {
UDP udp;
time_t timeout;
time_t rmgetdatatimeout;
struct timeval turnouttimeout;
bool send_logon;
bool status_poweron;
@ -61,7 +61,7 @@ class InterfaceZ21 {
InterfaceZ21();
~InterfaceZ21();
void Connect(string destination);
void Connect();
void Disconnect();
bool IsConnected() { return status_connected; };
@ -70,11 +70,11 @@ class InterfaceZ21 {
bool IsProgramminnMode() { return status_programmingmode; };
bool IsEmergencyStop() { return status_emergencystop; };
int Loop(string interfacename);
int Loop();
void PowerOnOff(int onoff);
void SetLocoSpeed(Locomotive *l, int step);
void SetLocoFunction(Locomotive *l, int func, int value);
void SetTurnout(Turnout *t, int activate, int motoractive);
void SetTurnout(Turnout *t, int activate, int outputactive);
};

@ -10,12 +10,13 @@
// **************************************************************************
Interface::Interface() {
debug (DEBUG_INFO | DEBUG_IFACE, "Interface:%s", __FUNCTION__);
name[0] = 0;
host[0] = 0;
flags = 0;
type = INTF_T_OFF_UNKNOWN;
needs_update = true;
timer_start(&turnouttimeout);
};
Interface::~Interface() {
@ -24,56 +25,28 @@ Interface::~Interface() {
void Interface::Connect () {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) Connect to %s", name, host);
switch (type) {
case INTF_T_Z21: intz21.Connect(host); break;
default: break;
}
};
void Interface::Disconnect() {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) Disconnect", name);
switch (type) {
case INTF_T_Z21: intz21.Disconnect(); break;
default: break;
}
};
void Interface::PowerOnOff(int onoff) {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) PowerOnOff %d", name, onoff);
switch (type) {
case INTF_T_Z21: intz21.PowerOnOff(onoff); break;
default: break;
}
};
//
// Turnout
//
void Interface::SetTurnout(Turnout *t, int active, int motoractive) {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) SetTurnout Addr:%d FinalAcitve:%d Motor:%d", name,
t->addr, active, motoractive);
if (motoractive == 1 && timer_get(&turnouttimeout) < 100) {
debug (0, "* Interface need to wait between two turnout commands");
return;
}
timer_start(&turnouttimeout);
switch (type) {
case INTF_T_Z21: intz21.SetTurnout(t, active, motoractive); break;
default: break;
}
/*
* Turnout:
* this function will check if the interface has not set any output within the past 100ms. For this we
* will save the current time in the value turnouttime.
*/
void Interface::SetTurnout(Turnout *t, int active, int outputactive) {
JSONParse jp;
//
// make sure we turn the motor later off
if (motoractive) t->flags |= TURNOUT_F_ACTIVE;
else t->flags &= ~TURNOUT_F_ACTIVE;
gettimeofday (&t->activatetime, NULL);
debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Interface (%s) SetTurnout Addr:%d Acitve:%d Output:%d", __FILE__, __LINE__, name,
t->addr, active, outputactive);
};
//
@ -81,326 +54,62 @@ void Interface::SetTurnout(Turnout *t, int active, int motoractive) {
//
void Interface::SetLocoSpeed(Locomotive *l, int step) {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) SetLocoSpeed Addr:%d Speed:%d ", name, l->addr, step);
switch (type) {
case INTF_T_Z21: intz21.SetLocoSpeed(l, step); break;
default: break;
}
};
void Interface::SetLocoFunction(Locomotive *l, int func, int value) {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) SetLocoFunction Addr:%d Func:%d:%d", name, l->addr, func, value);
switch (type) {
case INTF_T_Z21: intz21.SetLocoFunction(l, func, value); break;
default: break;
}
};
//
// if update is needed return 1
//
int Interface::Loop() {
int ret = 0;
// debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) Loop", name);
flags &= ~(INTF_F_CONNECTED | INTF_F_POWER | INTF_F_STOP | INTF_F_SHORT_CIRCUIT | INTF_F_PROGRAMMING);
if (needs_update) {
ret = 1;
needs_update = 0;
}
switch (type) {
case INTF_T_Z21:
ret = intz21.Loop(name);
if (intz21.IsConnected()) flags |= INTF_F_CONNECTED;
if (intz21.IsPoweron()) flags |= INTF_F_POWER;
if (intz21.IsEmergencyStop()) flags |= INTF_F_STOP;
if (intz21.IsSortCircuit()) flags |= INTF_F_SHORT_CIRCUIT;
break;
default: break;
}
// debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Interface: name:'%s' , Flags: %d", __FILE__, __LINE__, name, flags);
return ret;
};
bool Interface::IsConnected() {
bool ret = false;
switch (type) {
case INTF_T_Z21: ret = intz21.IsConnected(); break;
default: break;
}
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsConnected", name);
return ret;
}
bool Interface::IsPoweron() {
bool ret = false;
switch (type) {
case 1: ret = intz21.IsPoweron(); break;
default: break;
}
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsPoweron", name);
return ret;
}
// **************************************************************************
// *
// * I N T E R F A C E S (gateway to all devices)
// *
// **************************************************************************
Interfaces::Interfaces () {
max = INTERFACES_MAX;
changed = 0;
};
Interfaces::~Interfaces() {
max = 0;
};
int Interfaces::LockThread() {
if (pthread_mutex_lock(&mtx) == 0) return 1;
else return 0;
}
int Interfaces::UnLockThread() {
if (pthread_mutex_unlock(&mtx) == 0) return 1;
else return 0;
}
JSONParse Interfaces::_GetJSON(int idx) {
JSONParse json;
JSONElement je;
string s = "";
json.Clear();
s = interfaces[idx].name; json.AddObject("name", s);
s = interfaces[idx].host; json.AddObject("host", s);
json.AddObject("flags", interfaces[idx].flags);
json.AddObject("type", interfaces[idx].type);
return json;
};
JSONParse Interfaces::GetJSON(string name) {
int i;
JSONParse jp;
jp.Clear();
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (name.compare(interfaces[i].name) == 0) {
jp = _GetJSON(i);
}
}
UnLockThread();
return jp;
};
void Interfaces::GetJSONAll(JSONParse *json) {
int i, cnt;
JSONElement je;
LockThread();
//
// write all railway data
// create json object array manualy
je.type = JSON_T_ARRAY;
je.name = "interfaces";
for (cnt = 0, i = 0; i < max; i++)
if (interfaces[i].name[0] != 0) {
if (cnt != 0) je.value += ","; // not first element
je.value += _GetJSON(i).ToString();
cnt++;
}
json->AddObject(je);
UnLockThread();
};
Interface Interfaces::GetInterfaceFromJSON(JSONParse *j) {
Interface i;
string s;
i.name[0] = 0;
i.host[0] = 0;
j->GetValue("name", &s);
strncpy (i.name, s.c_str(), REFERENCENAME_LEN);
j->GetValue("host", &s);
strncpy (i.host, s.c_str(), REFERENCENAME_LEN);
j->GetValueInt("flags", &i.flags);
j->GetValueInt("type", &i.type);
return i;
};
int Interfaces::Change(Interface *iface) {
int i;
int ifree = -1;
LockThread();
for (i = 0; i < max; i++) {
if (interfaces[i].name[0] != 0) {
// found element
if (strncmp(interfaces[i].name, iface->name, REFERENCENAME_LEN) == 0) {
ifree = i;
break;
}
}
else if (ifree == -1) ifree = i;
}
// element not found add new element
if (ifree != -1 && ifree < max) {
strncpy (interfaces[ifree].name, iface->name, REFERENCENAME_LEN);
strncpy (interfaces[ifree].host, iface->host, REFERENCENAME_LEN);
interfaces[ifree].flags = iface->flags;
interfaces[ifree].type = iface->type;
interfaces[ifree].Connect();
}
changed = 1;
UnLockThread();
return 1;
};
int Interfaces::Delete(string name) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (name.compare(interfaces[i].name) == 0) {
interfaces[i].Disconnect();
interfaces[i].name[0] = 0;
interfaces[i].host[0] = 0;
interfaces[i].flags = 0;
interfaces[i].type = INTF_T_OFF_UNKNOWN;
changed = 1;
break;
}
}
UnLockThread();
return 1;
};
void Interfaces::PowerOnOff(int onoff) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
interfaces[i].PowerOnOff(onoff);
}
UnLockThread();
};
//
// Turnouts
//
void Interfaces::SetTurnout(Turnout *t, int active, int motoractive) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
if (strncmp(t->ifname, interfaces[i].name, REFERENCENAME_LEN) == 0)
interfaces[i].SetTurnout(t, active, motoractive);
}
UnLockThread();
};
//
// Locomotives
//
void Interfaces::SetLocoSpeed(Locomotive *l, int speed) {
int i;
int step = 0, maxstep = 0;
switch(l->stepcode) {
case LOCO_INT_DCC14: maxstep = 14; break;
case LOCO_INT_DCC28: maxstep = 28; break;
case LOCO_INT_DCC128: maxstep = 126; break;
default: maxstep = 0; break;
bool Interface::IsSortCircuit() {
bool ret = false;
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsSortCircuit", name);
return ret;
}
if (abs(speed) < l->vmin) step = 0;
if (abs(speed) >= l->vmin) step = (speed * (maxstep)) / l->vmax;
if (abs(speed) > l->vmax) step = maxstep;
l->speed = speed;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
if (strncmp(l->ifname, interfaces[i].name, REFERENCENAME_LEN) == 0)
interfaces[i].SetLocoSpeed(l, step);
bool Interface::IsProgramminnMode() {
bool ret = false;
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsProgramminnMode", name);
return ret;
}
UnLockThread();
};
void Interfaces::SetLocoFunction(Locomotive *l, int func, int value) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
if (strncmp(l->ifname, interfaces[i].name, REFERENCENAME_LEN) == 0)
interfaces[i].SetLocoFunction(l, func, value);
bool Interface::IsEmergencyStop() {
bool ret = false;
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsEmergencyStop", name);
return ret;
}
UnLockThread();
};
void Interfaces::Loop() {
int i;
JSONParse jout;
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (interfaces[i].Loop()) {
//
// now we need to send an update
jout.Clear();
jout.AddObject ("interface", _GetJSON(i));
if (network) network->ChangeListPushToAll(jout.ToString());
}
}
};

@ -6,7 +6,6 @@
#include "server.h"
#include "UDPTCPNetwork.h"
#include "json.h"
#include "interface-z21.h"
#define INTF_F_CONNECTED 0x0001
#define INTF_F_POWER 0x0002
@ -15,73 +14,34 @@
#define INTF_F_PROGRAMMING 0x0010
#define INTF_F_NEEDUPDATE 0x8000 // if something changes during the Loop
#define INTF_T_OFF_UNKNOWN 0
#define INTF_T_Z21 1
class Interface {
private:
InterfaceZ21 intz21;
bool needs_update;
struct timeval turnouttimeout;
public:
bool needs_update;
char name[REFERENCENAME_LEN];
char host[NET_HOSTLEN];
int flags;
int type;
Interface();
~Interface();
void Connect();
void Disconnect();
void PowerOnOff(int onoff);
void SetLocoSpeed(Locomotive *l, int step);
void SetLocoFunction(Locomotive *l, int func, int value);
void SetTurnout(Turnout *t, int active, int motoractive);
bool IsConnected();
bool IsPoweron();
int Loop();
};
class Interfaces {
private:
Interface interfaces[INTERFACES_MAX];
int max;
int changed;
pthread_mutex_t mtx;
int LockThread();
int UnLockThread();
// not thread safe
JSONParse _GetJSON(int idx);
public:
Interfaces();
~Interfaces();
bool IsChanged() { return changed; }
void ClearChanged() { changed = 0; };
virtual ~Interface();
int Change(Interface *iface);
int Delete(string name);
virtual void Connect();
virtual void Disconnect();
JSONParse GetJSON(string name);
void GetJSONAll(JSONParse *json);
Interface GetInterfaceFromJSON(JSONParse *j);
virtual void PowerOnOff(int onoff);
virtual void SetLocoSpeed(Locomotive *l, int step);
virtual void SetLocoFunction(Locomotive *l, int func, int value);
virtual void SetTurnout(Turnout *t, int active, int motoractive);
//
//
void PowerOnOff(int onoff);
void SetLocoSpeed(Locomotive *l, int speed);
void SetLocoFunction(Locomotive *l, int func, int value);
void SetTurnout(Turnout *t, int active, int motoractive);
virtual bool IsConnected();
virtual bool IsPoweron();
virtual bool IsSortCircuit();
virtual bool IsProgramminnMode();
virtual bool IsEmergencyStop();
void Loop();
virtual int Loop();
};
#endif

@ -0,0 +1,293 @@
#include <string>
#include "modelbahn.h"
#include "interface.h"
#include "interface-z21.h"
#include "interfaces.h"
// **************************************************************************
// *
// * I N T E R F A C E S (gateway to all devices)
// *
// **************************************************************************
Interfaces::Interfaces () {
max = INTERFACES_MAX;
pthread_mutex_init(&mtx, NULL);
for (int i = 0; i < max; i++) interfaces[i] = NULL;
changed = 0;
};
Interfaces::~Interfaces() {
max = 0;
};
int Interfaces::LockThread() {
if (pthread_mutex_lock(&mtx) == 0) return 1;
else return 0;
}
int Interfaces::UnLockThread() {
if (pthread_mutex_unlock(&mtx) == 0) return 1;
else return 0;
}
JSONParse Interfaces::_GetJSON(int idx) {
JSONParse json;
JSONElement je;
string s = "";
json.Clear();
if (interfaces[idx] != NULL) {
s = interfaces[idx]->name; json.AddObject("name", s);
s = interfaces[idx]->host; json.AddObject("host", s);
json.AddObject("flags", interfaces[idx]->flags);
json.AddObject("type", interfaces[idx]->type);
}
return json;
};
JSONParse Interfaces::GetJSON(string name) {
int i;
JSONParse jp;
jp.Clear();
LockThread();
for (i = 0; i < max; i++) if (interfaces[i] != NULL){
if (interfaces[i]->name[0] != 0) {
if (name.compare(interfaces[i]->name) == 0) {
jp = _GetJSON(i);
}
}
}
UnLockThread();
return jp;
};
void Interfaces::GetJSONAll(JSONParse *json) {
int i, cnt;
JSONElement je;
LockThread();
//
// write all railway data
// create json object array manualy
je.type = JSON_T_ARRAY;
je.name = "interfaces";
for (cnt = 0, i = 0; i < max; i++) if(interfaces[i] != NULL)
if (interfaces[i]->name[0] != 0) {
if (cnt != 0) je.value += ","; // not first element
je.value += _GetJSON(i).ToString();
cnt++;
}
json->AddObject(je);
UnLockThread();
};
Interface Interfaces::GetInterfaceFromJSON(JSONParse *j) {
Interface i;
string s;
i.name[0] = 0;
i.host[0] = 0;
j->GetValue("name", &s);
strncpy (i.name, s.c_str(), REFERENCENAME_LEN);
j->GetValue("host", &s);
strncpy (i.host, s.c_str(), REFERENCENAME_LEN);
j->GetValueInt("flags", &i.flags);
j->GetValueInt("type", &i.type);
return i;
};
int Interfaces::Change(Interface *iface) {
int i;
int ifree = -1;
printf ("Interface Type:%d\n", iface->type);
LockThread();
for (i = 0; i < max; i++) {
if (interfaces[i] != NULL) {
// found element
if (strncmp(interfaces[i]->name, iface->name, REFERENCENAME_LEN) == 0) {
delete interfaces[i];
interfaces[i] = NULL;
ifree = i;
break;
}
}
else if (ifree == -1) ifree = i;
}
// element found or we need to add the element.
if (ifree != -1 && ifree < max) {
if (iface->type == INTF_T_Z21) interfaces[ifree] = new InterfaceZ21();
else interfaces[ifree] = new Interface();
strncpy (interfaces[ifree]->name, iface->name, REFERENCENAME_LEN);
strncpy (interfaces[ifree]->host, iface->host, REFERENCENAME_LEN);
interfaces[ifree]->flags = iface->flags;
interfaces[ifree]->type = iface->type;
interfaces[ifree]->Connect();
}
changed = 1;
UnLockThread();
return 1;
};
int Interfaces::Delete(string name) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
if (name.compare(interfaces[i]->name) == 0) {
interfaces[i]->Disconnect();
interfaces[i]->name[0] = 0;
interfaces[i]->host[0] = 0;
interfaces[i]->flags = 0;
interfaces[i]->type = INTF_T_OFF_UNKNOWN;
delete interfaces[i];
interfaces[i] = NULL;
changed = 1;
break;
}
}
UnLockThread();
return 1;
};
void Interfaces::PowerOnOff(int onoff) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
interfaces[i]->PowerOnOff(onoff);
}
UnLockThread();
};
//
// Turnouts
//
void Interfaces::SetTurnout(Turnout *t, int active, int motoractive) {
int i;
if (t == NULL) return;
LockThread();
debug (0, "%s:%d Interfaces::SetTurnout Name:%s active:%d Output%d", __FILE__, __LINE__, t->name, active, motoractive);
//
// if the interfacename is debug ... simulate a change in the turnout
//
if (strncmp(t->ifname, "DEBUG", REFERENCENAME_LEN) == 0) {
if (active) t->flags |= TURNOUT_F_ACTIVE;
else t->flags &= ~TURNOUT_F_ACTIVE;
server->TurnoutAddrMode(t->ifname, t->addr, active);
}
else {
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
if (strncmp(t->ifname, interfaces[i]->name, REFERENCENAME_LEN) == 0)
interfaces[i]->SetTurnout(t, active, motoractive);
}
}
UnLockThread();
};
//
// Locomotives
//
void Interfaces::SetLocoSpeed(Locomotive *l, int speed) {
int i;
int step = 0, maxstep = 0;
debug (0, "Interfaces::SetLocoSpeed Loco:'%s' Speed:%d", l->name, speed);
switch(l->stepcode) {
case LOCO_INT_DCC14: maxstep = 14; break;
case LOCO_INT_DCC28: maxstep = 28; break;
case LOCO_INT_DCC128: maxstep = 126; break;
default: maxstep = 0; break;
}
if (abs(speed) < l->vmin) step = 0;
if (abs(speed) >= l->vmin) step = (speed * (maxstep)) / l->vmax;
if (abs(speed) > l->vmax) step = maxstep;
l->speed = speed;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
if (strncmp(l->ifname, interfaces[i]->name, REFERENCENAME_LEN) == 0)
interfaces[i]->SetLocoSpeed(l, step);
}
UnLockThread();
};
void Interfaces::SetLocoFunction(Locomotive *l, int func, int value) {
int i;
debug (0, "Interfaces::SetLocoFunction Loco:'%s' Function:%d Value:%d", l->name, func, value);
LockThread();
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
if (strncmp(l->ifname, interfaces[i]->name, REFERENCENAME_LEN) == 0)
interfaces[i]->SetLocoFunction(l, func, value);
}
UnLockThread();
};
void Interfaces::Loop() {
int i;
JSONParse jout;
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
if (interfaces[i]->Loop()) {
//
// now we need to send an update
jout.Clear();
jout.AddObject ("interface", _GetJSON(i));
if (network) network->ChangeListPushToAll(jout.ToString());
}
}
};

@ -0,0 +1,61 @@
#ifndef _INTERFACES_H_
#define _INTERFACES_H_
#include "modelbahn.h"
#include "server.h"
#include "UDPTCPNetwork.h"
#include "json.h"
#include "interface.h"
#include "interfaces.h"
#define INTF_F_CONNECTED 0x0001
#define INTF_F_POWER 0x0002
#define INTF_F_STOP 0x0004
#define INTF_F_SHORT_CIRCUIT 0x0008
#define INTF_F_PROGRAMMING 0x0010
#define INTF_F_NEEDUPDATE 0x8000 // if something changes during the Loop
enum {
INTF_T_OFF_UNKNOWN = 0,
INTF_T_Z21,
INTF_T_MAX
};
class Interfaces {
private:
Interface *interfaces[INTERFACES_MAX];
int max;
int changed;
pthread_mutex_t mtx;
int LockThread();
int UnLockThread();
// not thread safe
JSONParse _GetJSON(int idx);
public:
Interfaces();
~Interfaces();
bool IsChanged() { return changed; }
void ClearChanged() { changed = 0; };
int Change(Interface *iface);
int Delete(string name);
JSONParse GetJSON(string name);
void GetJSONAll(JSONParse *json);
Interface GetInterfaceFromJSON(JSONParse *j);
//
//
void PowerOnOff(int onoff);
void SetLocoSpeed(Locomotive *l, int speed);
void SetLocoFunction(Locomotive *l, int func, int value);
void SetTurnout(Turnout *t, int active, int outputactive);
void Loop();
};
#endif

@ -3,6 +3,9 @@
#include <string>
#include <string.h>
using namespace std;
#include "debug.h"
#include "json.h"
@ -49,7 +52,7 @@ int JSONParse::Set(string json) {
Clear();
// find start and read until end
for (step = STEP_NONE, i = 0, ignorenext = false; i < json.length(); i++) {
for (step = STEP_NONE, i = 0, ignorenext = false; i < (int) json.length(); i++) {
// need to copy next character
// debug (0, "JSONParse: step:%d i:%d name:'%s' value:'%s'", step, i, jelement.name.c_str(), jelement.value.c_str());
if (ignorenext) {
@ -246,7 +249,7 @@ int JSONParse::GetIdx(string src, int idx, string *dest) {
// printf("\n***************************************idx:%d\n", idx);
for (i = 0; i < MAXRECURSIVE; i++) recursive[i] = 0;
for (i = 0; i < src.length() && rcnt < MAXRECURSIVE && cnt <= idx; i++) {
for (i = 0; i < (int) src.length() && rcnt < MAXRECURSIVE && cnt <= idx; i++) {
// printf ("i:%d rcnt:%d['%c'] cnt:%d char:'%c' ous:'%s'\n",
// i, rcnt, recursive[rcnt], cnt, src[i], dest->c_str());
if (src[i] == '[') {

File diff suppressed because it is too large Load Diff

@ -10,8 +10,9 @@
#define LOCO_F_CANREVERSE 0x0020
#define LOCO_F_SHORTTRAIN 0x0040
#define LOCO_F_AUTO 0x0100
#define LOCO_F_RANDOM 0x0200
#define LOCO_F_AUTOSTOP 0x0400
#define LOCO_F_AUTOSHED 0x0200
#define LOCO_F_AUTORANDOM 0x0400
#define LOCO_F_AUTOSTOP 0x0800
#define LOCO_TO_TURNOUT (50+TURNOUT_DEFAULT_ACTIVETIMEOUT)
#define LOCO_TO_TRYAGAIN (1000)
@ -29,7 +30,7 @@ enum {
LOCO_OR_NOTHING = 0,
LOCO_OR_SEARCH, // search way (to next block and lock way)
LOCO_OR_PREPARE, // switch turnouts right way (one every 100ms)
// if no turnout has to be set, continue
// if no turnout has to been set, continue
LOCO_OR_ONTHEWAY, // locomotive is on the way // maybe prepare next block?
// ASSIGN -> PREV, NEXT -> ASSIGN, NEXT <- (empty)
// propabely searching next block (if DEST is set)?
@ -39,11 +40,6 @@ enum {
LOCO_OR_STOPWAIT // stopping
};
struct s_LocoAuto {
int onroute; // LOCO_OR_.....
struct timeval waituntil; // wait until this time for next action (tournout, waiting station...)
};
struct s_Locomotive {
char name[REFERENCENAME_LEN]; // name
char ifname[REFERENCENAME_LEN]; // ref. of interface
@ -55,6 +51,7 @@ struct s_Locomotive {
int vmid; // speed - for normal trains (max for cargo trains, on automode)
int vfast; // speed - for normal trains
int vmax; // speed - maximum speed
char schedway[WAYDATA_LEN]; // scheduled way W:15,B:+B17,W30,B:-B21
// dynamic data
int speed; // current speed
@ -64,6 +61,7 @@ struct s_Locomotive {
char blockprev[REFERENCENAME_LEN]; // prev block (mostly assigned block
char blockdest[REFERENCENAME_LEN]; // destination block
int sched_step; // on automode this is the scheduled way step
char auto_way[WAYDATA_LEN]; // route to way "b:+blockname,t:name:0,t:name:1,b:-blockname"
char auto_wayold[WAYDATA_LEN]; // route to way "b:+blockname,t:name:0,t:name:1,b:-blockname"
int auto_onroute; // LOCO_OR_....
@ -71,6 +69,7 @@ struct s_Locomotive {
struct timeval auto_timenext; // timeval of the next active step
} typedef Locomotive;
class Locomotives {
private:
Locomotive *locomotives;
@ -83,7 +82,15 @@ class Locomotives {
// not thread safe
JSONParse _GetJSON(int idx);
int SchedulerNextStep(Locomotive *loc); // automode, calculate next step
void SendUpdate(Locomotive *loc);
int Loco_SearchAndLock(Locomotive *loco);
int Loco_PrepareWay(Locomotive *loco);
int Loco_OnRoute(Locomotive *loco);
int Loco_BlockEnterStop(Locomotive *loco);
int Loco_BlockEnterNext(Locomotive *loco);
int Loco_BlockStopWait(Locomotive *loco);
public:
Locomotives();
~Locomotives();
@ -97,17 +104,18 @@ class Locomotives {
int SetReverse(string name, int reverse);
int SetFunction(string name, int func, int value);
int Reset(string name);
int SetMan(string name);
int SetAutoMan(string name);
int SetAuto(string name);
int SetAutoRand(string name);
int SetModeMan(string name);
int SetModeAutoMan(string name);
int SetModeAuto(string name);
int SetModeAutoRand(string name);
int SetModeAutoShed(string name);
int SetSpeedFromBus (string ifname, int addr, int speed);
int SetFunctionFromBus (string ifname, int addr, int func);
int SetDestination (string name, string block, int direction);
int SetAssign (string name, string block, int direction);
int GetFlags(string name);
int AutoCheckWaySingleStep(string way, string locname, int *data);
int AutoCheckWaySingleStep(string way, Locomotive *loc, int *data);
int Loop();
string GetName(int idx);
@ -115,7 +123,6 @@ class Locomotives {
JSONParse GetJSON(string name);
void GetJSONAll(JSONParse *json);
Locomotive GetLocomotiveFromJSON(JSONParse *j);
int Test(string loco);
};

@ -18,9 +18,12 @@ int running = 1;
Server *server = NULL;
Network *network = NULL;
int simulation = 0;
int main (int argc, char **argv) {
int ret;
int i;
tzset(); // needed for localtime to work
//
// setup signals
@ -49,6 +52,14 @@ int main (int argc, char **argv) {
debug (0, "* *");
debug (0, "***************************************************");
debug (0, "");
for (i = 1; i < argc; i++) {
if (strcmp (argv[i], "-simulation") == 0) {
simulation = 1;
debug (0, "WARINING SIMULATION MODE ACTIVE. ALL COMMANDS WILL BE SEND");
debug (0, "TO THE INTERFACES. TURNOUT AND SENSORDATA WILL BE FORCED.");
sleep (5);
}
}
//////////////////////////////////////////////////////////////////////
//

@ -35,12 +35,14 @@ int main (int argc, char **argv) {
//
// read data
memset (buffer, 0x0, BUFFERSIZE+1);
for (ptr = buffer, inlen = 0; inlen < BUFFERSIZE-1 && (fgets (ptr, BUFFERSIZE - inlen, stdin)) > 0;) {
for (ptr = buffer, inlen = 0; inlen < BUFFERSIZE-1 && (fgets (ptr, BUFFERSIZE - inlen, stdin)) != NULL;) {
inlen = strlen (buffer);
ptr = buffer+inlen;
}
if (inlen >= BUFFERSIZE-1) fprintf (logf, "read input puffer full.\n");
fprintf (logf, "read from stdin %d bytes\n", strlen(buffer));
fprintf (logf, "read from stdin %lu bytes\n", strlen(buffer));
// fprintf (logf, "%s\n", buffer);
fprintf (logf, "*************************************\n");
//
// send data to server
@ -54,7 +56,7 @@ int main (int argc, char **argv) {
i = u.ReadTimeout(buffer, BUFFERSIZE-1, 1000);
buffer[i] = 0;
fprintf (logf, "read from server %d bytes\n", i);
// fprintf (logf, "%s\n", buffer);
fprintf (logf, "%s\n", buffer);
printf ("%s", buffer);
} while (i == BUFFERSIZE-1);
u.Close();

@ -6,7 +6,7 @@
#define BUFFERSIZE 64000
#define MAXWAITTIME 500
#define UNIX_SOCKET_FILE "/tmp/modelbahn.socket"
#define DEFAULT_DATADIR "/home/steffen/Dokumente/Programmierung/modelbahn/"
#define DEFAULT_DATADIR "/home/steffen/Dokumente/Programmierung/Modelbahn/"
#define SESSIONS_MAX 8
#define REFERENCENAME_LEN 128
@ -27,7 +27,7 @@ extern int running;
extern Server *server;
extern Network *network;
extern int simulation;
//
// to measure the time in ms (used for debugging)

@ -29,11 +29,8 @@ Network::Network() {
thread = 0;
sessions.clear();
thread_running = 0;
mtx = { 0 };
mtx = PTHREAD_MUTEX_INITIALIZER;
mtxsessions = { 0 };
mtxsessions = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&mtx, NULL);
pthread_mutex_init(&mtxsessions, NULL);
}
Network::~Network() {
@ -54,7 +51,6 @@ Network::~Network() {
void Network::ThreadProcess() {
list<UNIX*>::iterator iteru;
Session *s;
UNIX *u;
int i = 0;
@ -181,9 +177,7 @@ Session *Network::GetSession(int sid) {
int Network::ClientLoop(UNIX *client) {
char bufferin[BUFFERSIZE];
char bufferout[BUFFERSIZE];
int len, i, rid, sid;
int res;
int len, rid, sid;
list<Session*>::iterator siter;
Session *session = NULL;
string value;
@ -200,6 +194,7 @@ int Network::ClientLoop(UNIX *client) {
JSONParse json;
JSONParse jsonout;
JSONParse jelement;
long int l;
bufferin[len] = 0; // prevent reading behind the data
@ -232,8 +227,6 @@ int Network::ClientLoop(UNIX *client) {
}
if (sid <= 0) {
int x, y;
debug (0, "* sid not set, gettin new SID");
session = new Session(rid);
sid = session->GetSessionID();
@ -279,8 +272,9 @@ int Network::ClientLoop(UNIX *client) {
jsonout.AddObject(je);
}
s = jsonout.ToString();
// debug (0, "%s:%d ---> send:\n\n\n%s\n\n\n", __FILE__, __LINE__, s.c_str());
client->Write((char*)s.c_str(), strlen(s.c_str()));
// printf ("***************************** %s:%d ---> send:\n\n\n%s\n\n\n", __FILE__, __LINE__, s.c_str());
l = client->Write((char*)s.c_str(), strlen(s.c_str()));
// printf ("\n\n Network::ClientLoop %s:%d strlen:%ld result:%ld \n\n\n", __FILE__, __LINE__, strlen(s.c_str()), l);
result = 1;
}
else {

@ -55,6 +55,7 @@ private:
void AddJSONSensor(JSONParse *jp);
void DelJSONSensor(JSONParse *jp);
void SetJSONSensorActive(JSONParse *jp);
void AddJSONInterface(JSONParse *jp);
void DelJSONInterface(JSONParse *jp);
@ -65,11 +66,11 @@ private:
void SetJSONLocoDest(JSONParse *jp);
void SetJSONLocoAssign(JSONParse *jp);
void SetJSONLocoReset(JSONParse *jp);
void SetJSONLocoTest(JSONParse *jp);
void SetJSONLocoMan(JSONParse *jp);
void SetJSONLocoAutoMan(JSONParse *jp);
void SetJSONLocoAuto(JSONParse *jp);
void SetJSONLocoAutoRand(JSONParse *jp);
void SetJSONLocoAutoShed(JSONParse *jp);
void BlockJSONOff(JSONParse *jp);
void BlockJSONClear(JSONParse *jp);

File diff suppressed because it is too large Load Diff

@ -25,6 +25,7 @@ enum {
#define RAILWAYS_MAX_WIDTH 500
#define RAILWAYS_MAX_HEIGHT 500
#define RAILWAYS_LOCKF_KEEPSTART 0x0001 // keep start
// direktion
//
@ -74,7 +75,7 @@ struct s_findway_data {
int oldx;
int oldy;
int oldenterfrom;
int parma;
int dist;
string way;
};
@ -99,7 +100,10 @@ class Railways {
JSONParse _GetJSONRailway(int x, int y);
void _New (int w, int h);
void DebugPrintFindWay(struct s_findway_map *fw);
int _FindReference(int *x, int *y, string name);
int _FindReference(int *x, int *y, string name, int cnt);
int _SplitBlockIsFreeAndAllowed(string loconame, int locoflags, string block);
int _NextPosIsValid(string loconame, int locoflags, struct s_findway_data *fwd);
string GetDestBlock(int locoflags, string blockend);
public:
Railways();
@ -125,12 +129,11 @@ class Railways {
void GetJSONAll(JSONParse *json);
Railway GetRailwayFromJSON(JSONParse *j);
int FindReference(int *x, int *y, string name);
int FindReference(int *x, int *y, string name, int cnt);
int FindWay(string blockstart, string blockend, string lockedfor, string *next);
int FindWayCheckIfNoDoubleTurnouts (string *next);
int FindRandomWay(string blockstart, string lockedfor, string *next);
int LockWay (string way, string lockedby, int lockonoff);
int LockWay (string way, string lockedby) { return LockWay(way, lockedby, 1); };
int UnLockWay (string way, string lockedby) { return LockWay(way, lockedby, 0); };
int LockWay (string way, string lockedby, int lockonoff, int flags);
int SetLockedby (int x, int y, string name, int locked);
struct s_findway_data NextPos(struct s_findway_data pos, int dirtype);

@ -7,9 +7,12 @@
Sensors::Sensors () {
changed = 0;
sensors = (Sensor*) malloc(sizeof(Sensor)*SENSORS_MAX);
memset (sensors, 0x0, sizeof(Sensor)*SENSORS_MAX);
max = SENSORS_MAX;
pthread_mutex_init(&mtx, NULL);
};
Sensors::~Sensors() {
free (sensors);
sensors = NULL;
@ -35,6 +38,29 @@ int Sensors::GetActive(string name) {
};
int Sensors::SetActive(string name, int value) {
int i;
JSONParse jp;
Lock();
for (i = 0; i < max; i++) if (sensors[i].name[0] != 0) {
if (name.compare(sensors[i].name) == 0) {
if (value) sensors[i].flags |= SENSOR_F_ACTIVE;
else sensors[i].flags &= ~SENSOR_F_ACTIVE;
jp.Clear();
jp.AddObject("sensor", _GetJSON(i));
if(network) network->ChangeListPushToAll(jp.ToString());
break;
}
}
UnLock();
return 1;
};
int Sensors::Lock() {
if (pthread_mutex_lock(&mtx) == 0) return 1;
else return 0;

@ -37,6 +37,7 @@ class Sensors {
int Change(Sensor *se);
int Get(int idx, Sensor *dest);
int GetActive(string name);
int SetActive(string name, int value);
int Get(string name, Sensor *dest);
int Delete(string name);

@ -73,7 +73,7 @@ int Server::Load(string fn) {
close (fd);
// everything read?
if (len < sbuf.st_size) {
if (len < (size_t) sbuf.st_size) {
free (buf);
debug (DEBUG_ERROR, "* Reading Track File Failed. (len < filesize)");
return 0;
@ -137,7 +137,6 @@ int Server::Load(string fn) {
turnouts.Change(&to);
}
//
// read blocks
Block bl;

@ -24,10 +24,9 @@
int Server::Start() {
int err;
pthread_attr_t attr;
mtx = { 0 };
mtx = PTHREAD_MUTEX_INITIALIZER;
thread_running = 1;
pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
err = pthread_create (&thread, &attr, ThreadEntry, this);
@ -41,9 +40,12 @@ int Server::Start() {
Server::Server() {
mtx = { 0 };
mtx = PTHREAD_MUTEX_INITIALIZER;
thread = 0;
thread_running = 0;
railways.SetSize(200, 200);
railways.SetSize(64, 32);
status_text = "init server";
mode = SMODE_STARTUP;
data_reset.mr_idx = -1;
@ -62,18 +64,30 @@ Server::~Server() {
int Server::TurnoutSet(string name, int active) {
int x, y, locked = 0;
string lockedby;
int cnt = 0;
Railway r;
//
// check if locked
while (server->railways.FindReference(&x, &y, name)) {
while (server->railways.FindReference(&x, &y, name, (cnt++))) {
r = server->railways.Get(x, y);
printf ("Reference %d,%d Name:%s Lockedby:%d\n", x, y, r.name, r.lockedby);
debug (0, "%s:%d Reference %d,%d Name:%s Lockedby:%s", __FILE__, __LINE__, x, y, r.name, r.lockedby);
if (r.lockedby[0] != 0) {
locked = 1;
lockedby = r.lockedby;
}
}
if (simulation) {
int flags;
debug (0, "%s:%d WARNING SIMULATION MODE", __FILE__, __LINE__);
flags = turnouts.GetFlags(turnouts.GetIdx(name));
if (flags & TURNOUT_F_TURNOUT) flags &= ~TURNOUT_F_TURNOUT;
else flags |= TURNOUT_F_TURNOUT;
turnouts.SetFlags(turnouts.GetIdx(name), flags);
turnouts.Set(name, active);
}
if (locked == 0) return turnouts.Set(name, active);
else {
debug (0, "%s:%d SetJSONTurnout Element %s is locked by %s", __FILE__, __LINE__, name.c_str(), lockedby.c_str());
@ -251,7 +265,7 @@ void Server::CycleModeReset() {
else {
data_reset.mr_idx = -1;
data_reset.mr_step++;
data_reset.mr_lastelm;
data_reset.mr_lastelm = "";
}
}
}
@ -264,19 +278,23 @@ void Server::CycleModeReset() {
data_reset.mr_idx++;
data_reset.mr_lastelm = turnouts.GetName(data_reset.mr_idx);
if (data_reset.mr_lastelm.length() > 0) {
//
// reset output/turnout only if not a relais
flags = turnouts.GetFlags(data_reset.mr_idx);
if ((flags & TURNOUT_F_ISRELAIS) == 0) {
if (flags & TURNOUT_F_TURNOUT) active = 1;
else active = 0;
timer_start (&data_reset.mr_timestamp);
if (data_reset.mr_lastelm.length() > 0) {
debug (0, "* Reset Turnout %s", data_reset.mr_lastelm.c_str());
TurnoutSet(data_reset.mr_lastelm, active);
}
}
else {
data_reset.mr_idx = -1;
data_reset.mr_step++;
data_reset.mr_lastelm;
data_reset.mr_lastelm = "";
}
}
}

@ -27,7 +27,7 @@
#include "railway.h"
#include "locomotive.h"
#include "sensor.h"
#include "interface.h"
#include "interfaces.h"
#include "block.h"
enum SMODE {
@ -164,11 +164,11 @@ public:
int LocomotiveSetDest(string name, string block, int direction) { return locomotives.SetDestination(name, block, direction); };
int LocomotiveSetAssign(string name, string block, int direction) { return locomotives.SetAssign(name, block, direction); };
int LocomotiveReset(string name) { return locomotives.Reset(name); };
int LocomotiveSetMan(string name) { return locomotives.SetMan(name); };
int LocomotiveSetAuto(string name) { return locomotives.SetAuto(name); };
int LocomotiveSetAutoMan(string name) { return locomotives.SetAutoMan(name); };
int LocomotiveSetAutoRand(string name) { return locomotives.SetAutoRand(name); };
int LocomotiveTest(string name) { return locomotives.Test(name); };
int LocomotiveSetMan(string name) { return locomotives.SetModeMan(name); };
int LocomotiveSetAuto(string name) { return locomotives.SetModeAuto(name); };
int LocomotiveSetAutoMan(string name) { return locomotives.SetModeAutoMan(name); };
int LocomotiveSetAutoRand(string name) { return locomotives.SetModeAutoRand(name); };
int LocomotiveSetAutoShed(string name) { return locomotives.SetModeAutoShed(name); };
/////////////////////////////////////////
// Sensor
@ -176,6 +176,7 @@ public:
Sensor SensorFromJSON(JSONParse *j) { return sensors.GetSensorFromJSON(j); };
JSONParse SensorGetJSON(string name) { return sensors.GetJSON(name); };
int SensorDelete(string name) { return sensors.Delete(name); };
int SensorSetActive(string name, int value) { return sensors.SetActive(name, value); };
/////////////////////////////////////////
// Blocks

@ -64,6 +64,10 @@ int Session::ProcessData(JSONParse *jin, JSONParse *jout) {
debug (0, "* Session Del Interface");
DelJSONInterface(jin);
}
//
// turnouts
//
else if (command.compare("addsensor") == 0) {
debug (0, "* Session Add Sensor");
AddJSONSensor(jin);
@ -72,6 +76,11 @@ int Session::ProcessData(JSONParse *jin, JSONParse *jout) {
debug (0, "* Session del Sensor");
DelJSONSensor(jin);
}
else if (command.compare("sensorSetActive") == 0) {
debug (0, "* Session Sensor Set Active");
printf ("%s:%d jin:%s", __FILE__, __LINE__, jin->ToString().c_str());
SetJSONSensorActive(jin);
}
//
// turnouts
@ -139,12 +148,12 @@ int Session::ProcessData(JSONParse *jin, JSONParse *jout) {
else if (command.compare("locomotivesetautorand") == 0) {
SetJSONLocoAutoRand(jin);
}
else if (command.compare("locomotivesetautoshed") == 0) {
SetJSONLocoAutoShed(jin);
}
else if (command.compare("locomotivereset") == 0) {
SetJSONLocoReset(jin);
}
else if (command.compare("locomotivetest") == 0) {
SetJSONLocoTest(jin);
}
//
// poweron / poweroff / save and resetdata
//
@ -178,9 +187,11 @@ int Session::ProcessData(JSONParse *jin, JSONParse *jout) {
// debuggin maybe we need to fix this somehow
elements = json.GetElements();
for (iter = elements.begin(); iter != elements.end(); iter++)
for (iter = elements.begin(); iter != elements.end(); iter++) {
// printf ("*********************** Session::ProcessData %s:%d\n\n***\n%s\n***\n", __FILE__, __LINE__, (*iter).GetString().c_str());
ChangeListPush("{"+(*iter).GetString()+"}");
}
}
else {
debug (DEBUG_ERROR | DEBUG_SESSION, "%s:%d Unknown command: '%s' JSON:%s",
__FILE__, __LINE__, command.c_str(), jin->ToString().c_str());
@ -521,85 +532,85 @@ void Session::SetJSONLocoAssign(JSONParse *jp) {
};
void Session::SetJSONLocoTest(JSONParse *jp) {
void Session::SetJSONLocoReset(JSONParse *jp) {
string loco;
JSONParse jout;
jp->GetValue("locomotive", &loco);
server->LockThread();
server->LocomotiveTest(loco);
server->LocomotiveReset(loco);
jout.Clear();
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco));
if (network) network->ChangeListPushToAll(jout.ToString());
server->UnLockThread();
};
void Session::SetJSONLocoReset(JSONParse *jp) {
void Session::SetJSONLocoMan(JSONParse *jp) {
string loco;
JSONParse jout;
jp->GetValue("locomotive", &loco);
server->LockThread();
server->LocomotiveReset(loco);
server->LocomotiveSetMan(loco);
jout.Clear();
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco));
if (network) network->ChangeListPushToAll(jout.ToString());
server->UnLockThread();
};
void Session::SetJSONLocoMan(JSONParse *jp) {
void Session::SetJSONLocoAutoMan(JSONParse *jp) {
string loco;
JSONParse jout;
jp->GetValue("locomotive", &loco);
server->LockThread();
server->LocomotiveSetMan(loco);
server->LocomotiveSetAutoMan(loco);
jout.Clear();
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco));
if (network) network->ChangeListPushToAll(jout.ToString());
server->UnLockThread();
};
void Session::SetJSONLocoAutoMan(JSONParse *jp) {
void Session::SetJSONLocoAuto(JSONParse *jp) {
string loco;
JSONParse jout;
jp->GetValue("locomotive", &loco);
server->LockThread();
server->LocomotiveSetAutoMan(loco);
server->LocomotiveSetAuto(loco);
jout.Clear();
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco));
if (network) network->ChangeListPushToAll(jout.ToString());
server->UnLockThread();
};
void Session::SetJSONLocoAuto(JSONParse *jp) {
void Session::SetJSONLocoAutoRand(JSONParse *jp) {
string loco;
JSONParse jout;
jp->GetValue("locomotive", &loco);
server->LockThread();
server->LocomotiveSetAuto(loco);
server->LocomotiveSetAutoRand(loco);
jout.Clear();
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco));
if (network) network->ChangeListPushToAll(jout.ToString());
server->UnLockThread();
};
void Session::SetJSONLocoAutoRand(JSONParse *jp) {
void Session::SetJSONLocoAutoShed(JSONParse *jp) {
string loco;
JSONParse jout;
jp->GetValue("locomotive", &loco);
server->LockThread();
server->LocomotiveSetAutoRand(loco);
server->LocomotiveSetAutoShed(loco);
jout.Clear();
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco));
if (network) network->ChangeListPushToAll(jout.ToString());
@ -666,9 +677,6 @@ void Session::SetJSONTurnout(JSONParse *jp) {
string name;
string lockedby;
int active;
int x, y;
int locked = 0;
Railway r;
server->LockThread();
@ -680,15 +688,11 @@ void Session::SetJSONTurnout(JSONParse *jp) {
// activate
debug (0, "%s:%d SetJSONTurnout Element %s active:%d", __FILE__, __LINE__, name.c_str(), active);
server->TurnoutSet(name, active);
jout.Clear();
jout.AddObject("turnout", server->TurnoutGetJSON(name));
if (network) network->ChangeListPushToAll(jout.ToString());
}
server->UnLockThread();
};
//
// add new block
//
@ -769,6 +773,27 @@ void Session::BlockJSONClear(JSONParse *jp) {
};
//
// add new block
//
void Session::SetJSONSensorActive(JSONParse *jp) {
string name;
int enabled;
JSONParse jtmp;
JSONParse jout;
server->LockThread();
jp->GetValue("sensor", &name);
jp->GetValueInt("enabled", &enabled);
server->SensorSetActive(name, enabled);
// jout.Clear();
// jout.AddObject("block", server->BlockGetJSON(bl.name));
// if (network) network->ChangeListPushToAll(jout.ToString());
server->UnLockThread();
};
/*
res = json.GetValue("command", &value);

@ -5,7 +5,9 @@
Turnouts::Turnouts() {
changed = 0;
turnouts = (Turnout*) malloc(sizeof(Turnout)*TURNOUTS_MAX);
memset (turnouts, 0x0, sizeof(Turnout)*TURNOUTS_MAX);
max = TURNOUTS_MAX;
pthread_mutex_init(&mtx, NULL);
};
Turnouts::~Turnouts() {
@ -164,20 +166,33 @@ int Turnouts::Delete(string name) {
int Turnouts::Set(string name, int value) {
int i;
JSONParse jp;
//
Lock();
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
if (name.compare(turnouts[i].name) == 0) {
debug (0, "Turnout::Set: Name:%s Flags:%d[%c%c%c] Value:%d", name.c_str(), turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-',
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
debug (0, "%s:%d Turnout::Set: Name:%s Flags:%d[%c%c%c%c] Value:%d", __FILE__, __LINE__, name.c_str(), turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_ISRELAIS) ? 'R' : '-',
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-',
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-',
value);
if (turnouts[i].flags & TURNOUT_F_ISRELAIS) {
printf ("%s:%d is relais.... %d\n", __FILE__, __LINE__, value);
server->interfaces.SetTurnout(&turnouts[i], value, value);
}
else {
if (turnouts[i].flags & TURNOUT_F_INVERSE)
server->interfaces.SetTurnout(&turnouts[i], !value, 1); // motor on
else
server->interfaces.SetTurnout(&turnouts[i], value, 1); // motor on
}
jp.Clear();
jp.AddObject("turnout", _GetJSON(i));
if (network) network->ChangeListPushToAll(jp.ToString());
gettimeofday (&turnouts[i].activatetime, NULL);
changed = 1;
@ -215,14 +230,15 @@ void Turnouts::SetFromBus(string ifname, int addr, int value) {
int i;
JSONParse jp;
debug (0, "Turnouts::SetFromBus Interface:%s, addr: %d, value:%d", ifname.c_str(), addr, value);
debug (0, "%s:%d Turnouts::SetFromBus Interface:%s, addr: %d, value:%d", __FILE__, __LINE__, ifname.c_str(), addr, value);
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
if (ifname.compare(turnouts[i].ifname) == 0 && turnouts[i].addr == addr) {
debug (0, "Turnout::SetFromBus Name:%s Flags:%d[%c%c%c]", turnouts[i].name, turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-',
debug (0, "%s:%d Turnout::SetFromBus Name:%s Flags:%d[%c%c%c%c]", __FILE__, __LINE__, turnouts[i].name, turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_ISRELAIS) ? 'R' : '-',
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-',
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-');
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-');
// if (value) turnouts[i].flags |= TURNOUT_F_ACTIVE;
// else turnouts[i].flags &= ~TURNOUT_F_ACTIVE;
@ -235,10 +251,11 @@ void Turnouts::SetFromBus(string ifname, int addr, int value) {
if (value) turnouts[i].flags |= TURNOUT_F_TURNOUT;
else turnouts[i].flags &= ~TURNOUT_F_TURNOUT;
}
debug (0, "Turnout::SetFromBus Name:%s Flags:%d[%c%c%c]", turnouts[i].name, turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-',
debug (0, "%s:%d Turnout::SetFromBus Name:%s Flags:%d[%c%c%c%c]", __FILE__, __LINE__, turnouts[i].name, turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_ISRELAIS) ? 'R' : '-',
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-',
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-');
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-');
jp.AddObject("turnout", _GetJSON(i));
if(network) network->ChangeListPushToAll(jp.ToString());
@ -248,11 +265,13 @@ void Turnouts::SetFromBus(string ifname, int addr, int value) {
//
// this loop is important: Turnout motors needs to be deactivated after a short time
//
/*
* this loop is important: some outputs especially motors needs to be deactivated
* after a short period of time.
*/
void Turnouts::Loop() {
int i;
JSONParse jp;
struct timeval curtime;
gettimeofday(&curtime, NULL);
@ -260,9 +279,9 @@ void Turnouts::Loop() {
Lock();
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
if (turnouts[i].flags & TURNOUT_F_ACTIVE) {
if ((turnouts[i].flags & TURNOUT_F_ACTIVE) && ((turnouts[i].flags & TURNOUT_F_ISRELAIS) == 0)) {
//
// motor still active check timeout and deactivate
// motor/output still active check timeout and deactivate
int timediff = (1000 * (curtime.tv_sec - turnouts[i].activatetime.tv_sec)) +
((curtime.tv_usec - turnouts[i].activatetime.tv_usec) / 1000);
if (timediff < 0) gettimeofday (&turnouts[i].activatetime, NULL);
@ -270,12 +289,25 @@ void Turnouts::Loop() {
// debug (0, "%s:%d timediff: %d", __FILE__, __LINE__, timediff);
if (timediff > turnouts[i].activetimeout) {
int active = turnouts[i].flags & TURNOUT_F_TURNOUT;
int turnout = (turnouts[i].flags & TURNOUT_F_TURNOUT) != 0 ? 1 : 0;
debug (0, "%s:%d Turnout::Loop Name:%s Flags:%d[%c%c%c%c] Turnout:%d", __FILE__, __LINE__, turnouts[i].name, turnouts[i].flags,
(turnouts[i].flags & TURNOUT_F_ISRELAIS) ? 'R' : '-',
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-',
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
(turnouts[i].flags & TURNOUT_F_INVERSE) ? 'I' : '-',
turnout);
if (turnouts[i].flags & TURNOUT_F_INVERSE)
server->interfaces.SetTurnout(&turnouts[i], !active, 0); // motor on
server->interfaces.SetTurnout(&turnouts[i], !turnout, 0); // motor on
else
server->interfaces.SetTurnout(&turnouts[i], active, 0); // motor on
server->interfaces.SetTurnout(&turnouts[i], turnout, 0); // motor on
turnouts[i].flags &= ~TURNOUT_F_ACTIVE;
jp.Clear();
jp.AddObject("turnout", _GetJSON(i));
if (network) network->ChangeListPushToAll(jp.ToString());
}
}
}
@ -307,3 +339,34 @@ int Turnouts::GetFlags(int idx) {
};
void Turnouts::SetFlags(int idx, int flags) {
JSONParse jp;
Lock();
if (idx <= max && idx >= 0) {
turnouts[idx].flags = flags;
jp.Clear();
jp.AddObject("turnout", _GetJSON(idx));
if (network) network->ChangeListPushToAll(jp.ToString());
}
UnLock();
};
int Turnouts::GetIdx(string name) {
int i;
int res = -1;
//
Lock();
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
if (name.compare(turnouts[i].name) == 0) {
res = i;
break;
}
}
UnLock();
return res;
}

@ -6,8 +6,9 @@
#include "server.h"
//
#define TURNOUT_F_INVERSE 0x0001 // inverse output
#define TURNOUT_F_ACTIVE 0x0002 // motor active
#define TURNOUT_F_ACTIVE 0x0002 // motor/output active
#define TURNOUT_F_TURNOUT 0x0004 // turnout active
#define TURNOUT_F_ISRELAIS 0x0008 // output is relais no auto off
#define TURNOUT_DEFAULT_ACTIVETIMEOUT 250 // active timeout default value
@ -54,7 +55,9 @@ class Turnouts {
Turnout GetTurnoutFromJSON(JSONParse *j);
string GetName(int idx);
int GetIdx(string name);
int GetFlags(int idx);
void SetFlags(int idx, int flags);
void SetFromBus(string name, int addr, int active);
};

@ -4,13 +4,14 @@
var blocks = [];
const BLOCK_F_OFF = 0x0001;
const BLOCK_F_SPLIT = 0x0002;
const BLOCK_F_SPLITPOS = 0x0004;
const BLOCK_F_SHORT = 0x0010;
const BLOCK_F_LONG = 0x0020;
const BLOCK_F_ENDSTATION = 0x0040;
const BLOCK_F_STATION = 0x0080;
const BLOCK_F_SPEEDLIMIT = 0x0100;
const BLOCK_F_ONLYCARGO = 0x0200;
const BLOCK_F_ONLYPASSENGER = 0x0400;
//
// update or add a new element
@ -21,23 +22,35 @@ function block_Update(blockdata) {
blocks[i].name = blockdata.name;
blocks[i].flags = blockdata.flags;
blocks[i].lockedby = blockdata.lockedby;
blocks[i].sensor_pos_1 = blockdata.sensor_pos_1,
blocks[i].sensor_center = blockdata.sensor_center,
blocks[i].sensor_neg_1 = blockdata.sensor_neg_1
blocks[i].sensor_stop_0 = blockdata.sensor_stop_0;
blocks[i].sensor_shortstop_0 = blockdata.sensor_shortstop_0;
blocks[i].sensor_slow_0 = blockdata.sensor_slow_0;
blocks[i].sensor_enter_0 = blockdata.sensor_enter_0;
blocks[i].sensor_stop_1 = blockdata.sensor_stop_1;
blocks[i].sensor_shortstop_1 = blockdata.sensor_shortstop_1;
blocks[i].sensor_slow_1 = blockdata.sensor_slow_1;
blocks[i].sensor_enter_1 = blockdata.sensor_enter_1;
blocks[i].secondblock = blockdata.secondblock;
blockdetail_setData(blocks[i]);
return;
}
}
// not found add element
//debug ("Add Interface:" + intdata.name + "(" + intdata.host + ")");
//console.log ("Add Interface:" + intdata.name + "(" + intdata.host + ")");
blocks.push ({
name: blockdata.name,
flags: blockdata.flags,
lockedby: blockdata.lockedby,
sensor_pos_1: blockdata.sensor_pos_1,
sensor_center: blockdata.sensor_center,
sensor_neg_1: blockdata.sensor_neg_1
sensor_enter_0: blockdata.sensor_enter_0,
sensor_slow_0: blockdata.sensor_slow_0,
sensor_stop_0: blockdata.sensor_stop_0,
sensor_shortstop_0: blockdata.sensor_shortstop_0,
sensor_enter_1: blockdata.sensor_enter_1,
sensor_slow_1: blockdata.sensor_slow_1,
sensor_stop_1: blockdata.sensor_stop_1,
sensor_shortstop_1: blockdata.sensor_shortstop_1,
secondblock: blockdata.secondblock
});
};
@ -178,13 +191,23 @@ function block_server_Clear(blockname) {
//
function block_server_Off(blockname) {
var request = { command: "blockoff", block: blockname };
debug ("send BlockOff:" + blockname);
console.log ("send BlockOff:" + blockname);
serverinout (request, serverinout_defaultCallback);
};
//
// if create is set the name should be filled in
function blockdetail_fillsensor() {
let r = "<option value=\"\"></option>";
for (var i = 0; i < sensors.length; i++) {
if (sensors[i].name)
r += "<option value=\""+sensors[i].name+"\">"+sensors[i].name+"</option>";
};
return r;
}
function blockdetail_show(name, create) {
var win = document.getElementById("blockdetail");
let innerHTML = " \
@ -198,44 +221,44 @@ function blockdetail_show(name, create) {
\
<table><tr><td>\
\
<table><tr><td> \
<label><input id=\"blockdet_flagoff\" type=\"checkbox\" value=\"\" disabled>Off Service</label><br> \
<label><input id=\"blockdet_flagshort\" type=\"checkbox\" value=\"\">Short</label><br>\
<label><input id=\"blockdet_flaglong\" type=\"checkbox\" value=\"\">Long</label> \
</td><td> \
<label><input id=\"blockdet_flagend\" type=\"checkbox\" value=\"\">End</label><br> \
<label><input id=\"blockdet_flagstation\" type=\"checkbox\" value=\"\">Station</label><br> \
<label><input id=\"blockdet_flagspeedlimit\" type=\"checkbox\" value=\"\">Speed Limit</label><br> \
</td></tr></table> \
<table><tr> \
<td><label><input id=\"blockdet_flagoff\" type=\"checkbox\" value=\"\" disabled>Off Service</label></td> \
<td><label><input id=\"blockdet_flagonlycargo\" type=\"checkbox\" value=\"\">Only Cargo</label></td> \
<td><label><input id=\"blockdet_flagshort\" type=\"checkbox\" value=\"\">Short</label></td> \
</tr><tr> \
<td><label><input id=\"blockdet_flagend\" type=\"checkbox\" value=\"\">End</label></td> \
<td><label><input id=\"blockdet_flagonlypassenger\" type=\"checkbox\" value=\"\">Only Passenger</label></td> \
<td><label><input id=\"blockdet_flagsplit\" type=\"checkbox\" value=\"\">Split</label></td> \
</tr><tr> \
<td><label><input id=\"blockdet_flagspeedlimit\" type=\"checkbox\" value=\"\">Speed Limit</label></td> \
<td><label><input id=\"blockdet_flagstation\" type=\"checkbox\" value=\"\">Station</label></td> \
<td><label><input id=\"blockdet_flagsplitpos\" type=\"checkbox\" value=\"\">Splitpos</label></td> \
</tr><tr> \
<td></td><td>second block:</td><td>";
innerHTML += "<input id=\"blockdet_secondblock\" style=\"width: 100\">";
innerHTML += " \
</tr></table> \
\
</td><td></td></tr></table> \
<fieldset><legend>Automatic Mode</legend><table> \
<tr><td>Lockedby:</td><td><input id=\"blockdet_lockedby\" style=\"width: 100\" disabled></td></tr>\
<tr><td>Sensor &larr;&uarr;:</td><td><label><select id=\"blockdet_sensorLU\">";
innerHTML += "<option value=\"\"></option>";
for (var i = 0; i < sensors.length; i++) {
if (sensors[i].name)
innerHTML += "<option value=\""+sensors[i].name+"\">"+sensors[i].name+"</option>";
}
innerHTML += "</select></label></td></tr>\
<tr><td>Sensor Center:</td><td><label><select id=\"blockdet_sensorC\">";
innerHTML += "<option value=\"\"></option>";
for (var i = 0; i < sensors.length; i++) {
if (sensors[i].name)
innerHTML += "<option value=\""+sensors[i].name+"\">"+sensors[i].name+"</option>";
}
innerHTML += "</select></label></td></tr>\
<tr><td>Sensor &rarr;&darr;:</td><td><label><select id=\"blockdet_sensorRD\">";
innerHTML += "<option value=\"\"></option>";
for (var i = 0; i < sensors.length; i++) {
if (sensors[i].name)
innerHTML += "<option value=\""+sensors[i].name+"\">"+sensors[i].name+"</option>";
}
innerHTML += "</select></label></td></tr>\
</table></fileset>\
<tr><td>Lockedby:</td><td><input id=\"blockdet_lockedby\" style=\"width: 100\" disabled></td></tr>"
innerHTML += "<table><tr><td></td><td>enter</td><td>slow</td><td>shortstop</td><td>stop</td></tr>";
innerHTML += "<tr><td>Direction &rarr;&darr;:</td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_enter_0\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_slow_0\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_shortstop_0\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_stop_0\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "</tr>";
innerHTML += "<tr><td>Direction &larr;&uarr;:</td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_enter_1\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_slow_1\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_shortstop_1\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "<td align=center><label><select id=\"blockdet_sensor_stop_1\">" + blockdetail_fillsensor() + "</select></label></td>";
innerHTML += "</tr></table>";
innerHTML += "</td></tr></table></fileset>\
</div> <hr>\
<div align=right> \
<button id=\"blockdet_SAVE\" type=\"button\">Save</button> \
@ -244,10 +267,10 @@ function blockdetail_show(name, create) {
</div> \
\
";
debug ("blockdetail_show");
console.log ("blockdetail_show");
if (!win) {
debug ("blockdetail_show create window");
console.log ("blockdetail_show create window");
win = gWindowCreate("blockdetail", "Block", 500, 400, innerHTML);
gAddEventListener("blockdet_CLOSE", 'click', blockdetail_cb_close);
@ -321,7 +344,7 @@ function blockdetail_cb_next () {
if (i == cursel) blockdetail_setData(blocks[i]);
}
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
// console.log ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
};
@ -344,7 +367,7 @@ function blockdetail_cb_prev () {
if (i == cursel) blockdetail_setData(blocks[i]);
}
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
// console.log ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
};
@ -355,26 +378,44 @@ function blockdetail_setData(elm) {
var name = document.getElementById("blockdet_name");
var flagoff = document.getElementById("blockdet_flagoff");
var flagshort = document.getElementById("blockdet_flagshort");
var flaglong = document.getElementById("blockdet_flaglong");
var flagsplit = document.getElementById("blockdet_flagsplit");
var flagsplitpos = document.getElementById("blockdet_flagsplitpos");
var flagend = document.getElementById("blockdet_flagend");
var flagonlycargo = document.getElementById("blockdet_flagonlycargo");
var flagonlypassenger = document.getElementById("blockdet_flagonlypassenger");
var flagstation = document.getElementById("blockdet_flagstation");
var flagspeedlimit = document.getElementById("blockdet_flagspeedlimit");
var sensorLU = document.getElementById("blockdet_sensorLU");
var sensorC = document.getElementById("blockdet_sensorC");
var sensorRD = document.getElementById("blockdet_sensorRD");
var sensor_enter_0 = document.getElementById("blockdet_sensor_enter_0");
var sensor_slow_0 = document.getElementById("blockdet_sensor_slow_0");
var sensor_stop_0 = document.getElementById("blockdet_sensor_stop_0");
var sensor_shortstop_0 = document.getElementById("blockdet_sensor_shortstop_0");
var sensor_enter_1 = document.getElementById("blockdet_sensor_enter_1");
var sensor_slow_1 = document.getElementById("blockdet_sensor_slow_1");
var sensor_stop_1 = document.getElementById("blockdet_sensor_stop_1");
var sensor_shortstop_1 = document.getElementById("blockdet_sensor_shortstop_1");
var lockedby = document.getElementById("blockdet_lockedby");
var secondblock = document.getElementById("blockdet_secondblock");
if (elm) {
if (name) name.value = elm.name;
if (flagoff) flagoff.checked = Number(elm.flags) & BLOCK_F_OFF;
if (flagshort) flagshort.checked = Number(elm.flags) & BLOCK_F_SHORT;
if (flaglong) flaglong.checked = Number(elm.flags) & BLOCK_F_LONG;
if (flagsplit) flagsplit.checked = Number(elm.flags) & BLOCK_F_SPLIT;
if (flagsplitpos) flagsplitpos.checked = Number(elm.flags) & BLOCK_F_SPLITPOS;
if (flagend) flagend.checked = Number(elm.flags) & BLOCK_F_ENDSTATION;
if (flagonlycargo) flagonlycargo.checked = Number(elm.flags) & BLOCK_F_ONLYCARGO;
if (flagonlypassenger) flagonlypassenger.checked = Number(elm.flags) & BLOCK_F_ONLYPASSENGER;
if (flagstation) flagstation.checked = Number(elm.flags) & BLOCK_F_STATION;
if (flagspeedlimit) flagspeedlimit.checked = Number(elm.flags) & BLOCK_F_SPEEDLIMIT;
if (sensorLU) sensorLU.value = elm.sensor_pos_1;
if (sensorC) sensorC.value = elm.sensor_center;
if (sensorRD) sensorRD.value = elm.sensor_neg_1;
if (sensor_enter_0) sensor_enter_0.value = elm.sensor_enter_0;
if (sensor_slow_0) sensor_slow_0.value = elm.sensor_slow_0;
if (sensor_stop_0) sensor_stop_0.value = elm.sensor_stop_0;
if (sensor_shortstop_0) sensor_shortstop_0.value = elm.sensor_shortstop_0;
if (sensor_enter_1) sensor_enter_1.value = elm.sensor_enter_1;
if (sensor_slow_1) sensor_slow_1.value = elm.sensor_slow_1;
if (sensor_stop_1) sensor_stop_1.value = elm.sensor_stop_1;
if (sensor_shortstop_1) sensor_shortstop_1.value = elm.sensor_shortstop_1;
if (secondblock) secondblock.value = elm.secondblock;
if (lockedby) lockedby.value = elm.lockedby;
}
};
@ -389,30 +430,63 @@ function blockdetail_getData() {
var name = document.getElementById("blockdet_name");
var flagoff = document.getElementById("blockdet_flagoff");
var flagshort = document.getElementById("blockdet_flagshort");
var flaglong = document.getElementById("blockdet_flaglong");
var flagsplit = document.getElementById("blockdet_flagsplit");
var flagsplitpos = document.getElementById("blockdet_flagsplitpos");
var flagend = document.getElementById("blockdet_flagend");
var flagonlycargo = document.getElementById("blockdet_flagonlycargo");
var flagonlypassenger = document.getElementById("blockdet_flagonlypassenger");
var flagstation = document.getElementById("blockdet_flagstation");
var flagspeedlimit = document.getElementById("blockdet_flagspeedlimit");
var sensorLU = document.getElementById("blockdet_sensorLU");
var sensorC = document.getElementById("blockdet_sensorC");
var sensorRD = document.getElementById("blockdet_sensorRD");
var sensor_enter_0 = document.getElementById("blockdet_sensor_enter_0");
var sensor_slow_0 = document.getElementById("blockdet_sensor_slow_0");
var sensor_stop_0 = document.getElementById("blockdet_sensor_stop_0");
var sensor_shortstop_0 = document.getElementById("blockdet_sensor_shortstop_0");
var sensor_enter_1 = document.getElementById("blockdet_sensor_enter_1");
var sensor_slow_1 = document.getElementById("blockdet_sensor_slow_1");
var sensor_stop_1 = document.getElementById("blockdet_sensor_stop_1");
var sensor_shortstop_1 = document.getElementById("blockdet_sensor_shortstop_1");
var secondblock = document.getElementById("blockdet_secondblock");
if (name) res.name = name.value;
if (flagoff.checked) res.flags |= BLOCK_F_OFF;
else res.flags &= ~BLOCK_F_OFF;
if (flagshort.checked) res.flags |= BLOCK_F_SHORT;
else res.flags &= ~BLOCK_F_SHORT;
if (flaglong.checked) res.flags |= BLOCK_F_LONG;
else res.flags &= ~BLOCK_F_LONG;
if (flagsplit.checked) res.flags |= BLOCK_F_SPLIT;
else res.flags &= ~BLOCK_F_SPLIT;
if (flagsplitpos.checked) res.flags |= BLOCK_F_SPLITPOS;
else res.flags &= ~BLOCK_F_SPLITPOS;
if (flagend.checked) res.flags |= BLOCK_F_ENDSTATION;
else res.flags &= ~BLOCK_F_ENDSTATION;
if (flagonlycargo.checked) res.flags |= BLOCK_F_ONLYCARGO;
else res.flags &= ~BLOCK_F_ONLYCARGO;
if (flagonlypassenger.checked) res.flags |= BLOCK_F_ONLYPASSENGER;
else res.flags &= ~BLOCK_F_ONLYPASSENGER;
if (flagstation.checked) res.flags |= BLOCK_F_STATION;
else res.flags &= ~BLOCK_F_STATION;
if (flagspeedlimit.checked) res.flags |= BLOCK_F_SPEEDLIMIT;
else res.flags &= ~BLOCK_F_SPEEDLIMIT;
if (sensorLU) res.sensor_pos_1 = sensorLU.value;
if (sensorC) res.sensor_center = sensorC.value;
if (sensorRD) res.sensor_neg_1 = sensorRD.value;
if (sensor_enter_0) res.sensor_enter_0 = sensor_enter_0.value;
if (sensor_slow_0) res.sensor_slow_0 = sensor_slow_0.value;
if (sensor_stop_0) res.sensor_stop_0 = sensor_stop_0.value;
if (sensor_shortstop_0) res.sensor_shortstop_0 = sensor_shortstop_0.value;
if (sensor_enter_1) res.sensor_enter_1 = sensor_enter_1.value;
if (sensor_slow_1) res.sensor_slow_1 = sensor_slow_1.value;
if (sensor_stop_1) res.sensor_stop_1 = sensor_stop_1.value;
if (sensor_shortstop_1) res.sensor_shortstop_1 = sensor_shortstop_1.value;
if (secondblock) res.secondblock = secondblock.value;
return res;
};

@ -91,7 +91,7 @@ button {
input {
border: 1px solid var(--input-bg-color);
border: 1px solid var(--input-fg-color);
background-color: var(--input-bg-color);
color: var(--input-fg-color);
font-family: "Lucida Console", Courier, monospace;

@ -6,7 +6,7 @@ var MousePosY = null;
//
// init all variables with the class givin
$(document).ready(function() {
// debug ("init");
// console.log ("init");
$(".GUIwindow").each( function (i) {
gWindowDragElement(this);
@ -65,7 +65,7 @@ function gContextmenuCreate(title, clientInnerHTML) {
parent.removeChild(cm);
}
debug("create Contextmenu:" + title);
console.log("create Contextmenu:" + title);
var head = document.createElement("div");
head.setAttribute("id", "ConextMenuHead");
@ -88,6 +88,9 @@ function gContextmenuCreate(title, clientInnerHTML) {
cm.style.top = getMouseY();
cm.style.left = getMouseX();
if (parseInt(cm.style.left) + 150 > window.innerWidth) cm.style.left = window.innerWidth - 150;
if (parseInt(cm.style.top) + 400 > window.innerHeight) cm.style.top = window.innerHeight - 400;
return cm;
};

@ -1,9 +0,0 @@
function debug (t) {
var pre = document.getElementById("debug");
var div = document.getElementById("debug_div");
if (pre) pre.innerHTML = pre.innerHTML + "<br>" + t;
if (div) div.scrollTop = div.scrollHeight;
};

@ -77,7 +77,7 @@ function gWindowDragElement(elmnt) {
function gWindowCreate(id, title, sizex, sizey, clientHTML) {
var win = document.getElementById(id);
if (!win) {
debug("create Title:" + title);
console.log("create Title:" + title);
var head = document.createElement("div");
head.setAttribute("id", id+"Head");
@ -98,7 +98,7 @@ function gWindowCreate(id, title, sizex, sizey, clientHTML) {
document.body.appendChild(win);
gWindowDragElement(win);
debug ("move to 100px from top");
console.log ("move to 100px from top");
win.style.top = "100px";
}
return win;
@ -108,7 +108,7 @@ function gWindowCreate(id, title, sizex, sizey, clientHTML) {
function gWindowCreateSize(id, title, sizex, sizey) {
var win = document.getElementById(id);
if (!win) {
debug("create Title:" + title);
console.log("create Title:" + title);
var head = document.createElement("div");
head.setAttribute("id", id+"Head");
@ -129,7 +129,7 @@ function gWindowCreateSize(id, title, sizex, sizey) {
win.appendChild (client);
document.body.appendChild(win);
gWindowDragElement(win);
debug ("move to 100px from top");
console.log ("move to 100px from top");
win.style.top = "100px";
}
return win;

@ -3,7 +3,6 @@
<head>
<title>Modelbahn</title>
<script src="jquery-3.1.0.min.js"></script>
<script src="gui/guidebug.js"></script>
<script src="gui/guiwindow.js"></script>
<script src="gui/gui.js"></script>
<script src="serverinout.js"></script>
@ -28,7 +27,6 @@
</button>
<div class="dropdown-content">
<a href="#" onclick="serverinout_Save(this);">Save</a>
<a href="#" onclick="debug_Enable(this);">Debug</a>
</div>
</div>
<div class="dropdown">
@ -86,24 +84,8 @@
<div class="page_main" id="page_main"></div>
<div class="page_bottom" id="debug_div">
<pre id="debug"></pre>
</div>
<script>
function debug_Enable() {
var x = document.getElementById("debug_div");
if (x.style.display === "none") {
$(':root').css('--bottom-height', '256px');
x.style.display = "block";
} else {
$(':root').css('--bottom-height', '0px');
x.style.display = "none";
}
}
$(document).ready(function() {
var client = document.getElementById("page_main");

@ -10,7 +10,7 @@ var interfaces = [];
function interface_Update(intdata) {
for (var i = 0; i < interfaces.length; i++) {
if (intdata.name == interfaces[i].name) {
//debug ("Update Interface:" + interfaces[i].name + "(" + interfaces[i].host + ") with Interface:" + intdata.name + "(" + intdata.host + ")");
console.log ("Update Interface:" + interfaces[i].name + "(" + interfaces[i].host + ") with Interface:" + intdata.name + "(" + intdata.host + ") Flags:" + intdata.flags);
if (!(intdata.flags & 0x0001)) sideBtnOnOffMode (3); // not connected
else if ((intdata.flags & 0x0010)) sideBtnOnOffMode (3); // programming mode
@ -28,7 +28,7 @@ function interface_Update(intdata) {
}
// not found add element
//debug ("Add Interface:" + intdata.name + "(" + intdata.host + ")");
//console.log ("Add Interface:" + intdata.name + "(" + intdata.host + ")");
interfaces.push ({
name: intdata.name,
host: intdata.host,
@ -80,10 +80,10 @@ function interface_server_Del(elm) {
function intdetail_show(intname) {
var win = document.getElementById("intdetail");
debug ("intdetail_show");
console.log ("intdetail_show");
if (!win) {
debug ("intdetail_show create window");
console.log ("intdetail_show create window");
win = gWindowCreate("intdetail", "Interface", 400, 300, " \
<div style=\"float: left\"> \
Interface Name: <input id=\"intdet_name\" style=\"width: 100\"> \
@ -181,7 +181,7 @@ function intdetail_cb_next () {
if (i == cursel) intdetail_setData(interfaces[i]);
}
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
// console.log ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
};
@ -204,7 +204,7 @@ function intdetail_cb_prev () {
if (i == cursel) intdetail_setData(interfaces[i]);
}
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
// console.log ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
};

@ -5,9 +5,9 @@ body {
}
:root {
--top-height: 34px;
--top-height: 35px;
--side-width: 37px;
--bottom-height: 2px;
--bottom-height: 0px;
--menu-bg-color: #333;
--menu-fg-color: linen;
@ -33,6 +33,8 @@ body {
--turnout-other: #666;
--sensor-active: #0F0;
--sensor-inactive: #666;
--button-active: #0F0;
--button-inactive: #666;
}
.page_side {

@ -7,8 +7,9 @@ const LOCO_F_CARGO = 0x0010;
const LOCO_F_CANREVERSE = 0x0020;
const LOCO_F_SHORTTRAIN = 0x0040;
const LOCO_F_AUTO = 0x0100;
const LOCO_F_RANDOM = 0x0200;
const LOCO_F_AUTOSTOP = 0x0400;
const LOCO_F_AUTOSHED = 0x0200;
const LOCO_F_AUTORANDOM = 0x0400;
const LOCO_F_AUTOSTOP = 0x0800;
var locomotives = [];
@ -19,7 +20,9 @@ var locomotives = [];
function locomotive_Update(data) {
for (var i = 0; i < locomotives.length; i++) {
if (data.name == locomotives[i].name) {
debug ("Update Locomotive:" + locomotives[i].name + " with Locomotive:" + data.name);
var loco_name = document.getElementById("locodet_name");
console.log ("Update Locomotive:" + locomotives[i].name + " with Locomotive:" + data.name);
locomotives[i].name = data.name;
locomotives[i].ifname = data.ifname;
locomotives[i].addr = data.addr;
@ -32,18 +35,25 @@ function locomotive_Update(data) {
locomotives[i].vmax = data.vmax;
locomotives[i].flags = data.flags;
if (data.blockassign) locomotives[i].blockassign = data.blockassign;
else locomotives[i].blockassign = "";
if (data.blockprev) locomotives[i].blockprev = data.blockprev;
else locomotives[i].blockprev = "";
if (data.blocknext) locomotives[i].blocknext = data.blocknext;
else locomotives[i].blocknext = "";
if (data.blockdest) locomotives[i].blockdest = data.blockdest;
else locomotives[i].blockdest = "";
if (data.schedway) locomotives[i].schedway = data.schedway;
else locomotives[i].schedway = "";
if (data.auto_way) locomotives[i].auto_way = data.auto_way;
locodetail_setData(locomotives[i]);
if (loco_name == data.name) locodetail_setData(locomotives[i]);
lococtrl_setData(data);
return;
}
}
// not found add element
debug ("Add Locomotive:" + data.name);
console.log ("Add Locomotive:" + data.name);
locomotives.push ({
name: data.name,
ifname: data.ifname,
@ -60,6 +70,7 @@ function locomotive_Update(data) {
blockdest: data.blockdest,
blocknext: data.blocknext,
blockprev: data.blockprev,
schedway: data.schedway,
auto_way: data.auto_way
});
@ -136,11 +147,11 @@ function locomotive_server_Set(elm) {
function locodetail_show(loconame) {
var win = document.getElementById("locodetail");
debug ("locodetail_show");
console.log ("locodetail_show");
if (!win) {
debug ("loco_showdetail create window");
win = gWindowCreate("locodetail", "Locomotive", 450, 500,
console.log ("loco_showdetail create window");
win = gWindowCreate("locodetail", "Locomotive", 450, 550,
"<div style=\"float: left\"> \
Name: <input id=\"locodet_name\" style=\"width: 100\"> \
</div> <div style=\"float: right\"> \
@ -153,15 +164,17 @@ function locodetail_show(loconame) {
Flags: <input id=\"locodet_flags\" style=\"width: 50\"> \
</div> <hr>\
<div><table><tr><td> \
<table><tr><td> \
<label><input id=\"locodet_auto\" type=\"checkbox\" value=\"\" disabled>Auto</label><br> \
<label><input id=\"locodet_random\" type=\"checkbox\" value=\"\" disabled>Random</label><br> \
<label><input id=\"locodet_autoshed\" type=\"checkbox\" value=\"\" disabled>Sheduler</label><br> \
<label><input id=\"locodet_autorandom\" type=\"checkbox\" value=\"\" disabled>Random</label><br> \
</td><td> \
<label><input id=\"locodet_cargo\" type=\"checkbox\" value=\"\">Cargo</label><br> \
<label><input id=\"locodet_short\" type=\"checkbox\" value=\"\">Short Train</label><br> \
<label><input id=\"locodet_canreverse\" type=\"checkbox\" value=\"\">Can Reverse</label><br> \
</td></tr></table> \
</td><td> \
<label><input id=\"locodet_cargo\" type=\"checkbox\" value=\"\">Cargo</label><br> \
</td></tr></table></div> \
\
<div> <table><tr><td> \
<fieldset><legend>Speed</legend> <table>\
<label><input id=\"locodet_reverse\" type=\"checkbox\" value=\"\">Reverse</label><br> \
<tr><td></td><td>Stop</td><td><button id=\"locodet_btnvstop\" type=\"button\" value=\"vstop\">X</button> </td></tr>\
@ -189,7 +202,13 @@ function locodetail_show(loconame) {
</table><button id=\"locodet_RESET\" type=\"button\">Reset</button> \
<button id=\"locodet_TEST\" type=\"button\">Test</button></fileset>\
\
</td></tr></table></div> <hr>\
</td></tr></table></div> \
\
<table><tr><td> \
Sched. Way: <input id=\"locodet_schedway\" style=\"width: 250\" placeholder=\"B:+:B13,W:30,B:-:B42,W:15\"> \
</td></tr></table> \
\
<hr>\
<div align=right> \
<button id=\"locodet_SAVE\" type=\"button\">Save</button> \
<button id=\"locodet_DELETE\" type=\"button\">Delete</button> \
@ -226,7 +245,7 @@ function locodetail_show(loconame) {
//
// load default values
var res = { name: "", ifname: "", addr: "", flags: 0, steps: "",
vmin: "20", vslow: "40", vmid:"60", vfast:"80", vmax:"100" };
vmin: "20", vslow: "40", vmid:"60", vfast:"80", vmax:"100", schedway: "" };
locodetail_setData(res);
if (loconame) {
@ -344,7 +363,7 @@ function locodetail_cb_btnmove () {
}
locomotive_server_Set ({name: loco_name.value, speed: speed});
debug ("Locomotive: '" + loco_name.value +"' Speed: " + speed);
console.log ("Locomotive: '" + loco_name.value +"' Speed: " + speed);
};
@ -398,7 +417,7 @@ function locodetail_cb_next () {
if (i == cursel) locodetail_setData(locomotives[i]);
}
debug ("Cursel: " + cursel + " locomotives.lenght:" + locomotives.length);
console.log ("Cursel: " + cursel + " locomotives.lenght:" + locomotives.length);
};
@ -421,7 +440,7 @@ function locodetail_cb_prev () {
if (i == cursel) locodetail_setData(locomotives[i]);
}
debug ("Cursel: " + cursel + " locomotives.lenght:" + locomotives.length);
console.log ("Cursel: " + cursel + " locomotives.lenght:" + locomotives.length);
};
@ -444,12 +463,14 @@ function locodetail_setData(elm) {
var loco_short = document.getElementById("locodet_short");
var loco_cargo = document.getElementById("locodet_cargo");
var loco_auto = document.getElementById("locodet_auto");
var loco_random = document.getElementById("locodet_random");
var loco_autorandom = document.getElementById("locodet_autorandom");
var loco_autoshed = document.getElementById("locodet_autoshed");
var loco_blockassign = document.getElementById("locodet_blockassign");
var loco_blockdest = document.getElementById("locodet_blockdest");
var loco_blocknext = document.getElementById("locodet_blocknext");
var loco_blockprev = document.getElementById("locodet_blockprev");
var loco_auto_way = document.getElementById("locodet_auto_way");
var loco_schedway = document.getElementById("locodet_schedway");
if (elm) {
if (loco_name) loco_name.value = elm.name;
@ -482,21 +503,27 @@ function locodetail_setData(elm) {
if (Number(elm.flags) & LOCO_F_AUTO) loco_auto.checked = true;
else loco_auto.checked = false;
}
if (loco_random) {
if (Number(elm.flags) & LOCO_F_RANDOM) loco_random.checked = true;
else loco_random.checked = false;
if (loco_autorandom) {
if (Number(elm.flags) & LOCO_F_AUTORANDOM) loco_autorandom.checked = true;
else loco_autorandom.checked = false;
}
if (loco_autoshed) {
if (Number(elm.flags) & LOCO_F_AUTOSHED) loco_autoshed.checked = true;
else loco_autoshed.checked = false;
}
if (loco_blockassign) loco_blockassign.value = elm.blockassign;
if (loco_blockdest) loco_blockdest.value = elm.blockdest;
if (loco_blocknext) loco_blocknext.value = elm.blocknext;
if (loco_blockprev) loco_blockprev.value = elm.blockprev;
if (loco_schedway && elm.schedway) loco_schedway.value = elm.schedway;
else if (loco_shedway) loco_schedway.value = "";
if (loco_auto_way) loco_auto_way.value = elm.auto_way;
}
var codes = document.getElementsByName('STEPCODE');
for(var i = 0; i < codes.length; i++) {
// debug ("STEPCODE: elm.stepcode: " + elm.stepcode + " i:" + i + " codes[i].value: " + codes[i].value + " codes.id: " + codes[i].id);
// console.log ("STEPCODE: elm.stepcode: " + elm.stepcode + " i:" + i + " codes[i].value: " + codes[i].value + " codes.id: " + codes[i].id);
if(elm.stepcode == codes[i].value) codes[i].checked = true;
else codes[i].checked = false;
}
@ -509,7 +536,7 @@ function locodetail_setData(elm) {
//
function locodetail_getData() {
var res = { name: "", ifname: "", addr: "", flags: 0, stepcode:"0",
vmin: "20", vslow: "40", vmid:"60", vfast:"80", vmax:"100" };
vmin: "20", vslow: "40", vmid:"60", vfast:"80", vmax:"100", schedway: "" };
var codes = document.getElementsByName('STEPCODE');
for(var i = 0; i < codes.length; i++){
@ -528,6 +555,7 @@ function locodetail_getData() {
var loco_vfast = document.getElementById("locodet_vfast");
var loco_vmax = document.getElementById("locodet_vmax");
var loco_speed = document.getElementById("locodet_speed");
var loco_schedway = document.getElementById("locodet_schedway");
if (loco_name) res.name = loco_name.value;
if (loco_ifname) res.ifname = loco_ifname.value;
@ -539,6 +567,7 @@ function locodetail_getData() {
if (loco_vfast) res.vfast = loco_vfast.value;
if (loco_vmax) res.vmax = loco_vmax.value;
if (loco_speed) res.speed = loco_speed.speed;
if (loco_schedway) res.schedway = loco_schedway.value;
return res;
};
@ -553,10 +582,10 @@ function locodetail_getData() {
function locolist_show() {
var win = document.getElementById("locolist");
debug ("locolist_show");
console.log ("locolist_show");
if (!win) {
debug ("locolist_show create window");
console.log ("locolist_show create window");
win = gWindowCreate("locolist", "Locomotives", 400, 500, " \
<div id=\"locolist_listdiv\"> \
<ul id=\"locolist_elements\" style=\"list-style-type:none\"></ul> \
@ -595,7 +624,7 @@ function locolist_show() {
function locolist_clicked() {
var i;
debug ("childnodes: " + this.childNodes[0].textContent);
console.log ("childnodes: " + this.childNodes[0].textContent);
lococtrl_show(this.childNodes[0].textContent);
};
@ -620,10 +649,10 @@ function lococtrl_show(name) {
var win = document.getElementById("lococtrl_"+name);
var i;
debug ("lococtrl_show:" + name);
console.log ("lococtrl_show:" + name);
if (!win) {
debug ("locolist_show create window");
console.log ("locolist_show create window");
win = gWindowCreate("lococtrl_"+name, "Loco:"+name, 600, 600, " \
<table><tr><td> \
<fieldset><legend>Speed</legend><table><tr><td align=center>\
@ -648,13 +677,16 @@ function lococtrl_show(name) {
<td><button id=\"lococtrl_"+name+"_btnman\" type=\"button\" value=\"vstop\">MAN</button></td> \
</tr><tr> \
<td align=center><input id=\"lococtrl_"+name+"_cbstopman\" type=\"checkbox\" value=\"\" disabled></td>\
<td><button id=\"lococtrl_"+name+"_btnstopman\" type=\"button\" value=\"vstop\">A&lArr;M</button></td> \
<td><button id=\"lococtrl_"+name+"_btnstopman\" type=\"button\" value=\"vstop\">A&rArr;M</button></td> \
</tr><tr> \
<td align=center><input id=\"lococtrl_"+name+"_cbauto\" type=\"checkbox\" value=\"\" disabled></td>\
<td><button id=\"lococtrl_"+name+"_btnauto\" type=\"button\" value=\"vstop\">AUTO</button></td> \
</tr><tr> \
<td align=center><input id=\"lococtrl_"+name+"_cbrand\" type=\"checkbox\" value=\"\" disabled></td>\
<td><button id=\"lococtrl_"+name+"_btnrand\" type=\"button\" value=\"vstop\">RAND</button></td> \
<td align=center><input id=\"lococtrl_"+name+"_cbautoshed\" type=\"checkbox\" value=\"\" disabled></td>\
<td><button id=\"lococtrl_"+name+"_btnautoshed\" type=\"button\" value=\"vstop\">SHED</button></td> \
</tr><tr> \
<td align=center><input id=\"lococtrl_"+name+"_cbautorand\" type=\"checkbox\" value=\"\" disabled></td>\
<td><button id=\"lococtrl_"+name+"_btnautorand\" type=\"button\" value=\"vstop\">RAND</button></td> \
</tr> \
</table></fieldset> \
</td><tr></table>\
@ -675,7 +707,8 @@ function lococtrl_show(name) {
gAddEventListener("lococtrl_"+name+"_btnman", 'click', lococtrl_cb_btnman);
gAddEventListener("lococtrl_"+name+"_btnstopman", 'click', lococtrl_cb_btnstopman);
gAddEventListener("lococtrl_"+name+"_btnauto", 'click', lococtrl_cb_btnauto);
gAddEventListener("lococtrl_"+name+"_btnrand", 'click', lococtrl_cb_btnrand);
gAddEventListener("lococtrl_"+name+"_btnautorand", 'click', lococtrl_cb_btnautorand);
gAddEventListener("lococtrl_"+name+"_btnautoshed", 'click', lococtrl_cb_btnautoshed);
gAddEventListener("lococtrl_"+name+"_RANGE", 'click', lococtrl_speed);
gAddEventListener("lococtrl_"+name+"_REVBTN", 'click', lococtrl_reverse);
@ -688,11 +721,13 @@ function lococtrl_show(name) {
};
function lococtrl_cb_btnreset() {
var name = getTextBetween(this.id, "lococtrl_", "_btnreset");
var request = { command: "locomotivereset", locomotive: name };
serverinout (request, serverinout_defaultCallback);
request = { command: "locomotivesetman", locomotive: name };
serverinout (request, serverinout_defaultCallback);
};
@ -717,13 +752,20 @@ function lococtrl_cb_btnauto() {
};
function lococtrl_cb_btnrand() {
var name = getTextBetween(this.id, "lococtrl_", "_btnauto");
function lococtrl_cb_btnautorand() {
var name = getTextBetween(this.id, "lococtrl_", "_btnautorand");
var request = { command: "locomotivesetautorand", locomotive: name };
serverinout (request, serverinout_defaultCallback);
};
function lococtrl_cb_btnautoshed() {
var name = getTextBetween(this.id, "lococtrl_", "_btnautoshed");
var request = { command: "locomotivesetautoshed", locomotive: name };
serverinout (request, serverinout_defaultCallback);
};
function lococtrl_reverse() {
var name = getTextBetween(this.id, "lococtrl_", "_REVBTN");
var reverse;
@ -764,7 +806,7 @@ function lococtrl_cb_btnmove () {
if (reverse.innerHTML == "REV") speed = 0 - speed;
locomotive_server_Set ({name: name, speed: speed});
debug ("Locomotive: '" + name +"' Speed: " + speed);
console.log ("Locomotive: '" + name +"' Speed: " + speed);
};
@ -775,7 +817,7 @@ function lococtrl_speed() {
let speed = this.value;
if (reverse.innerHTML == "REV") speed = 0 - speed;
debug ("Speed Loco:'"+name+"' Speed:'"+speed+"'");
console.log ("Speed Loco:'"+name+"' Speed:'"+speed+"'");
for (var i = 0; i < locomotives.length; i++) {
if (name == locomotives[i].name) {
locomotive_server_Set ({name: name, speed: speed});
@ -788,19 +830,48 @@ function lococtrl_setData(data) {
var range = document.getElementById("lococtrl_"+data.name+"_RANGE");
var reverse = document.getElementById("lococtrl_"+data.name+"_REVBTN");
var cbauto = document.getElementById("lococtrl_"+data.name+"_cbauto");
var cbrand = document.getElementById("lococtrl_"+data.name+"_cbrand");
var cbautorand = document.getElementById("lococtrl_"+data.name+"_cbautorand");
var cbautoshed = document.getElementById("lococtrl_"+data.name+"_cbautoshed");
var cbmanstop = document.getElementById("lococtrl_"+data.name+"_cbstopman");
var btnman = document.getElementById("lococtrl_"+data.name+"_btnman");
var btnautostop = document.getElementById("lococtrl_"+data.name+"_btnstopman");
var btnauto = document.getElementById("lococtrl_"+data.name+"_btnauto");
var btnautorand = document.getElementById("lococtrl_"+data.name+"_btnautorand");
var btnautoshed = document.getElementById("lococtrl_"+data.name+"_btnautoshed");
if (range && reverse) {
debug ("lococtrl: " + data.name + " speed:" + data.speed + " vmax:" +
console.log ("lococtrl: " + data.name + " speed:" + data.speed + " vmax:" +
data.vmax + " flags:" + data.flags);
if (data.flags & LOCO_F_REVERSE) reverse.innerHTML = "REV";
else reverse.innerHTML = "FWD";
cbauto.checked = (data.flags & LOCO_F_AUTO);
cbrand.checked = (data.flags & LOCO_F_RANDOM);
cbautorand.checked = (data.flags & LOCO_F_AUTORANDOM);
cbautoshed.checked = (data.flags & LOCO_F_AUTOSHED);
cbmanstop.checked = (data.flags & LOCO_F_AUTOSTOP);
if (data.flags & LOCO_F_AUTOSTOP) {
btnman.disabled = false;
btnauto.disabled = true;
btnautorand.disabled = true;
btnautoshed.disabled = true;
btnautostop.disabled = true;
}
else if (data.flags & LOCO_F_AUTO) {
btnman.disabled = true;
btnautorand.disabled = false;
btnautoshed.disabled = false;
btnautostop.disabled = false;
}
else {
btnman.disabled = true;
btnautorand.disabled = true;
btnautostop.disabled = true;
btnautoshed.disabled = true;
btnauto.disabled = false;
}
range.min = 0;
if (data.vmax) range.max = data.vmax;
range.value = Math.abs(Number(data.speed));
@ -809,7 +880,7 @@ function lococtrl_setData(data) {
function lococtrl_close() {
debug ("LocoCtrl_close:" + this.value);
console.log ("LocoCtrl_close:" + this.value);
var win = document.getElementById("lococtrl_"+this.value);
if (win) document.body.removeChild(win);

@ -2,20 +2,32 @@
//
//
const RAILWAY_T_NOTHING = 0;
const RAILWAY_T_NORMAL = 1;
const RAILWAY_T_CROSSING = 2;
const RAILWAY_T_TURNOUT = 3;
const RAILWAY_T_SENSOR = 4;
const RAILWAY_T_CONNECTOR = 5;
const RAILWAY_T_BUTTON = 6;
const RAILWAY_T_TEXT = 7;
const RAILWAY_T_BLOCK = 8;
const TURNOUT_F_INVERSE = 1;
const TURNOUT_F_MOTORACTIVE = 2;
const TURNOUT_F_OUTPUTACTIVE = 2;
const TURNOUT_F_TURNOUT = 4;
const TURNOUT_F_ISRELAIS = 8;
function rwdetail_requestcallback(response) {
debug ("rwdetail_requestcallback");
console.log ("rwdetail_requestcallback");
};
function rwdetail_request(posx, posy) {
var request = {locoid: locoID, parameter1: -1, name:"Otto"};
debug ("rwdetail_request");
console.log ("rwdetail_request");
serverinout(request, rwdetail_requestcallback);
};
@ -23,10 +35,10 @@ function rwdetail_request(posx, posy) {
function rwdetail_show(posx, posy) {
var win = document.getElementById("rwdetail");
debug ("rwdetail_show");
console.log ("rwdetail_show");
if (!win) {
debug ("rwdetail_show create window");
console.log ("rwdetail_show create window");
win = gWindowCreate("rwdetail", "Railway", 400, 500, " \
<div style=\"float: left\"> \
Position: <input id=\"rwdet_X\" style=\"width: 50\" value=\"" + posx +"\"> , <input id=\"rwdet_Y\" style=\"width: 50\" value=\"" + posy +"\"> \
@ -89,10 +101,15 @@ function rwdetail_show(posx, posy) {
y.value = posy;
}
console.log ("rwdetail_show track dimensions: " + track.size.x + "," + track.size.y + " Position: " + posx + "," + posy + " idx:" + (posx + posy * track.size.x));
rwdetail_setData({type: 0, x: posx, y: posy, dir: 0, altdir: 0, name: ""});
if (track.elements[posx + posy * track.size.x]) {
console.log ("rwdetail_show element found.");
rwdetail_setData(track.elements[posx + posy * track.size.x]);
}
else console.log ("rwdetail_show element NOT found.");
};
@ -100,13 +117,13 @@ function rwdetail_cb_gotoref () {
var type = document.getElementById("rwdet_type");
var name = document.getElementById("rwdet_name");
debug ("Name:" + name.value + " Type:" + type.value);
console.log ("Name:" + name.value + " Type:" + type.value);
switch(Number(type.value)) {
case 3: turndetail_show(name.value, true); break; // turnout
case 4: sensordetail_show(name.value, true); break; // sensor
case 5: break; // connector
case 8: blockdetail_show(name.value, true); break; // block
case RAILWAY_T_BUTTON: turndetail_show(name.value, true); break; // button
case RAILWAY_T_TURNOUT: turndetail_show(name.value, true); break; // turnout
case RAILWAY_T_SENSOR: sensordetail_show(name.value, true); break; // sensor
case RAILWAY_T_BLOCK: blockdetail_show(name.value, true); break; // block
default: break;
}
};
@ -218,10 +235,23 @@ function rw_Click(x,y) {
var idx = x + y * track.size.x;
if (track.elements[idx]) {
//
// Button or Turnout?
if (track.elements[idx].type == RAILWAY_TURNOUT || track.elements[idx].type == RAILWAY_BUTTON) {
// Turnout?
if (track.elements[idx].type == RAILWAY_TURNOUT) {
if (track.elements[idx].name != "") {
if (turnout_IsTurnoutActive(track.elements[idx].name)) {
turnout_server_Activate(track.elements[idx].name, 0);
}
else {
turnout_server_Activate(track.elements[idx].name, 1);
}
}
}
//
// Button
else if (track.elements[idx].type == RAILWAY_T_BUTTON) {
if (track.elements[idx].name != "") {
if (turnout_IsActive(track.elements[idx].name)) {
if (turnout_IsOutputActive(track.elements[idx].name)) {
turnout_server_Activate(track.elements[idx].name, 0);
}
else {
@ -234,6 +264,7 @@ function rw_Click(x,y) {
// Sensor
else if (track.elements[idx].type == RAILWAY_SENSOR) {
if (track.elements[idx].name != "") {
sensor_contextmenu(track.elements[idx].name);
}
}
@ -283,7 +314,7 @@ var turnouts = [];
function turnout_Update(data) {
for (var i = 0; i < turnouts.length; i++) {
if (data.name == turnouts[i].name) {
debug ("Update turnout:" + turnouts[i].name + " with turnout:" + data.name);
console.log ("Update turnout:" + turnouts[i].name + " with turnout:" + data.name + " Flags:" + data.flags);
turnouts[i].name = data.name;
turnouts[i].ifname = data.ifname;
turnouts[i].addr = data.addr;
@ -293,7 +324,7 @@ function turnout_Update(data) {
}
// not found add element
debug ("Add turnout:" + data.name);
console.log ("Add turnout:" + data.name + " Flags:" + data.flags);
turnouts.push ({
name: data.name,
ifname: data.ifname,
@ -306,7 +337,7 @@ function turnout_Update(data) {
//
// return if the turnout is active or not
//
function turnout_IsActive(name) {
function turnout_IsTurnoutActive(name) {
for (var i = 0; i < turnouts.length; i++) {
if (name == turnouts[i].name) {
if (turnouts[i].flags & TURNOUT_F_TURNOUT) return 1
@ -317,6 +348,17 @@ function turnout_IsActive(name) {
};
function turnout_IsOutputActive(name) {
for (var i = 0; i < turnouts.length; i++) {
if (name == turnouts[i].name) {
if (turnouts[i].flags & TURNOUT_F_OUTPUTACTIVE) return 1
else return 0;
}
}
return 0;
}
//
// delete element from the list
// in arrays we can not delete just an element, so we create a new one
@ -367,10 +409,10 @@ function turnout_server_Activate(name, onoff) {
function turndetail_show(turnname, create) {
var win = document.getElementById("turndetail");
debug ("turndetail_show");
console.log ("turndetail_show");
if (!win) {
debug ("turndetail_show create window");
console.log ("turndetail_show create window");
win = gWindowCreate("turndetail", "Turnout", 400, 500, " \
<div style=\"float: left\"> \
Name: <input id=\"turndet_name\" style=\"width: 100\"> \
@ -384,6 +426,8 @@ function turndetail_show(turnname, create) {
<tr><td>Flags:</td><td><input id=\"turndet_flags\" style=\"width: 50\"></td></tr> \
</table> </td><td> \
<label><input id=\"turndet_inverse\" type=\"checkbox\" value=\"\"> Inverse</label><br>\
<label><input id=\"turndet_output\" type=\"checkbox\" value=\"\"> Output Active</label><br>\
<label><input id=\"turndet_relais\" type=\"checkbox\" value=\"\"> Is Relais</label><br>\
<label><input id=\"turndet_active\" type=\"checkbox\" value=\"\"><dfn title=\"save first\"> Active</dfn></label>\
\
</td></tr></table></div> <hr>\
@ -397,6 +441,8 @@ function turndetail_show(turnname, create) {
gAddEventListener("turndet_inverse", 'click', turndetail_cb_inverse);
gAddEventListener("turndet_active", 'click', turndetail_cb_active);
gAddEventListener("turndet_output", 'click', turndetail_cb_output);
gAddEventListener("turndet_relais", 'click', turndetail_cb_relais);
gAddEventListener("turndet_CLOSE", 'click', turndetail_cb_close);
gAddEventListener("turndet_DELETE", 'click', turndetail_cb_delete);
@ -456,6 +502,34 @@ function turndetail_cb_active () {
};
//
// output
function turndetail_cb_output () {
var cb = document.getElementById("turndet_output");
var flags = document.getElementById("turndet_flags");
var name = document.getElementById("turndet_name");
if (cb.checked)
flags.value = Number(flags.value) | TURNOUT_F_OUTPUTACTIVE;
else
flags.value = Number(flags.value) & (0xFFFF-TURNOUT_F_OUTPUTACTIVE);
};
//
// isrelais
function turndetail_cb_relais () {
var cb = document.getElementById("turndet_relais");
var flags = document.getElementById("turndet_flags");
var name = document.getElementById("turndet_name");
if (cb.checked)
flags.value = Number(flags.value) | TURNOUT_F_ISRELAIS;
else
flags.value = Number(flags.value) & (0xFFFF-TURNOUT_F_ISRELAIS);
};
function turndetail_cb_close () {
var win = document.getElementById("turndetail");
@ -506,7 +580,7 @@ function turndetail_cb_next () {
if (i == cursel) turndetail_setData(turnouts[i]);
}
// debug ("Cursel: " + cursel + " turnouts.lenght:" + turnouts.length);
// console.log ("Cursel: " + cursel + " turnouts.lenght:" + turnouts.length);
};
@ -529,7 +603,7 @@ function turndetail_cb_prev () {
if (i == cursel) turndetail_setData(turnouts[i]);
}
// debug ("Cursel: " + cursel + " turnouts.lenght:" + turnouts.length);
// console.log ("Cursel: " + cursel + " turnouts.lenght:" + turnouts.length);
};
@ -543,6 +617,8 @@ function turndetail_setData(elm) {
var turnflags = document.getElementById("turndet_flags");
var cbinverse = document.getElementById("turndet_inverse");
var cbactive = document.getElementById("turndet_active");
var cbrelais = document.getElementById("turndet_relais");
var cboutput = document.getElementById("turndet_output");
if (elm) {
if (turnname) turnname.value = elm.name;
@ -550,13 +626,21 @@ function turndetail_setData(elm) {
if (turnaddr) turnaddr.value = elm.addr;
if (turnflags) turnflags.value = elm.flags;
if (cbinverse) {
if (Number(elm.flags) & 1) cbinverse.checked = true;
if (Number(elm.flags) & TURNOUT_F_INVERSE) cbinverse.checked = true;
else cbinverse.checked = false;
}
if (cbactive) {
if (Number(elm.flags) & 2) cbactive.checked = true;
if (Number(elm.flags) & TURNOUT_F_TURNOUT) cbactive.checked = true;
else cbactive.checked = false;
}
if (cboutput) {
if (Number(elm.flags) & TURNOUT_F_OUTPUTACTIVE) cboutput.checked = true;
else cboutput.checked = false;
}
if (cbrelais) {
if (Number(elm.flags) & TURNOUT_F_ISRELAIS) cbrelais.checked = true;
else cbrelais.checked = false;
}
}
};

@ -14,7 +14,7 @@ var sensors = [];
function sensor_Update(sdata) {
for (var i = 0; i < sensors.length; i++) {
if (sdata.name == sensors[i].name) {
debug ("Update Sensor:" + sensors[i].name + " with Sensor:" + sdata.name);
console.log ("Update Sensor:" + sensors[i].name + " with Sensor:" + sdata.name);
sensors[i].name = sdata.name;
sensors[i].ifname = sdata.ifname;
sensors[i].addr = sdata.addr;
@ -24,7 +24,7 @@ function sensor_Update(sdata) {
}
// not found add element
debug ("Add Sensor:" + sdata.name);
console.log ("Add Sensor:" + sdata.name);
sensors.push ({
name: sdata.name,
ifname: sdata.ifname,
@ -88,14 +88,13 @@ function sensor_IsActive(name) {
function sensordetail_show(name, create) {
var win = document.getElementById("sensordetail");
debug ("sensordetail_show");
console.log ("sensordetail_show");
if (!win) {
debug ("sensordetail_show create window");
console.log ("sensordetail_show create window");
win = gWindowCreate("sensordetail", "Sensor", 400, 300, " \
<div style=\"float: left\"> \
Sensor Name: <input id=\"sensor_name\" style=\"width: 100\"> \
@ -188,7 +187,7 @@ function sensordetail_cb_next () {
if (i == cursel) sensordetail_setData(sensors[i]);
}
debug ("Cursel: " + cursel + " sensors.lenght:" + sensors.length);
console.log ("Cursel: " + cursel + " sensors.lenght:" + sensors.length);
};
@ -211,7 +210,7 @@ function sensordetail_cb_prev () {
if (i == cursel) sensordetail_setData(sensors[i]);
}
debug ("Cursel: " + cursel + " sensors.lenght:" + sensors.length);
console.log ("Cursel: " + cursel + " sensors.lenght:" + sensors.length);
};
@ -262,10 +261,10 @@ function sensordetail_getData() {
function sensorlist_show() {
var win = document.getElementById("sensorlist");
debug ("sensorlist_show");
console.log ("sensorlist_show");
if (!win) {
debug ("sensorlist_show create window");
console.log ("sensorlist_show create window");
win = gWindowCreate("sensorlist", "Sensors", 400, 500, " \
<div id=\"sensorlist_listdiv\"> \
<ul id=\"sensorlist_elements\" style=\"list-style-type:none\"></ul> \
@ -306,7 +305,7 @@ function sensorlist_show() {
function sensorlist_clicked() {
var i;
debug ("childnodes: " + this.childNodes[0].textContent);
console.log ("childnodes: " + this.childNodes[0].textContent);
sensordetail_show(this.childNodes[0].textContent);
};
@ -320,3 +319,54 @@ function sensorlist_cb_close () {
// ***********************************************************************************************
// ***********************************************************************************************
// sensor contextmenu: show a context menu for the sensor
// this is only if the INTERFACE name is set tu DEBUG
// ***********************************************************************************************
// ***********************************************************************************************
function sensor_contextmenu(name) {
let innerhtml = "";
for (var i = 0; i < sensors.length; i++) {
if (name == sensors[i].name) {
if (sensors[i].ifname == "DEBUG") {
innerhtml = "<center>";
innerhtml += "<button id=\"contextbox_On\" type=\"button\">Set On</button><br>";
innerhtml += "<button id=\"contextbox_Off\" type=\"button\">Set Off</button><br>";
innerhtml += "<button id=\"contextbox_Close\" type=\"button\">Close</button></center>";
gContextmenuCreate(name, innerhtml);
gAddEventListener("contextbox_On", 'click', sensor_ctxmenu_On);
gAddEventListener("contextbox_Off", 'click', sensor_ctxmenu_Off);
gAddEventListener("contextbox_Close", 'click', gContextmenuClose);
}
}
}
};
function sensor_ctxmenu_On (element, value) {
let name = document.getElementById("ConextMenuHead").innerHTML;
sensor_server_setactive(name, "1");
gContextmenuClose();
}
function sensor_ctxmenu_Off (element, value) {
let name = document.getElementById("ConextMenuHead").innerHTML;
sensor_server_setactive(name, "0");
gContextmenuClose();
}
//
// send sensor activate and deactivate to server
//
function sensor_server_setactive(name, value) {
var request = { command: "sensorSetActive", sensor: name, enabled: value };
console.log ("send sensor active:" + name);
serverinout (request, serverinout_defaultCallback);
};

@ -24,18 +24,14 @@ function serverinout(request, callback) {
request.sid = sessionID;
request.rid = randomID;
// e.preventDefault();
senddata = JSON.stringify(request);
// debug('serverinout: send request:' + senddata);
$.ajax({
type: "POST",
// url: '/modelbahn/serverinout.php',
url: '/cgi-bin/modelbahn-cgi',
data: senddata,
success: function(response)
{
var jsonData = {};
// ENABLE LATER try {
jsonData = JSON.parse(response);
if (jsonData.success == "1")
{
@ -48,10 +44,6 @@ function serverinout(request, callback) {
var clientstatus = document.getElementById("infoclient");
clientstatus.innerHTML = "-trying-";
}
// ENABLE LATER } catch(err) {
// ENABLE LATER var serverstatus = document.getElementById("infoserver");
// ENABLE LATER serverstatus.innerHTML = "-error-";
// ENABLE LATER }
},
error: function(error) {
var status = document.getElementById("infoclient");
@ -92,7 +84,6 @@ function serverinout_Save(data) {
function serverinout_defaultCallback(data) {
// if (data.changes) if (data.changes.length > 0) debug ("From Server :" + JSON.stringify(data));
if (data.sid && data.rid) {
//
// valid data from server
@ -114,7 +105,7 @@ function serverinout_defaultCallback(data) {
//
// Infoline changes
if (data.changes[i].infoline) {
debug ("Info:" + data.changes[i].infoline);
console.log ("Info:" + data.changes[i].infoline);
}
//
@ -190,7 +181,7 @@ function serverinout_defaultCallback(data) {
}
}
if (data.changes[i].block) {
debug ("update Block:"+ data.changes[i].block.name + " Flags:" + data.changes[i].block.flags);
console.log ("update Block:"+ data.changes[i].block.name + " Flags:" + data.changes[i].block.flags);
block_Update(data.changes[i].block);
}
if (data.changes[i].blockdelete) {
@ -206,17 +197,16 @@ function serverinout_defaultCallback(data) {
else if (data.rid == randomID && data.sid > 0) {
// we got a new sessionID --> request track data
if (sessionID == 0) {
debug ("setup session ID");
sessionID = data.sid;
serverinout( {command: "getall" }, serverinout_defaultCallback);
}
}
else {
debug ("ERROR: serverinout_defaultCallback");
console.log ("ERROR: serverinout_defaultCallback");
}
}
else {
debug ("ERROR: serverinout_defaultCallback no data.sid && data.rid");
console.log ("ERROR: serverinout_defaultCallback no data.sid && data.rid");
}
};
@ -230,7 +220,7 @@ function serverinout_AutoUpdateCallback(data) {
function serverinout_AutoUpdate() {
// debug ("serverinout_AutoUpdate");
// console.log ("serverinout_AutoUpdate");
if (request_running == 0) {
request_running = 0;
serverinout({}, serverinout_defaultCallback);

@ -1,4 +1,8 @@
<?php
/*
* This code is not used anymore. PHP is just too slow. We went back to the cgi-bin interface
*/
session_start();

@ -11,7 +11,7 @@ function side_Display(type) {
var side_normal = document.getElementById("side_normalbuttons");
var btn = document.getElementById("cmd-none");
debug ("side_display(" + type +")");
console.log ("side_display(" + type +")");
if (type == SIDE_DISPLAY_EDITTRACK) {
side_normal.style.display = "none";

@ -3,7 +3,7 @@
//
function testwinbtnclick() {
debug ("Test Button");
console.log ("Test Button");
locodetail_show("");
}

@ -19,9 +19,13 @@ var track = {
elements: []
};
// trackMouse.step = 0 normal
// trackMouse.step = 1 destination
var trackMouse = {
pos: {x: -1, y: -1, subx: 0.5, suby: 0.5},
down: {x :-1 , y: -1, subx: 0.5, suby: 0.5}
down: {x :-1 , y: -1, subx: 0.5, suby: 0.5},
rect: {x1: -1, x2: -1, y1: -1, y2: -1},
step: 0
};
@ -119,8 +123,8 @@ function trackDrawElement(ctx, element, mode) {
var dir = element.dir;
var altdir = element.altdir;
if (element.name != "") if (turnout_IsActive(element.name)) {
// debug ("draw element:" + element.name + " isActive:" + turnout_IsActive(element.name));
if (element.name != "") if (turnout_IsTurnoutActive(element.name)) {
// console.log ("draw element:" + element.name + " isActive:" + turnout_IsActive(element.name));
altdir = element.dir;
dir = element.altdir;
}
@ -137,6 +141,26 @@ function trackDrawElement(ctx, element, mode) {
trackDrawTrack (ctx, {x: element.x, y: element.y}, altdir);
}
else if (element.type == RAILWAY_BUTTON) {
let bi;
ctx.beginPath();
ctx.lineWidth = 2;
ctx.setLineDash([0,0]);
ctx.strokeStyle = cssVar('--button-inactive');
for (bi = 0; bi < turnouts.length; bi++) {
if (turnouts[bi].name == element.name) {
if ((turnouts[bi].flags & TURNOUT_F_OUTPUTACTIVE) != 0)
ctx.strokeStyle = cssVar('--button-active');
}
}
ctx.moveTo((element.x+0.1) * track.scale, (element.y+0.1) * track.scale);
ctx.lineTo((element.x+0.9) * track.scale, (element.y+0.1) * track.scale);
ctx.lineTo((element.x+0.9) * track.scale, (element.y+0.9) * track.scale);
ctx.lineTo((element.x+0.1) * track.scale, (element.y+0.9) * track.scale);
ctx.lineTo((element.x+0.1) * track.scale, (element.y+0.1) * track.scale);
ctx.stroke();
}
else if (element.type == RAILWAY_NORMAL || element.type == RAILWAY_SENSOR || element.type == RAILWAY_BLOCK) {
//
// normal
@ -269,7 +293,7 @@ function trackDrawBlock(ctx, blockelm) {
y1 = y1 + (blockelm.y) * track.scale;
y2 = y2 + (blockelm.y) * track.scale;
// debug ("Flags:" + Number(blockelm.flags) + " Res:" + (Number(blockelm.flags) & BLOCK_F_OFF));
// console.log ("Flags:" + Number(blockelm.flags) + " Res:" + (Number(blockelm.flags) & BLOCK_F_OFF));
if (block && Number(block.flags) & BLOCK_F_OFF) ctx.fillStyle = cssVar('--block-bg-closed');
else if (blockelm.lockedby && blockelm.lockedby != "") ctx.fillStyle = cssVar('--block-bg-locked');
else ctx.fillStyle = cssVar('--block-bg');
@ -359,7 +383,7 @@ function trackDraw() {
var elm = {};
var tmpblocks = new Array();
// debug ("trackDraw pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
// console.log ("trackDraw pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
// " down: " + trackMouse.down.x + "," + trackMouse.down.y);
@ -384,44 +408,6 @@ function trackDraw() {
}
tmpblocks.length = 0;
//
// draw down position
if (trackMouse.down.x >= 0) {
var p1 = {};
var p2 = {};
if (trackMouse.pos.x < trackMouse.down.x) {
p1.x = trackMouse.pos.x;
p2.x = trackMouse.down.x;
}
else {
p1.x = trackMouse.down.x;
p2.x = trackMouse.pos.x;
}
if (trackMouse.pos.y < trackMouse.down.y) {
p1.y = trackMouse.pos.y;
p2.y = trackMouse.down.y;
}
else {
p1.y = trackMouse.down.y;
p2.y = trackMouse.pos.y;
}
ctx.lineWidth = 1;
ctx.lineJoin="round";
ctx.miterLimit = 1;
ctx.setLineDash([2,2]);
ctx.strokeStyle = cssVar('--track-color-selectframe');
ctx.beginPath();
ctx.moveTo(0.5+(p1.x + 0) * track.scale, 0.5+(p1.y+0) * track.scale);
ctx.lineTo(0.5+(p2.x + 1) * track.scale, 0.5+(p1.y+0) * track.scale);
ctx.lineTo(0.5+(p2.x + 1) * track.scale, 0.5+(p2.y+1) * track.scale);
ctx.lineTo(0.5+(p1.x + 0) * track.scale, 0.5+(p2.y+1) * track.scale);
ctx.lineTo(0.5+(p1.x + 0) * track.scale, 0.5+(p1.y+0) * track.scale);
ctx.stroke();
}
//
// draw mouse cursor
ctx.lineWidth = 1;
@ -441,8 +427,8 @@ function trackDraw() {
// draw mouseselection
var mode = sideBtnCmdGet();
if ((mode == "cmd-track-rail" || mode == "cmd-track-delete") &&
trackMouse.down.x >= 0 && trackMouse.down.y >= 0) {
if (mode == "cmd-track-rail" || mode == "cmd-track-delete") {
if (trackMouse.down.x >= 0 && trackMouse.down.y >= 0) {
var selected = new Array();
selected.length = 0;
@ -454,14 +440,83 @@ function trackDraw() {
var infoline = document.getElementById("infoline");
if (infoline) infoline.innerHTML = trackMouse.direction;
}
}
//
// draw possible turnout
else if (mode == "cmd-track-turn") {
var t = trackGetTurnout({x: trackMouse.pos.x, y: trackMouse.pos.y});
else if (mode == "cmd-track-move") {
if (trackMouse.step == 0) {
// draw rectangle for selection
let x1, x2, y1, y2;
// sort position down < pos
if (trackMouse.pos.x > trackMouse.down.x) {
x1 = trackMouse.down.x;
x2 = trackMouse.pos.x;
}
else {
x2 = trackMouse.down.x;
x1 = trackMouse.pos.x;
}
if (trackMouse.pos.y > trackMouse.down.y) {
y1 = trackMouse.down.y;
y2 = trackMouse.pos.y;
}
else {
y2 = trackMouse.down.y;
y1 = trackMouse.pos.y;
}
else if (!mode == "cmd-track-none") alert("track.js: unknown mode:" + mode);
if (trackMouse.down.x >= 0) {
ctx.lineWidth = 1;
ctx.lineJoin="round";
ctx.miterLimit = 1;
ctx.setLineDash([2,2]);
ctx.strokeStyle = cssVar('--track-element-fgborder');
ctx.beginPath();
ctx.moveTo(0.5+(x1 + 0) * track.scale, 0.5+(y1+0) * track.scale);
ctx.lineTo(0.5+(x2 + 1) * track.scale, 0.5+(y1+0) * track.scale);
ctx.lineTo(0.5+(x2 + 1) * track.scale, 0.5+(y2+1) * track.scale);
ctx.lineTo(0.5+(x1 + 0) * track.scale, 0.5+(y2+1) * track.scale);
ctx.lineTo(0.5+(x1 + 0) * track.scale, 0.5+(y1+0) * track.scale);
ctx.stroke();
}
}
else if (trackMouse.step == 1) {
let dx = trackMouse.pos.x - trackMouse.down.x;
let dy = trackMouse.pos.y - trackMouse.down.y;
ctx.lineWidth = 1;
ctx.lineJoin="round";
ctx.miterLimit = 1;
ctx.setLineDash([2,2]);
ctx.strokeStyle = cssVar('--track-element-selectframe');
ctx.beginPath();
ctx.moveTo(0.5+(trackMouse.rect.x1 + 0) * track.scale, 0.5+(trackMouse.rect.y1+0) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x2 + 1) * track.scale, 0.5+(trackMouse.rect.y1+0) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x2 + 1) * track.scale, 0.5+(trackMouse.rect.y2+1) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x1 + 0) * track.scale, 0.5+(trackMouse.rect.y2+1) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x1 + 0) * track.scale, 0.5+(trackMouse.rect.y1+0) * track.scale);
ctx.stroke();
ctx.lineWidth = 1;
ctx.lineJoin="round";
ctx.miterLimit = 1;
ctx.setLineDash([1,1]);
ctx.strokeStyle = cssVar('--track-element-selectframe');
ctx.beginPath();
ctx.moveTo(0.5+(trackMouse.rect.x1 + dx + 0) * track.scale, 0.5+(trackMouse.rect.y1 + dy + 0) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x2 + dx + 1) * track.scale, 0.5+(trackMouse.rect.y1 + dy + 0) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x2 + dx + 1) * track.scale, 0.5+(trackMouse.rect.y2 + dy + 1) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x1 + dx + 0) * track.scale, 0.5+(trackMouse.rect.y2 + dy + 1) * track.scale);
ctx.lineTo(0.5+(trackMouse.rect.x1 + dx + 0) * track.scale, 0.5+(trackMouse.rect.y1 + dy + 0) * track.scale);
ctx.stroke();
}
}
else if (mode == "cmd-track-rail" || mode == "cmd-track-detail" || mode == "cmd-track-none" || mode == "cmd-none") {
}
else alert("track.js: unknown mode:" + mode);
//
// flip screen - double buffering
@ -504,7 +559,7 @@ function trackMousemove(event) {
var mode = sideBtnCmdGet();
trackMouse.pos = trackMouseGetPos(event);
// debug ("trackMousemove pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
// console.log ("trackMousemove pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
// " subx: " + trackMouse.pos.subx + " suby:" + trackMouse.pos.suby);
trackDraw();
@ -518,8 +573,11 @@ function trackMousedown(event) {
if (mode == "cmd-track-rail" || mode == "cmd-track-delete") {
trackMouse.down = trackMouseGetPos(event);
}
else if (mode == "cmd-track-move") {
if (trackMouse.step == 0) trackMouse.down = trackMouseGetPos(event);
}
// debug ("trackMousedown pos: " + tmp.x + "," + tmp.y + " subx: " + tmp.subx + " suby:" + tmp.suby);
// console.log ("trackMousedown pos: " + tmp.x + "," + tmp.y + " subx: " + tmp.subx + " suby:" + tmp.suby);
trackDraw();
};
@ -532,9 +590,10 @@ function trackMouseup(event) {
var mode = sideBtnCmdGet();
var tmp = trackMouseGetPos(event);
debug ("trackMouseup tmp: " + tmp.x + "," + tmp.y + " mode:" + mode);
debug ("trackMouseup down: " + trackMouse.down.x + "," + trackMouse.down.y);
debug ("trackMouseup pos: " + trackMouse.pos.x + "," + trackMouse.pos.y);
console.log ("trackMouseup tmp: " + tmp.x + "," + tmp.y + " mode:" + mode);
console.log ("trackMouseup down: " + trackMouse.down.x + "," + trackMouse.down.y);
console.log ("trackMouseup pos: " + trackMouse.pos.x + "," + trackMouse.pos.y);
console.log ("trackMouseup step: " + trackMouse.step);
gContextmenuClose();
@ -546,10 +605,14 @@ function trackMouseup(event) {
selected = trackGetElementList(trackMouse.down, trackMouse.pos, trackMouse.direction);
serverinout_addTrack(selected);
selected.length = 0;
trackMouse.down.x = -1;
trackMouse.down.y = -1;
}
else if (mode == "cmd-track-detail") {
rwdetail_show(trackMouse.pos.x, trackMouse.pos.y);
trackMouse.down.x = -1;
trackMouse.down.y = -1;
}
else if (mode == "cmd-track-delete") {
@ -579,23 +642,62 @@ function trackMouseup(event) {
ye = trackMouse.down.y;
}
debug ("delete: xs: " + xs + " , " + ys + " xe: " + xe + " , " + ye);
for (x = xs; x <= xe; x++) for (y = ys; y <= ye; y++) {
selected.push({x: x, y: y, dir: 1, type: 0});
}
serverinout_delTrack(selected);
selected.length = 0;
trackMouse.down.x = -1;
trackMouse.down.y = -1;
}
else if (mode == "cmd-track-move") {
if (trackMouse.step == 0) {
let x1, x2, y1, y2;
// sort position down < pos
if (trackMouse.pos.x > trackMouse.down.x) {
trackMouse.rect.x1 = trackMouse.down.x;
trackMouse.rect.x2 = trackMouse.pos.x;
}
else {
debug ("rw_Click was das?");
rw_Click(trackMouse.pos.x, trackMouse.pos.y);
trackMouse.rect.x2 = trackMouse.down.x;
trackMouse.rect.x1 = trackMouse.pos.x;
}
if (trackMouse.pos.y > trackMouse.down.y) {
trackMouse.rect.y1 = trackMouse.down.y;
trackMouse.rect.y2 = trackMouse.pos.y;
}
else {
trackMouse.rect.y2 = trackMouse.down.y;
trackMouse.rect.y1 = trackMouse.pos.y;
}
trackMouse.step = 1;
trackMouse.down = trackMouse.pos;
}
else if (trackMouse.step == 1) {
//
// move railways
let dx = trackMouse.pos.x - trackMouse.down.x;
let dy = trackMouse.pos.y - trackMouse.down.y;
trackMoveArea(trackMouse.rect, dx, dy);
trackMouse.step = 0;
trackMouse.down.x = -1;
trackMouse.down.y = -1;
}
else {
trackMouse.step = 0;
}
}
else {
console.log ("rw_Click was das?");
rw_Click(trackMouse.pos.x, trackMouse.pos.y);
trackMouse.down.x = -1;
trackMouse.down.y = -1;
}
trackDraw();
};
@ -605,10 +707,10 @@ function trackMouseup(event) {
// add/or delete element
// fill in element
function trackAddElement(elm) {
// debug ("trackAddElement: pos:" + elm.x + "," + elm.y + " d: " + elm.dir + " name:" + elm.name + " type:" + elm.type);
// console.log ("trackAddElement: pos:" + elm.x + "," + elm.y + " d: " + elm.dir + " name:" + elm.name + " type:" + elm.type);
if (track.size.x > 0 && track.size.y > 0) {
track.elements[elm.x + track.size.y * elm.y] = elm;
track.elements[elm.x + track.size.x * elm.y] = elm;
}
};
@ -618,7 +720,7 @@ function trackAddElement(elm) {
// init the track view screen
// bind callback functions
function trackCreate(sizex, sizey) {
debug ("trackCreate " + sizex + " , " + sizey);
console.log ("trackCreate " + sizex + " , " + sizey);
var canvas = document.createElement("canvas");
track.size.x = sizex;
@ -644,7 +746,7 @@ function trackCreate(sizex, sizey) {
//
// get the size fo track from server, setup all data
function trackSetup(tracksetup) {
debug ("trackSetup");
console.log ("trackSetup");
var client = document.getElementById("page_main");
var oldc = document.getElementById("TrackCanvas");
@ -736,7 +838,7 @@ function trackGetElementList(start, end) {
}
else {
// should not possible but somehow we ended up here
debug ("trackGetElementList: ERROR elm 3 or 5 expected");
console.log ("trackGetElementList: ERROR elm 3 or 5 expected");
break;
}
}
@ -759,7 +861,7 @@ function trackGetElementList(start, end) {
}
else {
// should not possible but somehow we ended up here
debug ("trackGetElementList: ERROR elm 4 or 6 expected");
console.log ("trackGetElementList: ERROR elm 4 or 6 expected");
break;
}
}
@ -795,6 +897,7 @@ function trackGetElementList(start, end) {
return list;
};
//
// returns the element at the givin point
function trackGetTurnout(mousepos) {
@ -810,3 +913,40 @@ function trackGetTurnout(mousepos) {
return elm;
};
//
// trackMoveArea: moves an area from one to another place, it will overwrite the objects on this place.
//
function trackMoveArea (rect, dx, dy) {
let elmMove = new Array();
let elmDel = new Array();
let elm;
let x, y, idx;
if (dx == 0 && dy == 0) return;
for (x = rect.x1; x <= rect.x2; x++) for (y = rect.y1; y <= rect.y2; y++) {
idx = x + y * track.size.x;
elm = track.elements[idx];
if (!elm) {
elm = { x: x + dx,
y: y + dy,
type: RAILWAY_T_NOTHING,
dir: 0,
altdir: 0,
name: "" };
}
else {
elm.x = elm.x + dx;
elm.y = elm.y + dy;
}
elmMove.push (track.elements[idx]);
elm = {x: x, y: y};
elmDel.push (elm);
}
serverinout_delTrack(elmDel);
serverinout_addTrack(elmMove);
};

@ -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)

@ -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

@ -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<<EEWE)); // Wait for completion of previous write
EEAR = uiAddress; // Set up address and data registers
EEDR = ucData;
EECR |= (1<<EEMWE); // Write logical one to EEMWE
EECR |= (1<<EEWE); // Start eeprom write by setting EEWE
}
unsigned char EEPROM_read(unsigned int uiAddress) {
while(EECR & (1<<EEWE)); // Wait for completion of previous write
EEAR = uiAddress; // Set up address register
EECR |= (1<<EERE); // Start eeprom read by writing EERE
return EEDR; // return eeprom data register
}

@ -0,0 +1,18 @@
/*
* eprom.h
*
* Created on: 11.02.2018
* Author: steffen
*/
#ifndef EPROM_H_
#define EPROM_H_
#include <avr/io.h>
#include <avr/interrupt.h>
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char EEPROM_read(unsigned int uiAddress);
#endif /* ATMEGA8_DETECT_EPROM_H_ */

@ -0,0 +1,283 @@
/************************************************************
* 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 <avr/io.h>
#include <avr/interrupt.h>
#include <stdarg.h>
#include <stdio.h>
#include <util/delay.h>
#include <util/twi.h>
#include "eprom.h"
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
#define I2C_NUM_REGS 8
#define I2C_DEFAULT_ADDR 0x2F
#define VERSION 3
#define I2C_SREGS_OFFSET 0x20
enum {
I2C_SREG_VERSION = 0,
I2C_SREG_CMD,
I2C_SREG_ADDR,
I2C_SREG_DIOFFDELAY,
I2C_SREG_MAX
};
enum {
I2C_CMD_NONE = 0,
I2C_CMD_EEPROMREAD,
I2C_CMD_EEPROMWRITE
};
volatile uint8_t i2c_reg;
volatile uint8_t i2c_system[I2C_SREG_MAX];
volatile uint8_t i2c_regs[I2C_NUM_REGS];
//
// i2c slave addresse festlegen und interrupts einschalten
void i2c_slave_init(uint8_t adr) {
int i;
for (i = 0; i < I2C_NUM_REGS; i++) {
i2c_regs[i] = 0;
}
TWAR = adr << 1;
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
i2c_reg = 0x0;
sei();
}
ISR (TWI_vect) {
char data=0;
switch (TW_STATUS) {
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
TWCR_ACK;
i2c_reg=0xFF;
break;
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
data=TWDR;
if (i2c_reg == 0xFF) {
if(data < I2C_NUM_REGS || (data >= 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<<JTD);
MCUCSR |= (1<<JTD);
// enable inputs
DDRA = 0;
PORTA = 0xFF;
DDRB = 0;
PORTB = 0xFF;
DDRC = 0;
PORTC = 0xFF;
DDRD = 0;
PORTD = 0xFF;
//
// 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_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;
};

@ -0,0 +1,41 @@
# .SILENT:
# Atmega88
# CFLAGS= -Os -g -Wall -mmcu=atmega16 -DF_CPU=8000000UL
# LDFLAGS= -mmcu=atmega16
CPUTYPE1= atmega32
CPUTYPE2= m32
# Atmega32
CFLAGS= -Os -g -Wall -mmcu=$(CPUTYPE1) -DF_CPU=16000000UL
LDFLAGS= -mmcu=$(CPUTYPE1)
all: gleiserkennung-v4.bin
%.o: %.c
avr-gcc $(CFLAGS) -c -o $@ $^
rebuild: clean all
gleiserkennung-v4.elf: gleiserkennung-v4.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-v4: gleiserkennung-v4.bin
avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v4.bin:r

@ -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<<EEWE)); // Wait for completion of previous write
EEAR = uiAddress; // Set up address and data registers
EEDR = ucData;
EECR |= (1<<EEMWE); // Write logical one to EEMWE
EECR |= (1<<EEWE); // Start eeprom write by setting EEWE
}
unsigned char EEPROM_read(unsigned int uiAddress) {
while(EECR & (1<<EEWE)); // Wait for completion of previous write
EEAR = uiAddress; // Set up address register
EECR |= (1<<EERE); // Start eeprom read by writing EERE
return EEDR; // return eeprom data register
}

@ -0,0 +1,18 @@
/*
* eprom.h
*
* Created on: 11.02.2018
* Author: steffen
*/
#ifndef EPROM_H_
#define EPROM_H_
#include <avr/io.h>
#include <avr/interrupt.h>
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char EEPROM_read(unsigned int uiAddress);
#endif /* ATMEGA8_DETECT_EPROM_H_ */

@ -0,0 +1,281 @@
/******************************************************************
* reads some digital inputs and make them readable over i2c bus.
*
* Atmega 32
* +-------+
* S17 (XCK/T0) PB0 -|1 O 40|- PA0 (ADC0) S9
* S18 (T1) PB1 -|2 39|- PA1 (ADC1) S10
* S19 (INT2/AIN0) PB2 -|3 38|- PA2 (ADC2) S11
* S20 (OC0/AIN1) PB3 -|4 37|- PA3 (ADC3) S12
* S21 (SS) PB4 -|5 36|- PA4 (ADC4) S13
* S22 (MOSI) PB5 -|6 35|- PA5 (ADC5) S14
* S23 (MISO) PB6 -|7 34|- PA6 (ADC6) S15
* S24 (SCK) PB7 -|8 33|- PA7 (ADC7) S16
* RESET -|9 32|- AREF
* VCC -|10 31|- GND
* GND -|11 30|- AVCC
* XTAL2 -|12 29|- PC7 (TOSC2)
* XTAL1 -|13 28|- PC6 (TOSC1)
* S1 (RXD) PD0 -|14 27|- PC5 (TDI)
* S2 (TXD) PD1 -|15 26|- PC4 (TDO)
* S3 (INT0) PD2 -|16 25|- PC3 (TMS)
* S4 (INT1) PD3 -|17 24|- PC2 (TCK)
* S5 (OC1B) PD4 -|18 23|- PC1 (DSA) I2C
* S6 (OC1A) PD5 -|19 22|- PC0 (SCL) I2C
* S7 (ICP1) PD6 -|20 21|- PD7 (OC2) S8
* +-------+ */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdarg.h>
#include <stdio.h>
#include <util/delay.h>
#include <util/twi.h>
#include "eprom.h"
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
#define I2C_NUM_REGS 8
#define I2C_DEFAULT_ADDR 0x2F
#define VERSION 4
#define I2C_SREGS_OFFSET 0x20
enum {
I2C_SREG_VERSION = 0,
I2C_SREG_CMD,
I2C_SREG_ADDR,
I2C_SREG_DIOFFDELAY,
I2C_SREG_MAX
};
enum {
I2C_CMD_NONE = 0,
I2C_CMD_EEPROMREAD,
I2C_CMD_EEPROMWRITE
};
volatile uint8_t i2c_reg;
volatile uint8_t i2c_system[I2C_SREG_MAX];
volatile uint8_t i2c_regs[I2C_NUM_REGS];
//
// i2c slave addresse festlegen und interrupts einschalten
void i2c_slave_init(uint8_t adr) {
int i;
for (i = 0; i < I2C_NUM_REGS; i++) {
i2c_regs[i] = 0;
}
TWAR = adr << 1;
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
i2c_reg = 0x0;
sei();
}
ISR (TWI_vect) {
char data=0;
switch (TW_STATUS) {
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
TWCR_ACK;
i2c_reg=0xFF;
break;
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
data=TWDR;
if (i2c_reg == 0xFF) {
if(data < I2C_NUM_REGS || (data >= 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<<JTD);
MCUCSR |= (1<<JTD);
// enable inputs
DDRA = 0;
PORTA = 0xFF;
DDRB = 0;
PORTB = 0xFF;
DDRC = 0;
PORTC = 0xFF;
DDRD = 0;
PORTD = 0xFF;
//
// 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_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 - S8
i = 0; if (!(PINB & (1 << 0))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 1))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 2))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 3))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 4))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 5))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 6))) cnt[i] = offdelay;
i++; if (!(PINB & (1 << 7))) cnt[i] = offdelay;
// S9 - S16
i++; if (!(PINA & (1 << 0))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 1))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 2))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 3))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 4))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 5))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 6))) cnt[i] = offdelay;
i++; if (!(PINA & (1 << 7))) cnt[i] = offdelay;
// S17 - S24
i++; if (!(PIND & (1 << 0))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 1))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 2))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 3))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 4))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 5))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 6))) cnt[i] = offdelay;
i++; if (!(PIND & (1 << 7))) 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;
};

@ -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

@ -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<<EEWE)); // Wait for completion of previous write
EEAR = uiAddress; // Set up address and data registers
EEDR = ucData;
EECR |= (1<<EEMWE); // Write logical one to EEMWE
EECR |= (1<<EEWE); // Start eeprom write by setting EEWE
}
unsigned char EEPROM_read(unsigned int uiAddress) {
while(EECR & (1<<EEWE)); // Wait for completion of previous write
EEAR = uiAddress; // Set up address register
EECR |= (1<<EERE); // Start eeprom read by writing EERE
return EEDR; // return eeprom data register
}

@ -0,0 +1,18 @@
/*
* eprom.h
*
* Created on: 11.02.2018
* Author: steffen
*/
#ifndef EPROM_H_
#define EPROM_H_
#include <avr/io.h>
#include <avr/interrupt.h>
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char EEPROM_read(unsigned int uiAddress);
#endif /* ATMEGA8_DETECT_EPROM_H_ */

@ -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 <avr/io.h>
#include <avr/interrupt.h>
#include <stdarg.h>
#include <stdio.h>
#include <util/delay.h>
#include <util/twi.h>
#include "eprom.h"
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
#define I2C_NUM_REGS 8
#define I2C_DEFAULT_ADDR 0x4F
#define VERSION 1
#define I2C_SREGS_OFFSET 0x20
enum {
I2C_SREG_VERSION = 0,
I2C_SREG_CMD,
I2C_SREG_ADDR,
I2C_SREG_DIOFFDELAY,
I2C_SREG_DOOFFDELAY,
I2C_SREG_MAX
};
enum {
I2C_CMD_NONE = 0,
I2C_CMD_EEPROMREAD,
I2C_CMD_EEPROMWRITE
};
volatile uint8_t i2c_reg;
volatile uint8_t i2c_system[I2C_SREG_MAX];
volatile uint8_t i2c_regs[I2C_NUM_REGS];
//
// i2c slave addresse festlegen und interrupts einschalten
void i2c_slave_init(uint8_t adr) {
int i;
for (i = 0; i < I2C_NUM_REGS; i++) {
i2c_regs[i] = 0;
}
TWAR = adr << 1;
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
i2c_reg = 0x0;
sei();
}
ISR (TWI_vect) {
char data=0;
switch (TW_STATUS) {
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
TWCR_ACK;
i2c_reg=0xFF;
break;
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
data=TWDR;
if (i2c_reg == 0xFF) {
if(data < I2C_NUM_REGS || (data >= 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;
};

@ -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 <avr/io.h>
#include <avr/interrupt.h>
#include <stdarg.h>
#include <stdio.h>
#include <util/delay.h>
#include <util/twi.h>
#include "eprom.h"
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
#define I2C_NUM_REGS 8
#define VERSION 2
#define I2C_DEFAULT_ADDR 0x4F
#define I2C_SREGS_OFFSET 0x20
enum {
I2C_SREG_VERSION = 0,
I2C_SREG_CMD,
I2C_SREG_ADDR,
I2C_SREG_DIOFFDELAY,
I2C_SREG_DOOFFDELAY,
I2C_SREG_MAX
};
enum {
I2C_CMD_NONE = 0,
I2C_CMD_EEPROMREAD,
I2C_CMD_EEPROMWRITE
};
volatile uint8_t i2c_reg;
volatile uint8_t i2c_system[I2C_SREG_MAX];
volatile uint8_t i2c_regs[I2C_NUM_REGS];
//
// i2c slave addresse festlegen und interrupts einschalten
void i2c_slave_init(uint8_t adr) {
int i;
for (i = 0; i < I2C_NUM_REGS; i++) {
i2c_regs[i] = 0;
}
TWAR = adr << 1;
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
i2c_reg = 0x0;
sei();
}
ISR (TWI_vect) {
char data=0;
switch (TW_STATUS) {
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
TWCR_ACK;
i2c_reg=0xFF;
break;
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
data=TWDR;
if (i2c_reg == 0xFF) {
if(data < I2C_NUM_REGS || (data >= 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;
};

@ -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 <avr/io.h>
#include <avr/interrupt.h>
#include <stdarg.h>
#include <stdio.h>
#include <util/delay.h>
#include <util/twi.h>
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
#define I2C_NUM_REGS 8
volatile int i2c_reg;
volatile uint8_t i2c_inregs[I2C_NUM_REGS];
volatile uint8_t i2c_outregs[I2C_NUM_REGS];
//
// i2c slave addresse festlegen und interrupts einschalten
void i2c_slave_init(uint8_t adr) {
char i;
for (i = 0; i < I2C_NUM_REGS; i++) {
i2c_inregs[i] = i;
i2c_outregs[i] = i | 0x80;
}
TWAR = adr << 1;
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
i2c_reg = 0x0;
sei();
}
ISR (TWI_vect) {
char data=0;
switch (TW_STATUS) {
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
TWCR_ACK;
i2c_reg=0xFF;
break;
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
data=TWDR;
if (i2c_reg == 0xFF) {
if(data < I2C_NUM_REGS)
i2c_reg = data;
else
i2c_reg = 0; // FIXME: wrong address so start at register 0
TWCR_ACK;
}
else {
if(i2c_reg < I2C_NUM_REGS) {
i2c_inregs[i2c_reg] = data;
i2c_reg++;
}
TWCR_ACK;
}
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_outregs[i2c_reg];
// TWDR = 0xF3;
i2c_reg++;
}
else {
TWDR = 0; //Kein Daten mehr im Buffer
}
TWCR_ACK;
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;
}
}
/////////////////////////////////////////////////////////////////////////
//
#define OFFDELAY 0x2000;
int main( void ) {
long int cnt[8] = { 0 };
unsigned int i;
char inval = 0;
long int t;
// i2c benutzt PORTC bit5+C4
i2c_slave_init (0x30);
while( 1 ) {
if (PINB & 0x02) cnt[0] = OFFDELAY;
if (PINB & 0x04) cnt[1] = OFFDELAY;
if (PINC & 0x02) cnt[2] = OFFDELAY;
if (PINC & 0x01) cnt[3] = OFFDELAY;
if (PINB & 0x01) cnt[4] = OFFDELAY;
if (PIND & 0x80) cnt[5] = OFFDELAY;
if (PIND & 0x40) 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_outregs[1] = inval;
}
return 0;
};

@ -0,0 +1,45 @@
/*
* debug.cc
*
* Created on: 15.12.2017
* Author: steffen
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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");
};

@ -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_ */

@ -0,0 +1,105 @@
/*
* i2csensor.cc
*
* Created on: 18.12.2017
* Author: steffen
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#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;
};

@ -0,0 +1,31 @@
/*
* i2csensor.h
*
* Created on: 18.12.2017
* Author: steffen
*/
#ifndef I2CSENSOR_H_
#define I2CSENSOR_H_
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string>
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_ */

@ -0,0 +1,183 @@
/*
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h> /* close() */
#include <string.h> /* 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;
}

@ -0,0 +1,55 @@
#ifndef _SP_UDP_H_
#define _SP_UDP_H_
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#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

@ -0,0 +1,296 @@
#include <stdio.h>
#include <stdlib.h>
#include <string>
#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);
int debug = 0;
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], "-debug") == 0) {
debug = 1;
}
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)) {
if (debug) printf ("i2cloop: Read ADDR:%02x REG:%02x Value:%2x Error\n", rbus[index].i2c_addr, rbus[index].i2c_reg, rbus[index].status);
rbus[index].status = 0xFF; // error
}
else if (debug) {
printf ("i2cloop: Read ADDR:%02x REG:%02x Value:%2x\n", rbus[index].i2c_addr, rbus[index].i2c_reg, rbus[index].status);
}
}
}
//
// 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 || ver == 4) {
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 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", &reg);
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 (" -debug enabling debugging\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);
}

@ -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

@ -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];
extern int debug;
void xlan_turnout (int addr, bool enable);
#endif /* Z21EMU_H_ */

@ -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
:

@ -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<Z21Client*>::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);
};

@ -0,0 +1,58 @@
/*
* z21prot.h
*
* Created on: 15.12.2017
* Author: steffen
*/
#ifndef Z21PROT_H_
#define Z21PROT_H_
#include <list>
#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<Z21Client*> clients;
UDPConnection udp;
char buffer[NET_BUFFERSIZE];
public:
Z21Server ();
~Z21Server ();
int Loop(); // returns number of connections
void Start();
};
#endif /* Z21PROT_H_ */
Loading…
Cancel
Save