@ -0,0 +1,7 @@
|
||||
|
||||
2020-02-09:
|
||||
- Züge fahren falsch herrum
|
||||
- Speed und Fahrtrichtung werden nicht in den Zügen geupdated
|
||||
- Max Speed ist nicht gleich der Maximalste Step
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
|
||||
Dieses Programm wird nur von Steffen Pohle, Siegenburg verwendet und ist in einem Experimentellen Status.
|
||||
Sollte jemand dieses Programm verwenden, so tut er es auf eigene Verantwortung. Ich übernehme keine Haftung
|
||||
für Schäden durch die Software.
|
||||
|
||||
|
||||
Steffen Pohle <steffen@gulpe.de>
|
||||
9.2.2020, 93354 Siegenburg (Germany)
|
||||
|
@ -0,0 +1,11 @@
|
||||
|
||||
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.
|
||||
|
@ -0,0 +1,79 @@
|
||||
# .SILENT:
|
||||
|
||||
WEBUSER=www-data
|
||||
WEBGROUP=www-data
|
||||
VERSION=0.1
|
||||
PREFIX=/usr/local
|
||||
ETCPREFIX=/etc
|
||||
|
||||
DISTNAME=modelbahn
|
||||
|
||||
CXX=g++
|
||||
CXXFLAGS= -ggdb -fPIC -Wno-write-strings -g -ggdb -std=c++11
|
||||
LDFLAGS= -lm -lc -lpthread -L/usr/local/lib -g -ggdb
|
||||
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
|
||||
|
||||
CURDIR=`pwd`
|
||||
|
||||
all: dep $(TARGET) test-json modelbahn-cgi
|
||||
|
||||
modelbahn-server: $(SERVEROBJ)
|
||||
$(CXX) -o $@ $^ $(LDFLAGS_CGI) -lUDPTCPNetwork -L./ -I./ -lpthread
|
||||
|
||||
modelbahn-cgi: modelbahn-cgi.o debug.o
|
||||
$(CXX) -o $@ $^ $(LDFLAGS) -lUDPTCPNetwork -L./ -I./ -lpthread
|
||||
|
||||
test-json: json.o test-json.o debug.o
|
||||
$(CXX) -o $@ $^ $(LDFLAGS) -L./ -I./ -lpthread
|
||||
|
||||
install: $(TARGET)
|
||||
cp -f $(TARGET) $(PREFIX)/lib/
|
||||
|
||||
uninstall:
|
||||
rm -f $(PREFIX)/lib/$(TARGET)
|
||||
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
dep:
|
||||
$(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE)
|
||||
|
||||
clean:
|
||||
rm $(TARGET) -rf
|
||||
rm modelbahn-cgi -rf
|
||||
rm -rf gmon.out
|
||||
rm *.s -rf
|
||||
rm *.o -rf
|
||||
rm *.oo -rf
|
||||
rm *~ -rf
|
||||
rm -rf config.h
|
||||
rm -rf .depend
|
||||
rm -rf *.so
|
||||
rm -rf *.a
|
||||
rm -rf *.so.*
|
||||
|
||||
cleanall: clean
|
||||
|
||||
source: cleanall
|
||||
|
||||
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 ETCPREFIX \"$(ETCPREFIX)\"" >> config.h
|
||||
echo "" >> config.h
|
||||
echo "#endif" >> config.h
|
||||
|
||||
|
||||
-include $(DEPENDFILE)
|
||||
|
@ -0,0 +1,152 @@
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "block.h"
|
||||
|
||||
|
||||
Blocks::Blocks () {
|
||||
changed = 0;
|
||||
blocks = (Block*) malloc(sizeof(Block)*SENSORS_MAX);
|
||||
max = BLOCKS_MAX;
|
||||
};
|
||||
|
||||
Blocks::~Blocks() {
|
||||
free (blocks);
|
||||
blocks = NULL;
|
||||
max = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int Blocks::Lock() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
int Blocks::UnLock() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
JSONParse Blocks::_GetJSON(int idx) {
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
string s = "";
|
||||
|
||||
json.Clear();
|
||||
|
||||
s = blocks[idx].name; json.AddObject("name", s);
|
||||
json.AddObject("flags", blocks[idx].flags);
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
JSONParse Blocks::GetJSON(string name) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
jp.Clear();
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (blocks[i].name[0] != 0) {
|
||||
if (name.compare(blocks[i].name) == 0) {
|
||||
jp = _GetJSON(i);
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return jp;
|
||||
};
|
||||
|
||||
|
||||
void Blocks::GetJSONAll(JSONParse *json) {
|
||||
int i, cnt;
|
||||
JSONElement je;
|
||||
|
||||
Lock();
|
||||
|
||||
//
|
||||
// write all railway data
|
||||
// create json object array manualy
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "blocks";
|
||||
for (cnt = 0, i = 0; i < max; i++)
|
||||
if (blocks[i].name[0] != 0) {
|
||||
if (cnt != 0) je.value += ","; // not first element
|
||||
je.value += _GetJSON(i).ToString();
|
||||
cnt++;
|
||||
}
|
||||
json->AddObject(je);
|
||||
|
||||
UnLock();
|
||||
};
|
||||
|
||||
|
||||
Block Blocks::GetBlockFromJSON(JSONParse *j) {
|
||||
Block bl;
|
||||
string s;
|
||||
|
||||
bl.name[0] = 0;
|
||||
bl.flags = 0;
|
||||
|
||||
j->GetValue("name", &s);
|
||||
strncpy (bl.name, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValueInt("flags", &bl.flags);
|
||||
|
||||
return bl;
|
||||
};
|
||||
|
||||
|
||||
int Blocks::Change(Block *bl) {
|
||||
int i;
|
||||
int ifree = -1;
|
||||
|
||||
Lock();
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (blocks[i].name[0] != 0) {
|
||||
// found element
|
||||
if (strncmp(blocks[i].name, bl->name, REFERENCENAME_LEN) == 0) {
|
||||
ifree = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ifree == -1) ifree = i;
|
||||
}
|
||||
// element not found add new element
|
||||
if (ifree != -1 && ifree < max) {
|
||||
blocks[ifree] = *bl;
|
||||
strncpy (blocks[ifree].name, bl->name, REFERENCENAME_LEN);
|
||||
}
|
||||
|
||||
changed = 1;
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Blocks::Delete(string name) {
|
||||
int i;
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (blocks[i].name[0] != 0) {
|
||||
if (name.compare(blocks[i].name) == 0) {
|
||||
blocks[i].name[0] = 0;
|
||||
blocks[i].flags = 0;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
|
||||
#ifndef _BLOCK_H_
|
||||
#define _BLOCK_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
|
||||
#define BLOCKF_SHORTTRAIN 0x0001
|
||||
|
||||
struct s_Block {
|
||||
char name[REFERENCENAME_LEN];
|
||||
int flags;
|
||||
} typedef Block;
|
||||
|
||||
class Blocks {
|
||||
private:
|
||||
Block *blocks;
|
||||
int max;
|
||||
int changed;
|
||||
|
||||
pthread_mutex_t mtx;
|
||||
int Lock();
|
||||
int UnLock();
|
||||
|
||||
// not thread safe
|
||||
JSONParse _GetJSON(int idx);
|
||||
public:
|
||||
Blocks();
|
||||
~Blocks();
|
||||
|
||||
bool IsChanged() { return changed; }
|
||||
void ClearChanged() { changed = 0; };
|
||||
|
||||
int Change(Block *se);
|
||||
int Delete(string name);
|
||||
|
||||
JSONParse GetJSON(string name);
|
||||
void GetJSONAll(JSONParse *json);
|
||||
Block GetBlockFromJSON(JSONParse *j);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,56 @@
|
||||
|
||||
// #define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <execinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "modelbahn.h"
|
||||
|
||||
#define DEBUG_FILE "/tmp/modelbahn-server.log"
|
||||
int _debuglevel = 0xff;
|
||||
|
||||
pid_t gettid();
|
||||
|
||||
void debug (int type, char *fmt,...) {
|
||||
va_list args;
|
||||
char text1[DEBUG_TEXT1LEN];
|
||||
char text2[DEBUG_TEXT2LEN];
|
||||
pid_t pid = gettid();
|
||||
|
||||
va_start (args, fmt);
|
||||
vsnprintf (text1, (DEBUG_TEXT1LEN-1), fmt, args);
|
||||
va_end (args);
|
||||
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);
|
||||
|
||||
if (type == 0 || (type & _debuglevel) != 0) {
|
||||
FILE *f;
|
||||
printf ("%s\n", text2);
|
||||
f= fopen(DEBUG_FILE, "a");
|
||||
if (f) {
|
||||
fprintf (f, "%s\n", text2);
|
||||
fclose (f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************************
|
||||
* helper stuff
|
||||
*******************************************************************************************/
|
||||
|
||||
|
||||
//
|
||||
// return the current thread process id
|
||||
//
|
||||
pid_t gettid() {
|
||||
pid_t tid = 0;
|
||||
tid = syscall(SYS_gettid);
|
||||
return tid;
|
||||
};
|
@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#define DEBUG_INFO 0x0001
|
||||
#define DEBUG_ERROR 0x0002
|
||||
#define DEBUG_IFACE 0x0004
|
||||
#define DEBUG_NET 0x0008
|
||||
#define DEBUG_SESSION 0x0010
|
||||
#define DEBUG_SERVER 0x0020
|
||||
#define DEBUG_RAILWAY 0x0040
|
||||
#define DEBUG_LOCO 0x0080
|
||||
|
||||
#define DEBUG_TEXT1LEN 64000
|
||||
#define DEBUG_TEXT2LEN 65000
|
||||
|
||||
void debug(int type, char *fmt,...);
|
||||
|
||||
#endif // _DEBUG_H_
|
||||
|
||||
|
@ -0,0 +1,447 @@
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "interface.h"
|
||||
#include "interface-z21.h"
|
||||
|
||||
//
|
||||
// command and datasets for communication
|
||||
static unsigned char TX_X_SET_TRACK_POWER_ON[] { 0x07, 0x00, 0x40, 0x00, 0x21, 0x81, 0xa0 };
|
||||
static unsigned char TX_X_SET_TRACK_POWER_OFF[] { 0x07, 0x00, 0x40, 0x00, 0x21, 0x80, 0xa1 };
|
||||
|
||||
//
|
||||
// values to comapare for data
|
||||
static unsigned char RX_SYSTEMSTATE_DATACHANGED[] { 0x14, 0x00, 0x84, 0x00 };
|
||||
static unsigned char RX_GET_SERIAL_NUMBER[] { 0x08, 0x00, 0x10, 0x00 };
|
||||
static unsigned char RX_LOCONET_Z21_TX[] { 0x00, 0xa1, 0x00 }; // loconet dynamic length
|
||||
static unsigned char RX_X_GET_TURNOUT_INFO[] { 0x09, 0x00, 0x40, 0x00, 0x43 };
|
||||
static unsigned char RX_RMBUS_DATACHANGED[] { 0x0F, 0x00, 0x80, 0x00 };
|
||||
|
||||
//
|
||||
// locomotive values
|
||||
#define Z21_IDX_SETLOCO_DRIVE_SFMT 5
|
||||
#define Z21_IDX_SETLOCO_DRIVE_ADRH 6
|
||||
#define Z21_IDX_SETLOCO_DRIVE_ADRL 7
|
||||
#define Z21_IDX_SETLOCO_DRIVE_STEP 8
|
||||
#define Z21_IDX_SETLOCO_DRIVE_CHK 9
|
||||
|
||||
//
|
||||
// turnout values
|
||||
#define Z21_IDX_SETTURNOUT_ADRH 5
|
||||
#define Z21_IDX_SETTURNOUT_ADRL 6
|
||||
#define Z21_IDX_SETTURNOUT_MODE 7
|
||||
#define Z21_IDX_SETTURNOUT_CHK 8
|
||||
|
||||
InterfaceZ21::InterfaceZ21 () {
|
||||
status_connected = false;
|
||||
status_poweron = false;
|
||||
status_programmingmode = false;
|
||||
status_shortcircuit = false;
|
||||
status_emergencystop = false;
|
||||
|
||||
send_logon = false;
|
||||
|
||||
memset (rmsensors, 0x0, INTF_Z21_RMSENSOR_GROUPS * INTF_Z21_RMSENSOR_BYTES);
|
||||
rmsensorinit = 0;
|
||||
|
||||
serial = "";
|
||||
hostname = "";
|
||||
timeout = time(NULL);
|
||||
rmgetdatatimeout = time(NULL) - INTF_Z21_RMGETDATA_TIMEOUT;
|
||||
};
|
||||
|
||||
InterfaceZ21::~InterfaceZ21() {
|
||||
Disconnect();
|
||||
};
|
||||
|
||||
|
||||
void InterfaceZ21::Connect (string destination) {
|
||||
debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Connect to: %s", __FILE__, __LINE__, destination.c_str());
|
||||
|
||||
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)",
|
||||
__FILE__, __LINE__, strerror(errno));
|
||||
return;
|
||||
}
|
||||
udp.SetBlocked(1);
|
||||
timeout = time(NULL);
|
||||
send_SET_BROADCASTFLAGS();
|
||||
send_GET_SERIAL_NUMBER();
|
||||
status_connected = true;
|
||||
|
||||
for (int i = 0; i < INTF_Z21_LOCONET_MAXADDR; i++) {
|
||||
loconet_map[i] = { 0 , 0, 0, 0, 0};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// if connected, poweroff track and logoff from Z21 controller
|
||||
void InterfaceZ21::Disconnect() {
|
||||
if (status_connected) {
|
||||
PowerOnOff(0);
|
||||
send_LOGOFF();
|
||||
}
|
||||
udp.Close();
|
||||
|
||||
status_connected = false;
|
||||
status_poweron = false;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// check if we are connected and for timeouts.
|
||||
// read and go through incoming data
|
||||
int InterfaceZ21::Loop(string interfacename) {
|
||||
time_t curtime = time(NULL);
|
||||
string source;
|
||||
int inlen;
|
||||
int i;
|
||||
int update = false;
|
||||
|
||||
if (status_connected) {
|
||||
//
|
||||
// Z21 timed out? close all connection
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// rmgetdatatimeout?
|
||||
if (curtime - rmgetdatatimeout > INTF_Z21_RMGETDATA_TIMEOUT) {
|
||||
rmgetdatatimeout = curtime;
|
||||
send_RM_GETDATA(0);
|
||||
send_RM_GETDATA(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// check for incoming data
|
||||
if (status_connected) {
|
||||
if ((inlen = udp.ReadTimeout(&source, inbuffer, INTF_Z21_INBUFFER, 10)) > 0) {
|
||||
//
|
||||
// got some data
|
||||
|
||||
//
|
||||
// check for LAN_SYSTEMSTATE_DATACHANGED
|
||||
if (memcmp (inbuffer, RX_GET_SERIAL_NUMBER, sizeof(RX_GET_SERIAL_NUMBER)) == 0) {
|
||||
// got serial number... ignore this for now
|
||||
send_logon = false;
|
||||
}
|
||||
|
||||
//
|
||||
// check for LAN_X_TURNOUT_INFO
|
||||
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];
|
||||
|
||||
if (inbuffer[Z21_IDX_SETTURNOUT_MODE] == 2)
|
||||
server->TurnoutAddrMode(interfacename, addr, 1);
|
||||
else if (inbuffer[Z21_IDX_SETTURNOUT_MODE] == 1)
|
||||
server->TurnoutAddrMode(interfacename, addr, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// check for LAN_SYSTEMSTATE_DATACHANGED
|
||||
else if (memcmp (inbuffer, RX_SYSTEMSTATE_DATACHANGED, sizeof(RX_SYSTEMSTATE_DATACHANGED)) == 0) {
|
||||
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);
|
||||
|
||||
update = true;
|
||||
//if ( old_poweron != status_poweron ||
|
||||
// old_shortcircuit != status_shortcircuit ||
|
||||
// old_programmingmode != status_programmingmode ||
|
||||
// old_emergencystop != status_emergencystop) update = true;
|
||||
}
|
||||
|
||||
//
|
||||
// LOCONET
|
||||
//Got some Data:08:00:a1:00:a1:02:00:5c:
|
||||
//Got some Data:08:00:a1:00:a0:02:55:08:
|
||||
else if (memcmp (inbuffer+1, RX_LOCONET_Z21_TX, sizeof (RX_LOCONET_Z21_TX)) == 0) {
|
||||
int loconetopc = (unsigned char)inbuffer[4];
|
||||
printf ("%s:%d Got some LOCONET (%x) Data:", __FILE__, __LINE__, loconetopc);
|
||||
for (i = 0; i < inlen; i++) {
|
||||
int z = (unsigned char) inbuffer[i];
|
||||
printf ("i:%d %02x:", i, z);
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
//
|
||||
//
|
||||
if (loconetopc == 0xa0) {
|
||||
//
|
||||
// speed
|
||||
unsigned int inloc = inbuffer[5];
|
||||
unsigned int inspeed = inbuffer[6];
|
||||
|
||||
if (inloc >= 0 && inloc <= INTF_Z21_LOCONET_MAXADDR) {
|
||||
if (loconet_last.addr) {
|
||||
debug (0, "%s:%d loconet_lastaddr:%d", __FILE__, __LINE__, loconet_last.addr);
|
||||
loconet_map[inloc].addr = loconet_last.addr;
|
||||
}
|
||||
|
||||
debug (0, "%s:%d Loc:%d Speed:%d\n", __FILE__, __LINE__, loconet_map[inloc].addr, inspeed);
|
||||
if (loconet_map[inloc].addr > 0) {
|
||||
int speed = inspeed;
|
||||
server->LocomotiveAddrSpeed(interfacename, loconet_map[inloc].addr, speed);
|
||||
}
|
||||
}
|
||||
loconet_last.addr = 0;
|
||||
}
|
||||
|
||||
if (loconetopc == 0xa1) {
|
||||
//
|
||||
// speed
|
||||
unsigned int inloc = inbuffer[5];
|
||||
unsigned int infunc = inbuffer[6];
|
||||
|
||||
if (inloc >= 0 && inloc <= INTF_Z21_LOCONET_MAXADDR) {
|
||||
if (loconet_last.addr) loconet_map[inloc] = loconet_last;
|
||||
debug (0, "%s:%d Loc:%d Function:%d\n", __FILE__, __LINE__, loconet_map[inloc].addr, infunc);
|
||||
}
|
||||
loconet_last.addr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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;
|
||||
|
||||
printf ("LAN_RMBUS_DATA_CHANGE[%s] ", interfacename.c_str());
|
||||
for (idx = 0; idx < INTF_Z21_RMSENSOR_BYTES * INTF_Z21_RMSENSOR_GROUPS; idx++) {
|
||||
printf ("%x ", (unsigned char) inbuffer[4+idx]);
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
// groupindex (first or last 10 bytes)
|
||||
unsigned char rmsold[INTF_Z21_RMSENSOR_BYTES * INTF_Z21_RMSENSOR_GROUPS];
|
||||
memcpy (rmsold, rmsensors, INTF_Z21_RMSENSOR_BYTES * INTF_Z21_RMSENSOR_GROUPS);
|
||||
|
||||
if (group < INTF_Z21_RMSENSOR_GROUPS) {
|
||||
memcpy (rmsensors+(group * INTF_Z21_RMSENSOR_BYTES), inbuffer+5, INTF_Z21_RMSENSOR_BYTES);
|
||||
|
||||
// check for changes
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
rmsensorinit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
printf ("InterfaceZ21(%s) Got some Data:", interfacename.c_str());
|
||||
for (i = 0; i < inlen; i++) {
|
||||
int z = (unsigned char) inbuffer[i];
|
||||
printf ("%02x:", z);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
else if (inlen < 0) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
debug (DEBUG_ERROR | DEBUG_IFACE, "%s:%d error on reading (%s)",
|
||||
__FILE__, __LINE__, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return update;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// 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));
|
||||
}
|
||||
|
||||
//
|
||||
// send_GET_SERIAL_NUMBER
|
||||
void InterfaceZ21::send_GET_SERIAL_NUMBER() {
|
||||
unsigned char buffer[] = { 0x04, 0x00, 0x10, 0x00 };
|
||||
udp.Write(hostname, (char*)buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// send_RM_GETDATA
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// send_LOGOFF
|
||||
void InterfaceZ21::send_LOGOFF() {
|
||||
if (status_connected == false) return;
|
||||
|
||||
unsigned char buffer[] = { 0x04, 0x00, 0x30, 0x00 };
|
||||
udp.Write(hostname, (char*)buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Set Locomotive Speed
|
||||
void InterfaceZ21::SetLocoSpeed(Locomotive *l, int step) {
|
||||
unsigned char buffer[] = { 0x0A, 0x00, 0x40, 0x00, 0xE4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
debug (0, "%s:%d InterfaceZ21::SetLocoSpeed step:%d", __FILE__, __LINE__, step);
|
||||
|
||||
//
|
||||
// reverse?
|
||||
if (step < 0) {
|
||||
l->flags |= LOCO_F_REVERSE;
|
||||
}
|
||||
else if (step > 0) {
|
||||
l->flags &= ~LOCO_F_REVERSE;
|
||||
}
|
||||
if (l->flags & LOCO_F_REVERSE) buffer[Z21_IDX_SETLOCO_DRIVE_STEP] = 0x80;
|
||||
else buffer[Z21_IDX_SETLOCO_DRIVE_STEP] = 0x00;
|
||||
|
||||
//
|
||||
// setup loc addr
|
||||
if (l->addr >= 128) buffer[Z21_IDX_SETLOCO_DRIVE_ADRH] = 0xC0;
|
||||
else buffer[Z21_IDX_SETLOCO_DRIVE_ADRH] = 0;
|
||||
buffer[Z21_IDX_SETLOCO_DRIVE_ADRL] = (unsigned char) (l->addr & 0xFF);
|
||||
buffer[Z21_IDX_SETLOCO_DRIVE_ADRH] |= (unsigned char) (l->addr >> 8);
|
||||
|
||||
//
|
||||
// setup steps and selected step
|
||||
if (l->steps <= 14) {
|
||||
buffer[Z21_IDX_SETLOCO_DRIVE_SFMT] = 0x10;
|
||||
if (step == 0) buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= 0;
|
||||
else buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= (abs(step)+1);
|
||||
}
|
||||
else if (l->steps <= 28) {
|
||||
buffer[Z21_IDX_SETLOCO_DRIVE_SFMT] = 0x12;
|
||||
if (step == 0) buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= 0;
|
||||
else {
|
||||
buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= ((abs(step)>>1)+1);
|
||||
if (abs(step) & 0x01) buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= 0x10;
|
||||
}
|
||||
}
|
||||
else if (l->steps <= 128) {
|
||||
buffer[Z21_IDX_SETLOCO_DRIVE_SFMT] = 0x13;
|
||||
if (step == 0) buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= 0;
|
||||
else buffer[Z21_IDX_SETLOCO_DRIVE_STEP] |= (abs(step)+1);
|
||||
}
|
||||
|
||||
//
|
||||
// XOR Byte
|
||||
for (int i = 4; i < 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++) {
|
||||
int z = (unsigned char) buffer[i];
|
||||
printf ("%02x:", z);
|
||||
}
|
||||
printf ("\n");
|
||||
udp.Write(hostname, (char*)buffer, sizeof (buffer));
|
||||
loconet_last.addr = l->addr;
|
||||
loconet_last.dir = l->flags & LOCO_F_REVERSE;
|
||||
loconet_last.speed = l->speed;
|
||||
loconet_last.maxspeed = l->vmax;
|
||||
loconet_last.steps = l->steps;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Set Locomotive Function
|
||||
void InterfaceZ21::SetLocoFunction(Locomotive *l, int func, int value) {
|
||||
debug (0, "%s:%d InterfaceZ21::SetLocoFunction", __FILE__, __LINE__);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Set Turnout
|
||||
void InterfaceZ21::SetTurnout(Turnout *t, int activate, int motoractive) {
|
||||
unsigned char buffer[] = { 0x09, 0x00, 0x40, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
debug (0, "%s:%d InterfaceZ21::SetTurnout (a:%d, m:%d)", __FILE__, __LINE__, activate, motoractive);
|
||||
|
||||
//
|
||||
// setup turnout addr
|
||||
buffer[Z21_IDX_SETTURNOUT_ADRL] = (unsigned char) (t->addr & 0xFF);
|
||||
buffer[Z21_IDX_SETTURNOUT_ADRH] |= (unsigned char) (t->addr >> 8);
|
||||
|
||||
//
|
||||
// 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;
|
||||
|
||||
//
|
||||
// XOR Byte
|
||||
for (int i = 4; i < 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));
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// power on off
|
||||
// send_X_SET_TRACK_POWER_ON(); send_X_SET_TRACK_POWER_ON();
|
||||
void InterfaceZ21::PowerOnOff(int onoff) {
|
||||
if (status_connected == false) return;
|
||||
|
||||
if (onoff) {
|
||||
udp.Write(hostname, (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));
|
||||
}
|
||||
};
|
@ -0,0 +1,81 @@
|
||||
|
||||
#ifndef _INTERFACE_Z21_H_
|
||||
#define _INTERFACE_Z21_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "interface.h"
|
||||
#include <UDPTCPNetwork.h>
|
||||
|
||||
#define INTF_Z21_TIMEOUT 10
|
||||
#define INTF_Z21_INBUFFER 2048
|
||||
|
||||
// STATUSCHANGED / CENTRALSTATE
|
||||
#define INTF_Z21_CS_EmergencyStop 0x01
|
||||
#define INTF_Z21_CS_TrackVoltageOff 0x02
|
||||
#define INTF_Z21_CS_ShortCircuit 0x04
|
||||
#define INTF_Z21_CS_ProgModeActive 0x20
|
||||
|
||||
#define INTF_Z21_LOCONET_MAXADDR 255
|
||||
#define INTF_Z21_RMSENSOR_GROUPS 2
|
||||
#define INTF_Z21_RMSENSOR_BYTES 10
|
||||
#define INTF_Z21_RMGETDATA_TIMEOUT 30
|
||||
|
||||
struct s_loconet_map{
|
||||
int addr;
|
||||
int dir;
|
||||
int steps;
|
||||
int speed;
|
||||
int maxspeed;
|
||||
};
|
||||
|
||||
class InterfaceZ21 {
|
||||
private:
|
||||
string hostname;
|
||||
string serial;
|
||||
char inbuffer[INTF_Z21_INBUFFER];
|
||||
struct s_loconet_map loconet_map[INTF_Z21_LOCONET_MAXADDR];
|
||||
struct s_loconet_map loconet_last; // needed for detecting loco_changes
|
||||
|
||||
UDP udp;
|
||||
time_t timeout;
|
||||
time_t rmgetdatatimeout;
|
||||
bool send_logon;
|
||||
|
||||
bool status_poweron;
|
||||
bool status_shortcircuit;
|
||||
bool status_programmingmode;
|
||||
bool status_connected;
|
||||
bool status_emergencystop;
|
||||
|
||||
unsigned char rmsensors[INTF_Z21_RMSENSOR_BYTES * INTF_Z21_RMSENSOR_GROUPS];
|
||||
int rmsensorinit;
|
||||
|
||||
// void send_X_SET_TRACK_POWER_ON();
|
||||
// void send_X_SET_TRACK_POWER_OFF();
|
||||
void send_GET_SERIAL_NUMBER();
|
||||
void send_SET_BROADCASTFLAGS();
|
||||
void send_LOGOFF();
|
||||
void send_RM_GETDATA(int group);
|
||||
|
||||
public:
|
||||
InterfaceZ21();
|
||||
~InterfaceZ21();
|
||||
|
||||
void Connect(string destination);
|
||||
void Disconnect();
|
||||
|
||||
bool IsConnected() { return status_connected; };
|
||||
bool IsPoweron() { return status_poweron; };
|
||||
bool IsSortCircuit() { return status_shortcircuit; };
|
||||
bool IsProgramminnMode() { return status_programmingmode; };
|
||||
bool IsEmergencyStop() { return status_emergencystop; };
|
||||
|
||||
int Loop(string interfacename);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,392 @@
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "interface.h"
|
||||
|
||||
// **************************************************************************
|
||||
// *
|
||||
// * I N T E R F A C E (gateway to different devices)
|
||||
// *
|
||||
// **************************************************************************
|
||||
|
||||
Interface::Interface() {
|
||||
name[0] = 0;
|
||||
host[0] = 0;
|
||||
flags = 0;
|
||||
type = INTF_T_OFF_UNKNOWN;
|
||||
needs_update = true;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
switch (type) {
|
||||
case INTF_T_Z21: intz21.SetTurnout(t, active, motoractive); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
//
|
||||
// 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);
|
||||
};
|
||||
|
||||
//
|
||||
// Locomotive
|
||||
//
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int Interface::Loop() {
|
||||
int ret = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool Interface::IsPoweron() {
|
||||
bool ret = false;
|
||||
|
||||
switch (type) {
|
||||
case 1: ret = intz21.IsPoweron(); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (abs(speed) < l->vmin) step = 0;
|
||||
if (abs(speed) >= l->vmin) step = (speed * (l->steps-1)) / l->vmax;
|
||||
if (abs(speed) > l->vmax) step = l->steps-1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,86 @@
|
||||
|
||||
#ifndef _INTERFACE_H_
|
||||
#define _INTERFACE_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
#include "UDPTCPNetwork.h"
|
||||
#include "json.h"
|
||||
#include "interface-z21.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
|
||||
|
||||
#define INTF_T_OFF_UNKNOWN 0
|
||||
#define INTF_T_Z21 1
|
||||
|
||||
|
||||
class Interface {
|
||||
private:
|
||||
InterfaceZ21 intz21;
|
||||
bool needs_update;
|
||||
public:
|
||||
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; };
|
||||
|
||||
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 motoractive);
|
||||
|
||||
void Loop();
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,494 @@
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "json.h"
|
||||
|
||||
/***********************************************************************
|
||||
***********************************************************************
|
||||
*
|
||||
* JSONParse
|
||||
*
|
||||
***********************************************************************
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
enum {
|
||||
STEP_NONE = 0,
|
||||
STEP_STARTNAME,
|
||||
STEP_NAME,
|
||||
STEP_STARTVALUE,
|
||||
STEP_VALUE,
|
||||
STEP_END
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
// clear out all data
|
||||
//
|
||||
void JSONParse::Clear() {
|
||||
jsondata = "";
|
||||
names.clear();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
// read every element and keep only this in memory.
|
||||
//
|
||||
int JSONParse::Set(string json) {
|
||||
int i;
|
||||
int step;
|
||||
int level;
|
||||
bool ignorenext;
|
||||
|
||||
JSONElement jelement;
|
||||
|
||||
Clear();
|
||||
|
||||
// find start and read until end
|
||||
for (step = STEP_NONE, i = 0, ignorenext = false; i < 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) {
|
||||
ignorenext = false;
|
||||
if (step == STEP_NAME) jelement.name += json[i];
|
||||
if (step == STEP_VALUE) jelement.value += json[i];
|
||||
}
|
||||
|
||||
// searching for startname
|
||||
else if (step == STEP_NONE) {
|
||||
if (json[i] == '{') {
|
||||
step = STEP_STARTNAME;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// searching for startname
|
||||
else if (step == STEP_STARTNAME) {
|
||||
if (json[i] == '"') {
|
||||
step = STEP_NAME;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// copy name
|
||||
else if (step == STEP_NAME) {
|
||||
if (json[i] == '"') {
|
||||
step = STEP_STARTVALUE;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
jelement.name += json[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// searching for startvalue
|
||||
else if (step == STEP_STARTVALUE) {
|
||||
if (json[i] == '"') {
|
||||
step = STEP_VALUE;
|
||||
jelement.type = JSON_T_STRING;
|
||||
continue;
|
||||
}
|
||||
if (json[i] == '{') {
|
||||
step = STEP_VALUE;
|
||||
level = 0;
|
||||
jelement.type = JSON_T_OBJECT;
|
||||
jelement.value = "{";
|
||||
continue;
|
||||
}
|
||||
if (json[i] == '[') {
|
||||
step = STEP_VALUE;
|
||||
level = 0;
|
||||
jelement.type = JSON_T_ARRAY;
|
||||
jelement.value = "[";
|
||||
continue;
|
||||
}
|
||||
if ((json[i] >= '0' && json[i] <= '9') ||
|
||||
(json[i] == '+' || json[i] == '-')) {
|
||||
step = STEP_VALUE;
|
||||
level = 0;
|
||||
jelement.type = JSON_T_NUMBER;
|
||||
jelement.value = json[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// copy value
|
||||
else if (step == STEP_VALUE) {
|
||||
if (jelement.type == JSON_T_STRING) {
|
||||
if (json[i] == '"') step = STEP_END;
|
||||
else jelement.value += json[i];
|
||||
continue;
|
||||
}
|
||||
else if (jelement.type == JSON_T_OBJECT) {
|
||||
if (json[i] == '}' && level == 0) {
|
||||
jelement.value += json[i];
|
||||
step = STEP_END;
|
||||
}
|
||||
else {
|
||||
if (json[i] == '{') level++; // increase level
|
||||
if (json[i] == '}') level--; // decrease level
|
||||
jelement.value += json[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (jelement.type == JSON_T_ARRAY) {
|
||||
if (json[i] == ']' && level == 0) {
|
||||
jelement.value += json[i];
|
||||
step = STEP_END;
|
||||
}
|
||||
else {
|
||||
if (json[i] == '[') level++; // increase level
|
||||
if (json[i] == ']') level--; // decrease level
|
||||
jelement.value += json[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (jelement.type == JSON_T_NUMBER) {
|
||||
if ((json[i] < '0' || json[i] > '9') && json[i] != '.' &&
|
||||
json[i] != '+' && json[i] != 'e' && json[i] != 'E') step = STEP_END;
|
||||
else {
|
||||
jelement.value += json[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// another element?
|
||||
if (step == STEP_END) {
|
||||
if (json[i] == ',') {
|
||||
// debug (0, "* JSON.Set Add name:%s", jelement.name.c_str());
|
||||
if (jelement.type != JSON_T_NONE) {
|
||||
// debug (0, "%s:%d json add element type:%d", __FILE__, __LINE__, jelement.type);
|
||||
names.push_back (jelement);
|
||||
}
|
||||
jelement.Clear();
|
||||
step = STEP_STARTNAME;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// debug (0, "* JSON.Set Add name:%s", jelement.name.c_str());
|
||||
if (jelement.type != JSON_T_NONE) {
|
||||
// debug (0, "%s:%d json add element type:%d", __FILE__, __LINE__, jelement.type);
|
||||
names.push_back (jelement);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
int JSONParse::GetValue(string varname, string *dest) {
|
||||
list<JSONElement>::iterator iter;
|
||||
|
||||
if (dest == NULL) return 0;
|
||||
*dest = "";
|
||||
|
||||
for (iter = names.begin(); iter != names.end(); iter++) {
|
||||
if (varname.compare(iter->name) == 0) {
|
||||
*dest = iter->value;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
int JSONParse::GetValueInt(string varname, int *dest) {
|
||||
string s;
|
||||
int res = GetValue(varname, &s);
|
||||
if (res) {
|
||||
*dest = atoi (s.c_str());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
int JSONParse::GetValueInt64(string varname, int64_t *dest) {
|
||||
string s;
|
||||
int res = GetValue(varname, &s);
|
||||
if (res) {
|
||||
*dest = atol (s.c_str());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
int JSONParse::GetObject(string varname, JSONParse *dest) {
|
||||
list<JSONElement>::iterator iter;
|
||||
|
||||
if (dest == NULL) return 0;
|
||||
|
||||
for (iter = names.begin(); iter != names.end(); iter++) {
|
||||
if (varname.compare(iter->name) == 0) {
|
||||
dest->Set(iter->value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
#define MAXRECURSIVE 255
|
||||
int JSONParse::GetIdx(string src, int idx, string *dest) {
|
||||
char recursive[MAXRECURSIVE];
|
||||
int i = 0, rcnt = 0, cnt = 0;
|
||||
|
||||
(*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++) {
|
||||
// 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] == '[') {
|
||||
recursive[rcnt++] = src[i];
|
||||
continue;
|
||||
}
|
||||
else if (src[i] == '{' && recursive[rcnt] != '"') recursive[++rcnt] = src[i];
|
||||
else if (src[i] == '}' && recursive[rcnt] == '{') rcnt--;
|
||||
else if (src[i] == '"' && recursive[rcnt] == '"') rcnt--;
|
||||
else if (src[i] == '"') recursive[++rcnt] = src[i];
|
||||
else if (src[i] == ',' && rcnt == 1) {
|
||||
cnt++;
|
||||
continue;
|
||||
}
|
||||
else if (src[i] == ']' && rcnt == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rcnt > 0 && cnt == idx) {
|
||||
(*dest) += src[i];
|
||||
if (src[i] == '\\') (*dest) += src[i];
|
||||
}
|
||||
else {
|
||||
if (src[i] == '\\')i++;
|
||||
}
|
||||
}
|
||||
|
||||
// printf("\n***************************************idx:%d cnt:%d\n", idx, cnt);
|
||||
// printf("in:'%s'\n***\nout:'%s'\n\n*****\n", src.c_str(), dest->c_str());
|
||||
|
||||
//
|
||||
// final checks
|
||||
if (cnt == 0 && idx == 0 && // empty source/array?
|
||||
dest->size() == 0) return 0; //
|
||||
if (cnt >= idx) return 1; // found the right element
|
||||
return 0; // element not found
|
||||
}
|
||||
#undef MAXRECURSIVE
|
||||
|
||||
int JSONParse::GetValueIdx(string varname, int idx, string *dest) {
|
||||
list<JSONElement>::iterator iter;
|
||||
|
||||
if (dest == NULL) return 0;
|
||||
|
||||
for (iter = names.begin(); iter != names.end(); iter++) {
|
||||
if (varname.compare(iter->name) == 0) {
|
||||
return GetIdx(iter->value, idx, dest);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
int JSONParse::GetObjectIdx(string varname, int idx, JSONParse *dest) {
|
||||
list<JSONElement>::iterator iter;
|
||||
string deststr;
|
||||
int ret = 0;
|
||||
|
||||
if (dest == NULL) return 0;
|
||||
|
||||
for (iter = names.begin(); iter != names.end(); iter++) {
|
||||
if (varname.compare(iter->name) == 0) {
|
||||
ret = GetIdx(iter->value, idx, &deststr);
|
||||
if (ret == 1) dest->Set(deststr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
list<JSONElement> JSONParse::GetElements() {
|
||||
list<JSONElement> l;
|
||||
list<JSONElement>::iterator iter;
|
||||
|
||||
l.clear();
|
||||
for (iter = names.begin(); iter != names.end(); iter++) {
|
||||
l.push_back(*iter);
|
||||
}
|
||||
|
||||
return l;
|
||||
};
|
||||
|
||||
|
||||
void JSONParse::AddObject (JSONElement element) {
|
||||
names.push_back (element);
|
||||
};
|
||||
|
||||
|
||||
void JSONParse::AddObject (string name, JSONParse jp) {
|
||||
JSONElement je;
|
||||
je.SetObject(name, jp.ToString());
|
||||
names.push_back(je);
|
||||
};
|
||||
|
||||
|
||||
void JSONParse::AddObject (string name, int val) {
|
||||
JSONElement je;
|
||||
je.Set(name, val);
|
||||
names.push_back(je);
|
||||
};
|
||||
|
||||
|
||||
void JSONParse::AddObject (string name, int64_t val) {
|
||||
JSONElement je;
|
||||
je.Set(name, val);
|
||||
names.push_back(je);
|
||||
};
|
||||
|
||||
|
||||
void JSONParse::AddObject (string name, string val) {
|
||||
JSONElement je;
|
||||
je.Set(name, val);
|
||||
names.push_back(je);
|
||||
};
|
||||
|
||||
|
||||
void JSONParse::AddObject (string name, double val) {
|
||||
JSONElement je;
|
||||
je.Set(name, val);
|
||||
names.push_back(je);
|
||||
};
|
||||
|
||||
|
||||
string JSONParse::ToString() {
|
||||
list<JSONElement>::iterator iter;
|
||||
string output;
|
||||
int level, i;
|
||||
|
||||
output = "{";
|
||||
|
||||
for (level = 1, iter = names.begin(); iter != names.end(); iter++) {
|
||||
if (iter != names.begin()) output += ",";
|
||||
output += "\n";
|
||||
for (i = 0; i < 4*level; i++) output += " ";
|
||||
output += iter->GetString();
|
||||
}
|
||||
|
||||
output += "\n}\n";
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
***********************************************************************
|
||||
*
|
||||
* JSONElement
|
||||
*
|
||||
***********************************************************************
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
|
||||
void JSONElement::Set (string n, double v) {
|
||||
name = n;
|
||||
value = to_string(v);
|
||||
type = JSON_T_NUMBER;
|
||||
};
|
||||
|
||||
|
||||
void JSONElement::Set (string n, int v) {
|
||||
name = n;
|
||||
value = to_string(v);
|
||||
type = JSON_T_NUMBER;
|
||||
};
|
||||
|
||||
|
||||
void JSONElement::Set (string n, int64_t v) {
|
||||
name = n;
|
||||
value = to_string(v);
|
||||
type = JSON_T_NUMBER;
|
||||
};
|
||||
|
||||
|
||||
void JSONElement::Set (string n, string v) {
|
||||
name = n;
|
||||
value = v;
|
||||
type = JSON_T_STRING;
|
||||
};
|
||||
|
||||
|
||||
void JSONElement::SetArray (string n, list<JSONElement> *l) {
|
||||
list<JSONElement>::iterator iter;
|
||||
|
||||
name = n;
|
||||
value = "[";
|
||||
type = JSON_T_STRING;
|
||||
|
||||
for (iter = l->begin(); iter != l->end(); iter++) {
|
||||
if (iter != l->begin()) value += ",";
|
||||
value += iter->GetString();
|
||||
}
|
||||
value += "]";
|
||||
};
|
||||
|
||||
|
||||
void JSONElement::SetObject (string n, string s) {
|
||||
name = n;
|
||||
value = s;
|
||||
type = JSON_T_OBJECT;
|
||||
};
|
||||
|
||||
|
||||
string JSONElement::GetString () {
|
||||
string output = "";
|
||||
string filename = __FILE__;
|
||||
|
||||
switch (type) {
|
||||
case(JSON_T_NUMBER):
|
||||
output += "\"" + name + "\" : " + value;
|
||||
break;
|
||||
case(JSON_T_STRING):
|
||||
if (value.length()==0) {
|
||||
output += "\"" + name + "\" : \"\"";
|
||||
}
|
||||
// FIXME: we have to define all strings are saved here without ""
|
||||
// will be set up in the future
|
||||
// WORKAROUND for empty strings
|
||||
else if (value[0] != '"') {
|
||||
output += "\"" + name + "\" : \"" + value + "\"";
|
||||
}
|
||||
else output += "\"" + name + "\" : " + value;
|
||||
break;
|
||||
case(JSON_T_OBJECT):
|
||||
output += "\"" + name + "\" : " + value;
|
||||
break;
|
||||
case(JSON_T_ARRAY):
|
||||
if (value.length()==0) {
|
||||
output += "\"" + name + "\" : []";
|
||||
}
|
||||
// WORKAROUND for arrays without []
|
||||
else if (value[0] != '[') {
|
||||
output += "\"" + name + "\" : [" + value + "]";
|
||||
}
|
||||
else output += "\"" + name + "\" : " + value;
|
||||
break;
|
||||
default:
|
||||
output += "\"error\" : \""+ filename + ":" + to_string(__LINE__) + " JSONElement unknown type error\"("+to_string(type)+")";
|
||||
break;
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
@ -0,0 +1,72 @@
|
||||
|
||||
#ifndef _JSON_H_
|
||||
#define _JSON_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum {
|
||||
JSON_T_NONE,
|
||||
JSON_T_STRING,
|
||||
JSON_T_NUMBER,
|
||||
JSON_T_OBJECT,
|
||||
JSON_T_ARRAY
|
||||
};
|
||||
|
||||
class JSONElement {
|
||||
public:
|
||||
int type;
|
||||
string name;
|
||||
string value;
|
||||
|
||||
JSONElement() { Clear(); };
|
||||
~JSONElement() {};
|
||||
|
||||
void Clear() { type = JSON_T_NONE; name = ""; value = ""; };
|
||||
void Set (string n, double v);
|
||||
void Set (string n, int v);
|
||||
void Set (string n, int64_t v);
|
||||
void Set (string n, string v);
|
||||
void SetArray (string n, list<JSONElement> *l);
|
||||
void SetObject (string n, string s);
|
||||
string GetString();
|
||||
};
|
||||
|
||||
class JSONParse {
|
||||
private:
|
||||
string jsondata;
|
||||
list<JSONElement> names;
|
||||
|
||||
public:
|
||||
JSONParse() { Set("{}"); };
|
||||
JSONParse(string json) { Set(json); };
|
||||
~JSONParse() {};
|
||||
|
||||
void Clear();
|
||||
int Set(string json);
|
||||
|
||||
int GetValue(string varname, string *dest);
|
||||
int GetValueInt(string varname, int *dest);
|
||||
int GetValueInt64(string varname, int64_t *dest);
|
||||
int GetObject(string varname, JSONParse *dest);
|
||||
|
||||
int GetIdx(string src, int idx, string *dest);
|
||||
int GetValueIdx(string varname, int idx, string *dest);
|
||||
int GetObjectIdx(string varname, int idx, JSONParse *dest);
|
||||
|
||||
list<JSONElement> GetElements();
|
||||
|
||||
void AddObject (JSONElement element);
|
||||
void AddObject (string name, int val);
|
||||
void AddObject (string name, int64_t val);
|
||||
void AddObject (string name, string val);
|
||||
void AddObject (string name, double val);
|
||||
void AddObject (string name, JSONParse jp);
|
||||
|
||||
string ToString();
|
||||
};
|
||||
|
||||
#endif // _JSON_H_
|
@ -0,0 +1,269 @@
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "locomotive.h"
|
||||
|
||||
|
||||
Locomotives::Locomotives () {
|
||||
changed = 0;
|
||||
locomotives = (Locomotive*) malloc(sizeof(Locomotive)*LOCOMOTIVES_MAX);
|
||||
memset(locomotives, 0x0, sizeof(Locomotive)*LOCOMOTIVES_MAX);
|
||||
max = SENSORS_MAX;
|
||||
};
|
||||
|
||||
Locomotives::~Locomotives() {
|
||||
free (locomotives);
|
||||
locomotives = NULL;
|
||||
max = 0;
|
||||
};
|
||||
|
||||
|
||||
int Locomotives::Lock() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
int Locomotives::UnLock() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
JSONParse Locomotives::_GetJSON(int idx) {
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
string s = "";
|
||||
|
||||
json.Clear();
|
||||
|
||||
s = locomotives[idx].name; json.AddObject("name", s);
|
||||
s = locomotives[idx].ifname; json.AddObject("ifname", s);
|
||||
json.AddObject("addr", locomotives[idx].addr);
|
||||
json.AddObject("steps", locomotives[idx].steps);
|
||||
json.AddObject("speed", locomotives[idx].speed);
|
||||
json.AddObject("func", locomotives[idx].func);
|
||||
json.AddObject("flags", locomotives[idx].flags);
|
||||
json.AddObject("vmin", locomotives[idx].vmin);
|
||||
json.AddObject("vslow", locomotives[idx].vslow);
|
||||
json.AddObject("vmid", locomotives[idx].vmid);
|
||||
json.AddObject("vfast", locomotives[idx].vfast);
|
||||
json.AddObject("vmax", locomotives[idx].vmax);
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
JSONParse Locomotives::GetJSON(string name) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
jp.Clear();
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
|
||||
if (name.compare(locomotives[i].name) == 0) {
|
||||
jp = _GetJSON(i);
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return jp;
|
||||
};
|
||||
|
||||
|
||||
void Locomotives::GetJSONAll(JSONParse *json) {
|
||||
int i, cnt;
|
||||
JSONElement je;
|
||||
|
||||
Lock();
|
||||
|
||||
//
|
||||
// write all railway data
|
||||
// create json object array manualy
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "locomotives";
|
||||
for (cnt = 0, i = 0; i < max; i++)
|
||||
if (locomotives[i].name[0] != 0) {
|
||||
if (cnt != 0) je.value += ","; // not first element
|
||||
je.value += _GetJSON(i).ToString();
|
||||
cnt++;
|
||||
}
|
||||
json->AddObject(je);
|
||||
|
||||
UnLock();
|
||||
};
|
||||
|
||||
|
||||
Locomotive Locomotives::GetLocomotiveFromJSON(JSONParse *j) {
|
||||
Locomotive l;
|
||||
string s;
|
||||
|
||||
l.name[0] = 0;
|
||||
l.ifname[0] = 0;
|
||||
l.addr = 0;
|
||||
l.steps = 0;
|
||||
l.vmin = 0;
|
||||
l.vslow = 0;
|
||||
l.vmid = 0;
|
||||
l.vfast = 0;
|
||||
l.vmax = 0;
|
||||
l.flags = 0;
|
||||
l.speed = 0;
|
||||
l.func = 0;
|
||||
|
||||
j->GetValue("name", &s);
|
||||
strncpy (l.name, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValue("ifname", &s);
|
||||
strncpy (l.ifname, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValueInt("addr", &l.addr);
|
||||
j->GetValueInt("steps", &l.steps);
|
||||
j->GetValueInt("speed", &l.speed);
|
||||
j->GetValueInt64("func", &l.func);
|
||||
j->GetValueInt("flags", &l.flags);
|
||||
j->GetValueInt("vmin", &l.vmin);
|
||||
j->GetValueInt("vslow", &l.vslow);
|
||||
j->GetValueInt("vmid", &l.vmid);
|
||||
j->GetValueInt("vfast", &l.vfast);
|
||||
j->GetValueInt("vmax", &l.vmax);
|
||||
|
||||
return l;
|
||||
};
|
||||
|
||||
|
||||
int Locomotives::Change(Locomotive *loco) {
|
||||
int i;
|
||||
int ifree = -1;
|
||||
|
||||
Lock();
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (locomotives[i].name[0] != 0) {
|
||||
// found element
|
||||
if (strncmp(locomotives[i].name, loco->name, REFERENCENAME_LEN) == 0) {
|
||||
ifree = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ifree == -1) ifree = i;
|
||||
}
|
||||
// element not found add new element
|
||||
if (ifree != -1 && ifree < max) {
|
||||
locomotives[ifree] = *loco;
|
||||
strncpy (locomotives[ifree].name, loco->name, REFERENCENAME_LEN);
|
||||
strncpy (locomotives[ifree].ifname, loco->ifname, REFERENCENAME_LEN);
|
||||
}
|
||||
|
||||
changed = 1;
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Locomotives::Delete(string name) {
|
||||
int i;
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
|
||||
if (name.compare(locomotives[i].name) == 0) {
|
||||
locomotives[i].name[0] = 0;
|
||||
locomotives[i].ifname[0] = 0;
|
||||
locomotives[i].addr = 0;
|
||||
locomotives[i].steps = 0;
|
||||
locomotives[i].vmin = 0;
|
||||
locomotives[i].vslow = 0;
|
||||
locomotives[i].vmid = 0;
|
||||
locomotives[i].vfast = 0;
|
||||
locomotives[i].vmax = 0;
|
||||
locomotives[i].flags = 0;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Locomotives::SetSpeed(string name, int speed) {
|
||||
int i;
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
|
||||
if (name.compare(locomotives[i].name) == 0) {
|
||||
server->interfaces.SetLocoSpeed(&locomotives[i], speed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Locomotives::SetFunction(string name, int func, int value) {
|
||||
int i;
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
|
||||
if (name.compare(locomotives[i].name) == 0) {
|
||||
server->interfaces.SetLocoFunction(&locomotives[i], func, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// set values from bus...
|
||||
//
|
||||
int Locomotives::SetSpeedFromBus(string name, int addr, int speed) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
|
||||
if (name.compare(locomotives[i].name) == 0 && locomotives[i].addr == addr) {
|
||||
locomotives[i].speed = speed;
|
||||
|
||||
jp.AddObject("locomotive",_GetJSON(i));
|
||||
if(network) network->ChangeListPushToAll(jp.ToString());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
int Locomotives::SetDirectionFromBus(string name, int addr, int reverse) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
|
||||
if (name.compare(locomotives[i].name) == 0 && locomotives[i].addr == addr) {
|
||||
if (reverse) locomotives[i].flags |= LOCO_F_REVERSE;
|
||||
else locomotives[i].flags &= ~LOCO_F_REVERSE;
|
||||
|
||||
jp.AddObject("locomotive",_GetJSON(i));
|
||||
if(network) network->ChangeListPushToAll(jp.ToString());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,59 @@
|
||||
|
||||
#ifndef _LOCOMOTIVE_H_
|
||||
#define _LOCOMOTIVE_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
|
||||
#define LOCO_F_REVERSE 0x0001
|
||||
|
||||
struct s_Locomotive {
|
||||
char name[REFERENCENAME_LEN];
|
||||
char ifname[REFERENCENAME_LEN];
|
||||
int steps;
|
||||
int speed;
|
||||
int64_t func;
|
||||
int flags;
|
||||
int addr;
|
||||
int vmin;
|
||||
int vslow;
|
||||
int vmid;
|
||||
int vfast;
|
||||
int vmax;
|
||||
} typedef Locomotive;
|
||||
|
||||
class Locomotives {
|
||||
private:
|
||||
Locomotive *locomotives;
|
||||
int max;
|
||||
int changed;
|
||||
|
||||
pthread_mutex_t mtx;
|
||||
int Lock();
|
||||
int UnLock();
|
||||
|
||||
// not thread safe
|
||||
JSONParse _GetJSON(int idx);
|
||||
|
||||
public:
|
||||
Locomotives();
|
||||
~Locomotives();
|
||||
|
||||
bool IsChanged() { return changed; }
|
||||
void ClearChanged() { changed = 0; };
|
||||
|
||||
int Change(Locomotive *loco);
|
||||
int Delete(string name);
|
||||
int SetSpeed(string name, int speed);
|
||||
int SetFunction(string name, int func, int value);
|
||||
|
||||
int SetSpeedFromBus (string name, int addr, int speed);
|
||||
int SetDirectionFromBus (string name, int addr, int speed);
|
||||
|
||||
JSONParse GetJSON(string name);
|
||||
void GetJSONAll(JSONParse *json);
|
||||
Locomotive GetLocomotiveFromJSON(JSONParse *j);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,120 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <UDPTCPNetwork.h>
|
||||
|
||||
#include "modelbahn.h"
|
||||
|
||||
void uprintf (UNIX *u, char *fmt,...);
|
||||
static void sig_int(int); // signal handler
|
||||
int running = 1;
|
||||
|
||||
Server *server = NULL;
|
||||
Network *network = NULL;
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
int ret;
|
||||
|
||||
//
|
||||
// setup signals
|
||||
//
|
||||
if (signal(SIGINT, sig_int) == SIG_ERR) {
|
||||
fprintf (stderr, "%s:%d could not set signal for SIGINT\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
if (signal(SIGTERM, sig_int) == SIG_ERR) {
|
||||
fprintf (stderr, "%s:%d could not set signal for SIGTERM\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
if (signal(SIGHUP, sig_int) == SIG_ERR) {
|
||||
fprintf (stderr, "%s:%d could not set signal for SIGHUB\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
debug (0, "***************************************************");
|
||||
debug (0, "* *");
|
||||
debug (0, "* Modelbahn Server *");
|
||||
debug (0, "* *");
|
||||
debug (0, "***************************************************");
|
||||
debug (0, "");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// application startup
|
||||
//
|
||||
debug (0, "* application startup");
|
||||
server = new Server();
|
||||
network = new Network();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// application loop
|
||||
//
|
||||
debug (0, "* application loop");
|
||||
server->Start();
|
||||
network->Start();
|
||||
while (running) {
|
||||
sleep (1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// application shutdown
|
||||
//
|
||||
while (server->isRunning() || network->isRunning());
|
||||
debug (0, "* application shutdown");
|
||||
delete network;
|
||||
debug (0, "* deleted network");
|
||||
delete server;
|
||||
debug (0, "* deleted server");
|
||||
debug (0, "* application exited");
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
void uprintf (UNIX *u, char *fmt,...) {
|
||||
va_list args;
|
||||
char buffer[BUFFERSIZE];
|
||||
|
||||
va_start (args, fmt);
|
||||
vsnprintf (buffer, (BUFFERSIZE-1), fmt, args);
|
||||
va_end (args);
|
||||
buffer[BUFFERSIZE-1] = 0;
|
||||
u->Write(buffer, strlen (buffer));
|
||||
};
|
||||
|
||||
static void sig_int(int sig) {
|
||||
debug (0, "* signal:%d received", sig);
|
||||
|
||||
if (signal (SIGINT, sig_int) == SIG_ERR) {
|
||||
fprintf (stderr, "%s:%d could not set up signal SIGINT\n", __FILE__, __LINE__);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
running = 0;
|
||||
}
|
||||
|
||||
|
||||
void timer_start(struct timeval *tv) {
|
||||
gettimeofday(tv, NULL);
|
||||
};
|
||||
|
||||
|
||||
int timer_end(struct timeval *tv) {
|
||||
struct timeval tvnow;
|
||||
|
||||
gettimeofday(&tvnow, NULL);
|
||||
|
||||
return ((tvnow.tv_sec - tv->tv_sec)*1000 + (tvnow.tv_usec - tv->tv_usec)/1000);
|
||||
};
|
@ -0,0 +1,64 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <UDPTCPNetwork.h>
|
||||
#define UNIX_SOCKET_FILE "/tmp/modelbahn.socket"
|
||||
#define LOG_FILE "/tmp/modelbahn-cgi.log"
|
||||
#define BUFFERSIZE 64000
|
||||
|
||||
//extern char **environ;
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
int i, inlen;
|
||||
FILE *logf;
|
||||
char buffer[BUFFERSIZE+1];
|
||||
char *ptr = NULL;
|
||||
|
||||
printf ("Content-type: text/html\n");
|
||||
printf ("Expires: now\n");
|
||||
printf ("Pragma: no-cache\n");
|
||||
printf ("\n");
|
||||
|
||||
//
|
||||
// open logfile for writing
|
||||
logf = fopen(LOG_FILE, "a+");
|
||||
if (logf == NULL) return 0;
|
||||
fprintf (logf, "*************************************\n");
|
||||
|
||||
//
|
||||
// read data
|
||||
memset (buffer, 0x0, BUFFERSIZE+1);
|
||||
// FIXME: fgets is wrong....
|
||||
for (ptr = buffer, inlen = 0; inlen < BUFFERSIZE-1 && (fgets (ptr, BUFFERSIZE - inlen, stdin)) > 0;) {
|
||||
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));
|
||||
|
||||
//
|
||||
// send data to server
|
||||
UNIX u;
|
||||
if (u.Connect(UNIX_SOCKET_FILE) != 1) return 0;
|
||||
u.Write(buffer, strlen(buffer));
|
||||
|
||||
//
|
||||
// read data and send back to the web server
|
||||
do {
|
||||
i = u.ReadTimeout(buffer, BUFFERSIZE-1, 1000);
|
||||
buffer[i] = 0;
|
||||
fprintf (logf, "read from server %d bytes\n", i);
|
||||
printf ("%s", buffer);
|
||||
} while (i == BUFFERSIZE-1);
|
||||
u.Close();
|
||||
|
||||
fclose (logf);
|
||||
return 0;
|
||||
};
|
@ -0,0 +1,40 @@
|
||||
|
||||
#ifndef _MODELBAHN_H_
|
||||
#define _MODELBAHN_H_
|
||||
|
||||
#define TIMEOUT_REFRESH 1
|
||||
#define BUFFERSIZE 64000
|
||||
#define MAXWAITTIME 500
|
||||
#define UNIX_SOCKET_FILE "/tmp/modelbahn.socket"
|
||||
#define DEFAULT_DATADIR "/home/steffen/Dokumente/Programmierung/Modelbahn/"
|
||||
#define SESSIONS_MAX 8
|
||||
|
||||
#define REFERENCENAME_LEN 128
|
||||
#define INTERFACES_MAX 8
|
||||
#define TURNOUTS_MAX 255
|
||||
#define LOCOMOTIVES_MAX 255
|
||||
#define SENSORS_MAX 255
|
||||
#define BLOCKS_MAX 128
|
||||
|
||||
#include "server.h"
|
||||
#include "turnout.h"
|
||||
#include "sensor.h"
|
||||
#include "network.h"
|
||||
#include "block.h"
|
||||
#include "debug.h"
|
||||
|
||||
extern int running;
|
||||
|
||||
extern Server *server;
|
||||
extern Network *network;
|
||||
|
||||
|
||||
//
|
||||
// to measure the time in ms (used for debugging)
|
||||
//
|
||||
void timer_start(struct timeval *tv);
|
||||
int timer_end(struct timeval *tv);
|
||||
|
||||
|
||||
#endif // _MODELBAHN_H_
|
||||
|
@ -0,0 +1,279 @@
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <pthread.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <list>
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "network.h"
|
||||
#include "json.h"
|
||||
|
||||
Network::Network() {
|
||||
thread = 0;
|
||||
sessions.clear();
|
||||
thread_running = 0;
|
||||
mtx = { 0 };
|
||||
mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
}
|
||||
|
||||
Network::~Network() {
|
||||
list<Session*>::iterator iter;
|
||||
|
||||
while ((iter = sessions.begin()) != sessions.end()) {
|
||||
Session *s = *iter;
|
||||
sessions.remove(*iter);
|
||||
delete s;
|
||||
}
|
||||
Stop();
|
||||
};
|
||||
|
||||
|
||||
|
||||
int Network::LockThread() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
int Network::UnLockThread() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Network::ThreadProcess() {
|
||||
list<UNIX*>::iterator iteru;
|
||||
Session *s;
|
||||
UNIX *u;
|
||||
|
||||
while (running) {
|
||||
//
|
||||
// check network
|
||||
|
||||
//
|
||||
// server socket
|
||||
ServerLoop();
|
||||
|
||||
//
|
||||
// client socket
|
||||
for (iteru = clients.begin(); iteru != clients.end(); iteru++) {
|
||||
if (ClientLoop((UNIX*) *iteru) < 0) {
|
||||
u = *iteru;
|
||||
clients.remove(u);
|
||||
delete u;
|
||||
iteru = clients.begin();
|
||||
}
|
||||
}
|
||||
|
||||
usleep (100000);
|
||||
}
|
||||
thread_running = 0;
|
||||
};
|
||||
|
||||
|
||||
int Network::Start() {
|
||||
int err;
|
||||
pthread_attr_t attr;
|
||||
mtx = { 0 };
|
||||
mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
//
|
||||
// start socket server
|
||||
//
|
||||
if (sockserver.Listen(UNIX_SOCKET_FILE) != 1) {
|
||||
return 0;
|
||||
}
|
||||
chmod(UNIX_SOCKET_FILE, 00666);
|
||||
|
||||
thread_running = 1;
|
||||
pthread_attr_init (&attr);
|
||||
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
|
||||
err = pthread_create (&thread, &attr, ThreadEntry, this);
|
||||
if (err != 0) {
|
||||
debug (DEBUG_ERROR, (char*)"%s(%s:%d) pthread_create errror: %s", __FUNCTION__, __FILE__, __LINE__, strerror (errno));
|
||||
running = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
void Network::Stop() {
|
||||
sockserver.Close();
|
||||
unlink(UNIX_SOCKET_FILE);
|
||||
}
|
||||
|
||||
|
||||
void Network::_ChangeListPushToAll(string changes) {
|
||||
list<Session*>::iterator iter;
|
||||
|
||||
for (iter = sessions.begin(); iter != sessions.end(); iter++) {
|
||||
if ((*iter)->GetSessionID() > 0) (*iter)->ChangeListPush(changes);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Network::ChangeListPushToAll(string changes) {
|
||||
LockThread();
|
||||
_ChangeListPushToAll(changes);
|
||||
UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
|
||||
int Network::ServerLoop() {
|
||||
UNIX *u = NULL;
|
||||
|
||||
if (sockserver.IsData(10)) {
|
||||
u = sockserver.Accept();
|
||||
clients.push_back(u);
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
Session *Network::GetSession(int sid) {
|
||||
Session *s = NULL;
|
||||
list<Session*>::iterator iter;
|
||||
|
||||
for (iter = sessions.begin(); iter != sessions.end(); iter++) {
|
||||
if ((*iter)->GetSessionID() == sid) {
|
||||
s = *iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
};
|
||||
|
||||
|
||||
int Network::ClientLoop(UNIX *client) {
|
||||
char bufferin[BUFFERSIZE];
|
||||
char bufferout[BUFFERSIZE];
|
||||
int len, i, rid, sid;
|
||||
int res;
|
||||
list<Session*>::iterator siter;
|
||||
Session *session = NULL;
|
||||
string value;
|
||||
string ssid;
|
||||
string srid;
|
||||
string s;
|
||||
int result = -1;
|
||||
struct timeval timer;
|
||||
|
||||
timer_start(&timer);
|
||||
|
||||
len = client->ReadTimeout(bufferin, BUFFERSIZE, 20);
|
||||
if (len > 0 && len < BUFFERSIZE) {
|
||||
JSONParse json;
|
||||
JSONParse jsonout;
|
||||
JSONParse jelement;
|
||||
|
||||
bufferin[len] = 0; // prevent reading behind the data
|
||||
|
||||
json.Set(bufferin);
|
||||
if (!json.GetValue("sid", &ssid)) {
|
||||
debug (0, "json.GetValue error --> sid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!json.GetValue("rid", &srid)) {
|
||||
debug (0, "json.GetValue error --> rid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
try {
|
||||
rid = stoi (srid);
|
||||
}
|
||||
catch (...) {
|
||||
rid = 0;
|
||||
debug (0, "* rid error");
|
||||
}
|
||||
|
||||
try {
|
||||
sid = stoi (ssid);
|
||||
}
|
||||
catch (...) {
|
||||
sid = 0;
|
||||
debug (0, "* sid error");
|
||||
}
|
||||
|
||||
if (sid <= 0) {
|
||||
int x, y;
|
||||
|
||||
debug (0, "* sid not set, gettin new SID");
|
||||
session = new Session(rid);
|
||||
sid = session->GetSessionID();
|
||||
LockThread();
|
||||
sessions.push_back(session);
|
||||
UnLockThread();
|
||||
}
|
||||
else {
|
||||
LockThread();
|
||||
//
|
||||
// search for session
|
||||
session = NULL;
|
||||
for (siter = sessions.begin(); siter != sessions.end(); siter++) {
|
||||
if ((*siter)->GetRandomID() == rid && ((Session*)(*siter))->GetSessionID() == sid) {
|
||||
session = (*siter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
UnLockThread();
|
||||
}
|
||||
|
||||
if (session) {
|
||||
JSONElement je;
|
||||
int retval;
|
||||
|
||||
LockThread();
|
||||
retval = session->ProcessData(&json, &jsonout);
|
||||
UnLockThread();
|
||||
|
||||
len = BUFFERSIZE;
|
||||
if (retval) {
|
||||
je.Clear();
|
||||
je.Set("success", 1);
|
||||
jsonout.AddObject(je);
|
||||
}
|
||||
else {
|
||||
je.Clear();
|
||||
je.Set("success", 0);
|
||||
jsonout.AddObject(je);
|
||||
}
|
||||
s = jsonout.ToString();
|
||||
client->Write((char*)s.c_str(), strlen(s.c_str()));
|
||||
result = 1;
|
||||
}
|
||||
else {
|
||||
// no session found
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
else if (len == 0) {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
@ -0,0 +1,111 @@
|
||||
|
||||
#ifndef _NETWORK_H_
|
||||
#define _NETWORK_H_
|
||||
|
||||
#include <UDPTCPNetwork.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "json.h"
|
||||
|
||||
|
||||
extern int next_sessionID;
|
||||
|
||||
|
||||
class Session {
|
||||
private:
|
||||
int sessionID;
|
||||
int randomID;
|
||||
list<string> changes;
|
||||
|
||||
void AddJSONRailway(JSONParse *jp);
|
||||
void DelJSONRailway(JSONParse *jp);
|
||||
|
||||
void AddJSONTurnout(JSONParse *jp);
|
||||
void DelJSONTurnout(JSONParse *jp);
|
||||
void SetJSONTurnout(JSONParse *jp);
|
||||
|
||||
void AddJSONSensor(JSONParse *jp);
|
||||
void DelJSONSensor(JSONParse *jp);
|
||||
|
||||
void AddJSONInterface(JSONParse *jp);
|
||||
void DelJSONInterface(JSONParse *jp);
|
||||
|
||||
void AddJSONLocomotive(JSONParse *jp);
|
||||
void DelJSONLocomotive(JSONParse *jp);
|
||||
void SetJSONLocomotive(JSONParse *jp);
|
||||
|
||||
public:
|
||||
Session(int rid);
|
||||
~Session();
|
||||
|
||||
// changed which need to be send to the client //
|
||||
void ChangeListPush(string chng); // push ChangeList (String must be JSON format)
|
||||
JSONElement ChangeListGet(); // get ChangeList as JSON and clear list
|
||||
void ChangesListClear(); // clear out Change list
|
||||
|
||||
int GetSessionID() { return sessionID; };
|
||||
int GetRandomID() { return randomID; };
|
||||
|
||||
int SendData(UNIX *u, string data);
|
||||
|
||||
int ProcessData(JSONParse *jin, JSONParse *jout);
|
||||
};
|
||||
|
||||
|
||||
class Network {
|
||||
private:
|
||||
void ThreadProcess();
|
||||
pthread_mutex_t mtx;
|
||||
pthread_t thread;
|
||||
int thread_running;
|
||||
|
||||
list<Session*> sessions;
|
||||
list<UNIX*> clients;
|
||||
|
||||
Session *GetSession(int Sid);
|
||||
int ServerLoop(); // loop for network connection and call clientloop if needed
|
||||
int ClientLoop(UNIX *u);
|
||||
UNIX sockserver;
|
||||
|
||||
void _ChangeListPushToAll (string changes); // not thread save
|
||||
friend class Session;
|
||||
public:
|
||||
Network();
|
||||
~Network();
|
||||
|
||||
int LockThread();
|
||||
int UnLockThread();
|
||||
|
||||
int Start();
|
||||
void Stop();
|
||||
void ChangeListPushToAll (string changes); // adds JSON compat. change string too all clients
|
||||
|
||||
int isRunning() { return thread_running; }
|
||||
protected:
|
||||
static void *ThreadEntry (void *This) { ((Network*)This)->ThreadProcess(); return NULL;};
|
||||
};
|
||||
|
||||
|
||||
#endif // _NETWORK_H_
|
@ -0,0 +1,295 @@
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
#include "debug.h"
|
||||
|
||||
Railways::Railways() {
|
||||
debug (0, "* Railways Constructor");
|
||||
height = 0;
|
||||
width = 0;
|
||||
railways = NULL;
|
||||
mtx = { 0 };
|
||||
mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
changed = 0;
|
||||
};
|
||||
|
||||
|
||||
Railways::~Railways() {
|
||||
if (railways) free (railways);
|
||||
height = 0;
|
||||
width = 0;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// thread protection: lock
|
||||
int Railways::Lock() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// thread protection: unlock
|
||||
int Railways::UnLock() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// return index inside the array (clip to boundery)
|
||||
int Railways::GetRIdx(int x, int y) {
|
||||
int _x, _y;
|
||||
|
||||
if (x < 0) _x = 0;
|
||||
else if (x >= width) _x = width-1;
|
||||
else _x = x;
|
||||
|
||||
if (y < 0) _y = 0;
|
||||
else if (y >= height) _y = height-1;
|
||||
else _y = y;
|
||||
|
||||
return (_x + _y * width);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return JSON strign with the Railway data
|
||||
// not thread safe !!!!
|
||||
JSONParse Railways::_GetJSONRailway(int x, int y) {
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
int idx = GetRIdx(x,y);
|
||||
string name = "";
|
||||
|
||||
json.Clear();
|
||||
json.AddObject("x", x);
|
||||
json.AddObject("y", y);
|
||||
json.AddObject("dir", railways[idx].dir);
|
||||
json.AddObject("altdir", railways[idx].altdir);
|
||||
json.AddObject("type", railways[idx].type);
|
||||
json.AddObject("maxspeed", railways[idx].maxspeed);
|
||||
json.AddObject("flags", railways[idx].flags);
|
||||
name = railways[idx].name;
|
||||
json.AddObject("name", name);
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return JSON strign with the Railway data
|
||||
// thread safe.
|
||||
JSONParse Railways::GetJSONRailway(int x, int y) {
|
||||
JSONParse json;
|
||||
|
||||
Lock();
|
||||
json = _GetJSONRailway(x, y);
|
||||
UnLock();
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
Railway Railways::GetRailwayFromJSON(JSONParse *j) {
|
||||
string name;
|
||||
Railway r = {
|
||||
type: RAILWAY_NOTHING,
|
||||
x: 0,
|
||||
y: 0,
|
||||
dir: 0,
|
||||
altdir: 0,
|
||||
maxspeed: -1,
|
||||
flags: 0
|
||||
};
|
||||
r.name[0] = 0;
|
||||
|
||||
j->GetValueInt("x", &r.x);
|
||||
j->GetValueInt("y", &r.y);
|
||||
j->GetValueInt("dir", &r.dir);
|
||||
j->GetValueInt("altdir", &r.altdir);
|
||||
j->GetValueInt("type", &r.type);
|
||||
j->GetValueInt("maxspeed", &r.maxspeed);
|
||||
j->GetValueInt("flags", &r.flags);
|
||||
j->GetValue("name", &name);
|
||||
strncpy (r.name, name.c_str(), REFERENCENAME_LEN);
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return some data about the railway/tracks
|
||||
//
|
||||
JSONParse Railways::GetJSONTrack() {
|
||||
JSONParse json;
|
||||
JSONParse jsondata;
|
||||
JSONElement je;
|
||||
|
||||
json.Clear();
|
||||
json.AddObject("height", height);
|
||||
json.AddObject("width", width);
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
//
|
||||
// change railway
|
||||
// return 1 on change
|
||||
int Railways::Change(Railway *rw) {
|
||||
int x, y;
|
||||
int result = 1;
|
||||
JSONParse json;
|
||||
|
||||
if (rw == NULL) return 0;
|
||||
Lock();
|
||||
|
||||
if (rw->x < 0 || rw->x >= width) result = 0;
|
||||
else if (rw->y < 0 || rw->y >= height) result = 0;
|
||||
else if (rw->dir < 0 || rw->dir > 6) result = 0;
|
||||
else {
|
||||
changed = true;
|
||||
result = 1;
|
||||
|
||||
if (rw->dir == 0) rw->type == RAILWAY_NOTHING;
|
||||
|
||||
//
|
||||
// need to delete?
|
||||
if (rw->type == RAILWAY_NOTHING) {
|
||||
Railway *r = &railways[GetRIdx(rw->x, rw->y)];
|
||||
|
||||
r->type = RAILWAY_NOTHING;
|
||||
r->dir = 0;
|
||||
r->altdir = 0;
|
||||
r->flags = 0;
|
||||
r->maxspeed = 0;
|
||||
r->x = rw->x;
|
||||
r->y = rw->y;
|
||||
r->name[0] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// add normal railway
|
||||
else if (rw->type == RAILWAY_NORMAL) {
|
||||
railways[GetRIdx(rw->x, rw->y)] = *rw;
|
||||
}
|
||||
|
||||
//
|
||||
// add normal railway
|
||||
else if (rw->type < RAILWAY_MAX) {
|
||||
railways[GetRIdx(rw->x, rw->y)] = *rw;
|
||||
}
|
||||
|
||||
else {
|
||||
debug (DEBUG_INFO, "%s:%d add unknown %d,%d dir(%d) type:%d", __FILE__, __LINE__, rw->x, rw->y, rw->dir, rw->type);
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
return result;
|
||||
};
|
||||
|
||||
//
|
||||
// redefine the size of the track, keep data
|
||||
void Railways::SetSize (int neww, int newh) {
|
||||
Railway *rarray = railways;
|
||||
int ow = width;
|
||||
int oh = height;
|
||||
int x, y;
|
||||
|
||||
debug (0, "* Railways::SetSize (%d, %d)", neww, newh);
|
||||
|
||||
Lock();
|
||||
|
||||
//
|
||||
// old values saved during call up of the function, create new array for the railways data
|
||||
railways = NULL;
|
||||
_New (neww, newh);
|
||||
|
||||
//
|
||||
// copy old data
|
||||
for (x = 0; x < ow && x < width; x++)
|
||||
for (y = 0; y < oh && x < height; y++)
|
||||
railways[x + y * width] = rarray[x + y * oh];
|
||||
free (rarray);
|
||||
UnLock();
|
||||
};
|
||||
|
||||
|
||||
void Railways::_New (int neww, int newh) {
|
||||
int x, y;
|
||||
|
||||
debug (0, "* Railways New");
|
||||
|
||||
//
|
||||
// clip to minimum and maximum sizes
|
||||
if (neww < RAILWAYS_MIN_WIDTH) width = RAILWAYS_MIN_WIDTH;
|
||||
else if (neww > RAILWAYS_MAX_WIDTH) width = RAILWAYS_MAX_WIDTH;
|
||||
else width = neww;
|
||||
if (newh < RAILWAYS_MIN_HEIGHT) width = RAILWAYS_MIN_HEIGHT;
|
||||
else if (newh > RAILWAYS_MAX_HEIGHT) width = RAILWAYS_MAX_HEIGHT;
|
||||
else height = newh;
|
||||
|
||||
//
|
||||
// if memory is already allocated free it first
|
||||
if (railways != NULL) free (railways);
|
||||
|
||||
//
|
||||
// allocate memory and reset memory
|
||||
railways = (Railway*) malloc (sizeof (Railway) * width * height);
|
||||
for (x = 0; x < width; x++) for (y = 0; y < height; y++) {
|
||||
Railway *r = &railways[GetRIdx(x, y)];
|
||||
r->type = RAILWAY_NOTHING;
|
||||
r->dir = 0;
|
||||
r->altdir = 0;
|
||||
r->flags = 0;
|
||||
r->maxspeed = 0;
|
||||
r->x = x;
|
||||
r->y = y;
|
||||
r->name[0] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void Railways::New (int neww, int newh) {
|
||||
Lock();
|
||||
_New (neww, newh);
|
||||
UnLock();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// append all data to the givin jasonobject
|
||||
void Railways::GetJSONAll(JSONParse *json) {
|
||||
int x, y;
|
||||
|
||||
if (json == NULL) return;
|
||||
|
||||
Lock();
|
||||
|
||||
json->AddObject("track", GetJSONTrack());
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (railways[GetRIdx(x, y)].type != RAILWAY_NOTHING) {
|
||||
json->AddObject("railway", _GetJSONRailway(x, y));
|
||||
}
|
||||
|
||||
UnLock();
|
||||
}
|
||||
|
||||
//
|
||||
// get railway element
|
||||
// thread safe
|
||||
Railway Railways::Get(int x, int y) {
|
||||
Railway r;
|
||||
|
||||
Lock();
|
||||
r = railways[GetRIdx(x, y)];
|
||||
UnLock();
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
|
||||
|
@ -0,0 +1,95 @@
|
||||
|
||||
#ifndef _RAILWAY_H_
|
||||
#define _RAILWAY_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
|
||||
enum {
|
||||
RAILWAY_NOTHING = 0,
|
||||
RAILWAY_NORMAL,
|
||||
RAILWAY_CROSSING,
|
||||
RAILWAY_TURNOUT,
|
||||
RAILWAY_SENSOR,
|
||||
RAILWAY_CONNECTOR,
|
||||
RAILWAY_BUTTON, // just a simple button on the track to press
|
||||
RAILWAY_TEXT,
|
||||
RAILWAY_BLOCK,
|
||||
|
||||
RAILWAY_MAX
|
||||
};
|
||||
|
||||
|
||||
#define RAILWAYS_MIN_WIDTH 40
|
||||
#define RAILWAYS_MIN_HEIGHT 25
|
||||
#define RAILWAYS_MAX_WIDTH 500
|
||||
#define RAILWAYS_MAX_HEIGHT 500
|
||||
|
||||
|
||||
// direktion
|
||||
//
|
||||
// +---+ +---+ +---+ +---+
|
||||
// | | | | | | | |/ |
|
||||
// 0| | 1| | | 2|---| 3| |
|
||||
// | | | | | | | | |
|
||||
// +---+ +---+ +---+ +---+
|
||||
//
|
||||
// +---+ +---+ +---+ +---+
|
||||
// | \| | | | | | |
|
||||
// 4| | 5| | 6| | 7| |
|
||||
// | | | /| |\ | | |
|
||||
// +---+ +---+ +---+ +---+
|
||||
//
|
||||
|
||||
|
||||
struct s_Railway {
|
||||
int type;
|
||||
int x;
|
||||
int y;
|
||||
int dir;
|
||||
int altdir; // turnout or crossing
|
||||
int maxspeed;
|
||||
int flags; // not defined yet
|
||||
char name[REFERENCENAME_LEN]; // reference name
|
||||
} typedef Railway;
|
||||
|
||||
|
||||
class Railways {
|
||||
private:
|
||||
Railway *railways;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int changed;
|
||||
|
||||
pthread_mutex_t mtx;
|
||||
int Lock();
|
||||
int UnLock();
|
||||
int GetRIdx(int x, int y);
|
||||
JSONParse _GetJSONRailway(int x, int y);
|
||||
void _New (int w, int h);
|
||||
public:
|
||||
|
||||
Railways();
|
||||
~Railways();
|
||||
|
||||
void New (int w, int h);
|
||||
void SetSize (int w, int h);
|
||||
Railway Get(int x, int y);
|
||||
Railways* GetBlock(int x, int y, int w, int h);
|
||||
int Set(Railway *rw);
|
||||
int SetBlock(Railway *rw, int cnt);
|
||||
int GetHeight () {return height;};
|
||||
int GetWidth () {return width;};
|
||||
int IsChanged() { return changed; };
|
||||
void ClearChanged() { changed = 0; };
|
||||
int Change(Railway *rw);
|
||||
|
||||
Railway RailwayGet(int x, int y) {return railways[GetRIdx(x, y)];};
|
||||
JSONParse GetJSONRailway(int x, int y);
|
||||
JSONParse GetJSONTrack();
|
||||
void GetJSONAll(JSONParse *json);
|
||||
Railway GetRailwayFromJSON(JSONParse *j);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,190 @@
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "sensor.h"
|
||||
|
||||
|
||||
Sensors::Sensors () {
|
||||
changed = 0;
|
||||
sensors = (Sensor*) malloc(sizeof(Sensor)*SENSORS_MAX);
|
||||
max = SENSORS_MAX;
|
||||
};
|
||||
|
||||
Sensors::~Sensors() {
|
||||
free (sensors);
|
||||
sensors = NULL;
|
||||
max = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int Sensors::Lock() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
int Sensors::UnLock() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
JSONParse Sensors::_GetJSON(int idx) {
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
string s = "";
|
||||
|
||||
json.Clear();
|
||||
|
||||
s = sensors[idx].name; json.AddObject("name", s);
|
||||
s = sensors[idx].ifname; json.AddObject("ifname", s);
|
||||
json.AddObject("addr", sensors[idx].addr);
|
||||
json.AddObject("flags", sensors[idx].flags);
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
JSONParse Sensors::GetJSON(string name) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
jp.Clear();
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (sensors[i].name[0] != 0) {
|
||||
if (name.compare(sensors[i].name) == 0) {
|
||||
jp = _GetJSON(i);
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return jp;
|
||||
};
|
||||
|
||||
|
||||
void Sensors::GetJSONAll(JSONParse *json) {
|
||||
int i, cnt;
|
||||
JSONElement je;
|
||||
|
||||
Lock();
|
||||
|
||||
//
|
||||
// write all railway data
|
||||
// create json object array manualy
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "sensors";
|
||||
for (cnt = 0, i = 0; i < max; i++)
|
||||
if (sensors[i].name[0] != 0) {
|
||||
if (cnt != 0) je.value += ","; // not first element
|
||||
je.value += _GetJSON(i).ToString();
|
||||
cnt++;
|
||||
}
|
||||
json->AddObject(je);
|
||||
|
||||
UnLock();
|
||||
};
|
||||
|
||||
|
||||
Sensor Sensors::GetSensorFromJSON(JSONParse *j) {
|
||||
Sensor se;
|
||||
string s;
|
||||
|
||||
se.name[0] = 0;
|
||||
se.ifname[0] = 0;
|
||||
se.addr = 0;
|
||||
se.flags = 0;
|
||||
|
||||
j->GetValue("name", &s);
|
||||
strncpy (se.name, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValue("ifname", &s);
|
||||
strncpy (se.ifname, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValueInt("addr", &se.addr);
|
||||
j->GetValueInt("flags", &se.flags);
|
||||
|
||||
return se;
|
||||
};
|
||||
|
||||
|
||||
int Sensors::Change(Sensor *se) {
|
||||
int i;
|
||||
int ifree = -1;
|
||||
|
||||
Lock();
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (sensors[i].name[0] != 0) {
|
||||
// found element
|
||||
if (strncmp(sensors[i].name, se->name, REFERENCENAME_LEN) == 0) {
|
||||
ifree = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ifree == -1) ifree = i;
|
||||
}
|
||||
// element not found add new element
|
||||
if (ifree != -1 && ifree < max) {
|
||||
sensors[ifree] = *se;
|
||||
strncpy (sensors[ifree].name, se->name, REFERENCENAME_LEN);
|
||||
strncpy (sensors[ifree].ifname, se->ifname, REFERENCENAME_LEN);
|
||||
}
|
||||
|
||||
changed = 1;
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Sensors::Delete(string name) {
|
||||
int i;
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (sensors[i].name[0] != 0) {
|
||||
if (name.compare(sensors[i].name) == 0) {
|
||||
sensors[i].name[0] = 0;
|
||||
sensors[i].ifname[0] = 0;
|
||||
sensors[i].addr = 0;
|
||||
sensors[i].flags = 0;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// got some information from an interface..
|
||||
void Sensors::SetFromBus(string name, int addr, int active) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
for (i = 0; i < max; i++) if (sensors[i].name[0] != 0) {
|
||||
if (strncmp (sensors[i].ifname, name.c_str(), REFERENCENAME_LEN) == 0 && sensors[i].addr == addr) {
|
||||
debug (0, "* Sensor %s changed:%d", sensors[i].name, active);
|
||||
if (sensors[i].flags & SENSOR_F_INVERSE) {
|
||||
if (active) sensors[i].flags &= ~SENSOR_F_ACTIVE;
|
||||
else sensors[i].flags |= SENSOR_F_ACTIVE;
|
||||
}
|
||||
else {
|
||||
if (active) sensors[i].flags |= SENSOR_F_ACTIVE;
|
||||
else sensors[i].flags &= ~SENSOR_F_ACTIVE;
|
||||
}
|
||||
|
||||
jp.AddObject("sensor", _GetJSON(i));
|
||||
if(network) network->ChangeListPushToAll(jp.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
jp.AddObject("infoline", "Sensor:"+name+"["+ to_string(addr) +"]");
|
||||
if(network) network->ChangeListPushToAll(jp.ToString());
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,48 @@
|
||||
|
||||
#ifndef _SENSOR_H_
|
||||
#define _SENSOR_H_
|
||||
|
||||
#define SENSOR_F_INVERSE 0x0001
|
||||
#define SENSOR_F_ACTIVE 0x0002
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
|
||||
struct s_Sensor {
|
||||
char name[REFERENCENAME_LEN];
|
||||
char ifname[REFERENCENAME_LEN];
|
||||
int addr;
|
||||
int flags;
|
||||
} typedef Sensor;
|
||||
|
||||
class Sensors {
|
||||
private:
|
||||
Sensor *sensors;
|
||||
int max;
|
||||
int changed;
|
||||
|
||||
pthread_mutex_t mtx;
|
||||
int Lock();
|
||||
int UnLock();
|
||||
|
||||
// not thread safe
|
||||
JSONParse _GetJSON(int idx);
|
||||
public:
|
||||
Sensors();
|
||||
~Sensors();
|
||||
|
||||
bool IsChanged() { return changed; }
|
||||
void ClearChanged() { changed = 0; };
|
||||
|
||||
int Change(Sensor *se);
|
||||
int Delete(string name);
|
||||
|
||||
JSONParse GetJSON(string name);
|
||||
void GetJSONAll(JSONParse *json);
|
||||
Sensor GetSensorFromJSON(JSONParse *j);
|
||||
|
||||
void SetFromBus(string name, int addr, int active);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,194 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "modelbahn.h"
|
||||
|
||||
int Server::Load() {
|
||||
string f = DEFAULT_DATADIR;
|
||||
f = f + "/track.json";
|
||||
|
||||
Load (f);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
int Server::Save() {
|
||||
struct stat sbuf;
|
||||
string f = DEFAULT_DATADIR;
|
||||
string nf;
|
||||
|
||||
//
|
||||
// check if the folder does exists.
|
||||
if (stat (f.c_str(), &sbuf) != 0) {
|
||||
debug (DEBUG_ERROR, "* Track::Save could not find directory '%s'. Creating it.", f.c_str());
|
||||
if (mkdir (f.c_str(), 0755) != 0) {
|
||||
debug (DEBUG_ERROR, "* Track::Save could not create directory '%s'. (%s)", f.c_str(), strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ((sbuf.st_mode & S_IFMT) != S_IFDIR) {
|
||||
debug (DEBUG_ERROR, "* Track::Save could not stat directory: '%s'. (%s)", f.c_str(), strerror(errno));
|
||||
if (errno != EINTR) return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// check if the file exsists
|
||||
f = DEFAULT_DATADIR; f = f + "/track.json";
|
||||
nf = DEFAULT_DATADIR; nf = nf + "/track.json.backup." + to_string(time(NULL));
|
||||
if (stat (f.c_str(), &sbuf) == 0) {
|
||||
debug (DEBUG_INFO, "* Track::Save rename backup file to: %s", nf.c_str());
|
||||
if (rename (f.c_str(), nf.c_str())) {
|
||||
debug (DEBUG_ERROR, "* Track::Save could not rename file '%s' to '%s'. Error:(%s)",
|
||||
f.c_str(), nf.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return Save(f);
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// loading and saving of the file is done here. We do no checks
|
||||
// here.
|
||||
//
|
||||
int Server::Load(string fn) {
|
||||
int fd;
|
||||
size_t len;
|
||||
struct stat sbuf;
|
||||
JSONParse json;
|
||||
JSONParse jtmp;
|
||||
char *buf = NULL;
|
||||
string s;
|
||||
int x, y, i;
|
||||
|
||||
debug (DEBUG_INFO, "* Load File:%s", fn.c_str());
|
||||
if (stat (fn.c_str(), &sbuf) == 0) {
|
||||
buf = (char *) malloc(sbuf.st_size+1);
|
||||
memset (buf, 0x0, sbuf.st_size+1);
|
||||
fd = open (fn.c_str(), O_RDONLY);
|
||||
len = read (fd, buf, sbuf.st_size);
|
||||
close (fd);
|
||||
|
||||
// everything read?
|
||||
if (len < sbuf.st_size) {
|
||||
free (buf);
|
||||
debug (DEBUG_ERROR, "* Reading Track File Failed. (len < filesize)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = buf;
|
||||
json.Set(s);
|
||||
}
|
||||
else {
|
||||
debug (DEBUG_ERROR, "* cloud not stat file (%s)", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// json holds all the data
|
||||
|
||||
//
|
||||
// read track values
|
||||
json.GetObject("track", &jtmp);
|
||||
jtmp.GetValueInt("width", &x);
|
||||
jtmp.GetValueInt("height", &y);
|
||||
railways.New (x, y);
|
||||
|
||||
//
|
||||
// read railways
|
||||
Railway rw;
|
||||
for (i = 0; json.GetObjectIdx("railways", i, &jtmp); i++) {
|
||||
rw = railways.GetRailwayFromJSON(&jtmp);
|
||||
railways.Change(&rw);
|
||||
}
|
||||
|
||||
//
|
||||
// read interfaces
|
||||
Interface iface;
|
||||
for (i = 0; json.GetObjectIdx("interfaces", i, &jtmp); i++) {
|
||||
iface = interfaces.GetInterfaceFromJSON(&jtmp);
|
||||
interfaces.Change(&iface);
|
||||
}
|
||||
|
||||
//
|
||||
// read locomotives
|
||||
Locomotive loco;
|
||||
for (i = 0; json.GetObjectIdx("locomotives", i, &jtmp); i++) {
|
||||
loco = locomotives.GetLocomotiveFromJSON(&jtmp);
|
||||
locomotives.Change(&loco);
|
||||
}
|
||||
|
||||
//
|
||||
// read sensors
|
||||
Sensor se;
|
||||
for (i = 0; json.GetObjectIdx("sensors", i, &jtmp); i++) {
|
||||
se = sensors.GetSensorFromJSON(&jtmp);
|
||||
sensors.Change(&se);
|
||||
}
|
||||
|
||||
//
|
||||
// read turnouts
|
||||
Turnout to;
|
||||
for (i = 0; json.GetObjectIdx("turnouts", i, &jtmp); i++) {
|
||||
to = turnouts.GetTurnoutFromJSON(&jtmp);
|
||||
turnouts.Change(&to);
|
||||
}
|
||||
|
||||
|
||||
railways.ClearChanged();
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Server::Save(string fn) {
|
||||
FILE *f;
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
int x, y, cnt;
|
||||
|
||||
debug (DEBUG_INFO, "* Save File:%s", fn.c_str());
|
||||
json.Clear();
|
||||
json.AddObject("track", railways.GetJSONTrack());
|
||||
|
||||
//
|
||||
// write all railway data
|
||||
// create json object array manualy
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "railways";
|
||||
for (cnt = 0, x = 0; x < railways.GetWidth(); x++) for (y = 0; y < railways.GetHeight(); y++)
|
||||
if (railways.Get(x, y).type != RAILWAY_NOTHING) {
|
||||
if (cnt != 0) je.value += ","; // not first element
|
||||
je.value += railways.GetJSONRailway(x, y).ToString();
|
||||
cnt++;
|
||||
}
|
||||
json.AddObject(je);
|
||||
|
||||
//
|
||||
// write all interfaces
|
||||
interfaces.GetJSONAll(&json);
|
||||
|
||||
//
|
||||
// write all locomotives
|
||||
locomotives.GetJSONAll(&json);
|
||||
|
||||
//
|
||||
// write all sensors
|
||||
sensors.GetJSONAll(&json);
|
||||
|
||||
//
|
||||
// write all turnouts
|
||||
turnouts.GetJSONAll(&json);
|
||||
|
||||
|
||||
f = fopen (fn.c_str(), "w");
|
||||
fprintf (f, "%s", json.ToString().c_str());
|
||||
fclose (f);
|
||||
|
||||
railways.ClearChanged();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
@ -0,0 +1,105 @@
|
||||
|
||||
#include <string>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
|
||||
|
||||
int Server::Start() {
|
||||
int err;
|
||||
pthread_attr_t attr;
|
||||
mtx = { 0 };
|
||||
mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
thread_running = 1;
|
||||
pthread_attr_init (&attr);
|
||||
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
|
||||
err = pthread_create (&thread, &attr, ThreadEntry, this);
|
||||
if (err != 0) {
|
||||
debug (DEBUG_ERROR, (char*)"%s(%s:%d) pthread_create errror: %s", __FUNCTION__, __FILE__, __LINE__, strerror (errno));
|
||||
running = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
Server::Server() {
|
||||
thread = 0;
|
||||
thread_running = 0;
|
||||
railways.SetSize(200, 200);
|
||||
Load ();
|
||||
};
|
||||
|
||||
|
||||
Server::~Server() {
|
||||
if (IsChanged()) Save();
|
||||
};
|
||||
|
||||
|
||||
void Server::ThreadProcess() {
|
||||
int i = 0;
|
||||
while (running) {
|
||||
interfaces.Loop();
|
||||
turnouts.Loop();
|
||||
usleep (25000);
|
||||
}
|
||||
debug (0, "Server::ThreadProcess Finished");
|
||||
thread_running = 0;
|
||||
};
|
||||
|
||||
|
||||
void Server::LockThread() {
|
||||
debug(DEBUG_INFO, "%s:%d Server::LockThread", __FILE__, __LINE__);
|
||||
pthread_mutex_lock (&mtx);
|
||||
};
|
||||
|
||||
|
||||
void Server::UnLockThread() {
|
||||
debug (DEBUG_INFO, "%s:%d Server::UnLockThreads", __FILE__, __LINE__);
|
||||
pthread_mutex_unlock (&mtx);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return JSONObject with all data
|
||||
void Server::GetJSONAll(JSONParse *json) {
|
||||
debug (DEBUG_INFO, "* Track::GetJSONAll data");
|
||||
if (json == NULL) return;
|
||||
|
||||
railways.GetJSONAll(json);
|
||||
interfaces.GetJSONAll(json);
|
||||
sensors.GetJSONAll(json);
|
||||
locomotives.GetJSONAll(json);
|
||||
turnouts.GetJSONAll(json);
|
||||
}
|
||||
|
||||
|
||||
bool Server::IsChanged() {
|
||||
if (railways.IsChanged() ||
|
||||
interfaces.IsChanged() ||
|
||||
locomotives.IsChanged() ||
|
||||
sensors.IsChanged() ||
|
||||
turnouts.IsChanged()) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,135 @@
|
||||
|
||||
#ifndef _SERVER_H_
|
||||
#define _SERVER_H_
|
||||
|
||||
#include <string>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "json.h"
|
||||
#include "modelbahn.h"
|
||||
#include "turnout.h"
|
||||
#include "railway.h"
|
||||
#include "locomotive.h"
|
||||
#include "sensor.h"
|
||||
#include "interface.h"
|
||||
|
||||
class Server {
|
||||
private:
|
||||
pthread_mutex_t mtx;
|
||||
pthread_t thread;
|
||||
int thread_running;
|
||||
Turnouts turnouts;
|
||||
Sensors sensors;
|
||||
Railways railways;
|
||||
Locomotives locomotives;
|
||||
Interfaces interfaces;
|
||||
|
||||
void ThreadProcess();
|
||||
void LoopCheckChanges();
|
||||
bool IsChanged();
|
||||
|
||||
int Load(string fn);
|
||||
int Save(string fn);
|
||||
|
||||
friend class Interfaces;
|
||||
friend class InterfacesZ21;
|
||||
friend class Locomotives;
|
||||
friend class Sensors;
|
||||
friend class Turnouts;
|
||||
public:
|
||||
/////////////////////////////////////////
|
||||
// functions here are required to be thread save
|
||||
|
||||
Server();
|
||||
~Server();
|
||||
|
||||
int Start();
|
||||
int isRunning() { return thread_running; }
|
||||
|
||||
void LockThread();
|
||||
void UnLockThread();
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// General Commands, for controlling trains,
|
||||
// turnouts and sensors
|
||||
//
|
||||
void PowerOnOff(int onoff) { interfaces.PowerOnOff(onoff); };
|
||||
|
||||
int GetHeight() { return railways.GetHeight(); };
|
||||
int GetWidth() { return railways.GetWidth(); };
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Railway
|
||||
int RailwayChange(Railway *rw) { return railways.Change(rw);};
|
||||
JSONParse RailwayGetJSONTrack() { return railways.GetJSONTrack(); };
|
||||
JSONParse RailwayGetJSONRailway (int x, int y) { return railways.GetJSONRailway(x, y); };
|
||||
Railway GetRailwayFromJSON(JSONParse *j) { return railways.GetRailwayFromJSON(j); };
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Turnout
|
||||
int TurnoutChange(Turnout *t) { return turnouts.Change(t); };
|
||||
Turnout TurnoutFromJSON(JSONParse *j) { return turnouts.GetTurnoutFromJSON(j); };
|
||||
JSONParse TurnoutGetJSON(string name) { return turnouts.GetJSON(name); };
|
||||
int TurnoutDelete(string name) { return turnouts.Delete(name); };
|
||||
int TurnoutSet(string name, int active) { return turnouts.Set(name, active); };
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Interface
|
||||
int InterfaceChange(Interface *i) { return interfaces.Change(i); };
|
||||
Interface InterfaceFromJSON(JSONParse *j) { return interfaces.GetInterfaceFromJSON(j); };
|
||||
JSONParse InterfaceGetJSON(string name) { return interfaces.GetJSON(name); };
|
||||
int InterfaceDelete(string name) { return interfaces.Delete(name); };
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Locomotive
|
||||
int LocomotiveChange(Locomotive *l) { return locomotives.Change(l); };
|
||||
Locomotive LocomotiveFromJSON(JSONParse *j) { return locomotives.GetLocomotiveFromJSON(j); };
|
||||
JSONParse LocomotiveGetJSON(string name) { return locomotives.GetJSON(name); };
|
||||
int LocomotiveDelete(string name) { return locomotives.Delete(name); };
|
||||
int LocomotiveSetSpeed(string name, int speed) { return locomotives.SetSpeed(name, speed); };
|
||||
int LocomotiveSetFunction(string name, int func, int value) { return locomotives.SetFunction(name, func, value); };
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Sensor
|
||||
int SensorChange(Sensor *s) { return sensors.Change(s); };
|
||||
Sensor SensorFromJSON(JSONParse *j) { return sensors.GetSensorFromJSON(j); };
|
||||
JSONParse SensorGetJSON(string name) { return sensors.GetJSON(name); };
|
||||
int SensorDelete(string name) { return sensors.Delete(name); };
|
||||
|
||||
void GetJSONAll(JSONParse *json);
|
||||
|
||||
/////////////////////////////////////////
|
||||
// reports from interfaces
|
||||
int LocomotiveAddrSpeed(string name, int addr, int speed) { return locomotives.SetSpeedFromBus(name, addr, speed); };
|
||||
int LocomotiveAddrDirection(string name, int addr, int reverse) { return locomotives.SetDirectionFromBus(name, addr, reverse); };
|
||||
int TurnoutAddrMode(string name, int addr, int active) { turnouts.SetFromBus(name, addr, active); return 1; };
|
||||
int SensorAddrChange(string name, int addr, int active) { sensors.SetFromBus(name, addr, active); return 1; };
|
||||
|
||||
|
||||
//
|
||||
// Load Save Part
|
||||
int Load();
|
||||
int Save();
|
||||
|
||||
protected:
|
||||
static void *ThreadEntry (void *This) { ((Server*)This)->ThreadProcess(); return NULL;};
|
||||
};
|
||||
|
||||
#endif // _SERVER_H_
|
@ -0,0 +1,510 @@
|
||||
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include <list>
|
||||
|
||||
int next_sessionID = 1;
|
||||
|
||||
int Session::SendData(UNIX *u, string data) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
Session::Session(int rid) {
|
||||
sessionID = random();
|
||||
randomID = rid;
|
||||
changes.clear();
|
||||
};
|
||||
|
||||
Session::~Session() {
|
||||
changes.clear();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// process data and send result back
|
||||
// it will process the command, and reply with all known
|
||||
// changes.
|
||||
//
|
||||
int Session::ProcessData(JSONParse *jin, JSONParse *jout) {
|
||||
JSONElement je;
|
||||
JSONParse json;
|
||||
JSONParse jsondata;
|
||||
string command;
|
||||
list<JSONElement> elements;
|
||||
list<JSONElement>::iterator iter;
|
||||
jout->Clear();
|
||||
|
||||
// debug (0, "* Session sid:%d rid:%d", sessionID, randomID);
|
||||
|
||||
//
|
||||
// found command
|
||||
if (jin->GetValue("command", &command) == 1) {
|
||||
//
|
||||
// editing elements
|
||||
//
|
||||
debug (0, "%s:%d JIN:%s", __FILE__, __LINE__, jin->ToString().c_str());
|
||||
if (command.compare("addrailway") == 0) {
|
||||
debug (0, "* Session Add Railways");
|
||||
AddJSONRailway(jin);
|
||||
}
|
||||
else if (command.compare("delrailway") == 0) {
|
||||
debug (0, "* Session Del Railways");
|
||||
DelJSONRailway(jin);
|
||||
}
|
||||
else if (command.compare("addinterface") == 0) {
|
||||
debug (0, "* Session Add Interface");
|
||||
AddJSONInterface(jin);
|
||||
}
|
||||
else if (command.compare("delinterface") == 0) {
|
||||
debug (0, "* Session Del Interface");
|
||||
DelJSONInterface(jin);
|
||||
}
|
||||
else if (command.compare("addsensor") == 0) {
|
||||
debug (0, "* Session Add Sensor");
|
||||
AddJSONSensor(jin);
|
||||
}
|
||||
else if (command.compare("delsensor") == 0) {
|
||||
debug (0, "* Session del Sensor");
|
||||
DelJSONSensor(jin);
|
||||
}
|
||||
else if (command.compare("addturnout") == 0) {
|
||||
debug (0, "* Session Add Turnout");
|
||||
AddJSONTurnout(jin);
|
||||
}
|
||||
else if (command.compare("delturnout") == 0) {
|
||||
debug (0, "* Session del Turnout");
|
||||
DelJSONTurnout(jin);
|
||||
}
|
||||
else if (command.compare("addlocomotive") == 0) {
|
||||
debug (0, "* Session Add Locomotive");
|
||||
AddJSONLocomotive(jin);
|
||||
}
|
||||
else if (command.compare("dellocomotive") == 0) {
|
||||
debug (0, "* Session Del Locomotive");
|
||||
DelJSONLocomotive(jin);
|
||||
}
|
||||
|
||||
//
|
||||
// locomotives
|
||||
//
|
||||
else if (command.compare("setlocomotive") == 0) {
|
||||
SetJSONLocomotive(jin);
|
||||
}
|
||||
//
|
||||
// locomotives
|
||||
//
|
||||
else if (command.compare("setturnout") == 0) {
|
||||
SetJSONTurnout(jin);
|
||||
}
|
||||
//
|
||||
// poweron / poweroff
|
||||
//
|
||||
else if (command.compare("poweron") == 0) {
|
||||
debug (0, "* Session Poweron");
|
||||
server->PowerOnOff(1);
|
||||
}
|
||||
else if (command.compare("poweroff") == 0) {
|
||||
debug (0, "* Session Poweroff");
|
||||
server->PowerOnOff(0);
|
||||
}
|
||||
|
||||
else if (command.compare("save") == 0) {
|
||||
debug (0, "* Save All");
|
||||
server->Save();
|
||||
}
|
||||
else if (command.compare("getall") == 0) {
|
||||
json.Clear();
|
||||
server->GetJSONAll(&json);
|
||||
|
||||
// debuggin maybe we need to fix this somehow
|
||||
elements = json.GetElements();
|
||||
for (iter = elements.begin(); iter != elements.end(); iter++)
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
je = ChangeListGet();
|
||||
jout->AddObject(je);
|
||||
jout->AddObject("sid", sessionID);
|
||||
jout->AddObject("rid", randomID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// add chenges which need to be send to the clients
|
||||
//
|
||||
void Session::ChangeListPush(string chng) {
|
||||
changes.push_back(chng);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// get the changes as json string and clear list of changes
|
||||
//
|
||||
JSONElement Session::ChangeListGet() {
|
||||
JSONElement je;
|
||||
list<string>::iterator iter;
|
||||
|
||||
// debug (0, "* Session::ChangeListGet cnt:%d", changes.size());
|
||||
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "changes";
|
||||
je.value = "[";
|
||||
|
||||
for (iter = changes.begin(); iter != changes.end(); iter++) {
|
||||
if (iter != changes.begin()) je.value += ",\n ";
|
||||
else je.value += "\n ";
|
||||
je.value += (*iter);
|
||||
}
|
||||
|
||||
changes.clear();
|
||||
|
||||
je.value += "]";
|
||||
|
||||
// debug (0, "* Session::ChangeListGet string:'%s'", je.GetString().c_str());
|
||||
|
||||
return je;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// commands send from the client to the server
|
||||
//
|
||||
// add a new jsonrailway to the server the JSONParse Object
|
||||
// will contains the full JSON string from the web page
|
||||
//
|
||||
void Session::AddJSONRailway(JSONParse *jp) {
|
||||
int i;
|
||||
JSONParse element;
|
||||
JSONParse pos;
|
||||
JSONParse jout;
|
||||
Railway r;
|
||||
list<Railway> l;
|
||||
|
||||
if (server == NULL) return;
|
||||
|
||||
server->LockThread();
|
||||
for (i = 0; jp->GetObjectIdx("rail", i, &element); i++) {
|
||||
debug (0, "%s:%d AddJSONRailway Element '%s'", __FILE__, __LINE__, element.ToString().c_str());
|
||||
r = server->GetRailwayFromJSON(&element);
|
||||
server->RailwayChange(&r);
|
||||
jout.Clear();
|
||||
jout.AddObject("railway", server->RailwayGetJSONRailway(r.x, r.y));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// delete some jsonrailway from the server the JSONParse Object
|
||||
// will contains the full JSON string from the web page
|
||||
//
|
||||
void Session::DelJSONRailway(JSONParse *jp) {
|
||||
int i;
|
||||
JSONParse element;
|
||||
JSONParse pos;
|
||||
JSONParse jout;
|
||||
Railway r;
|
||||
|
||||
if (server == NULL) return;
|
||||
|
||||
server->LockThread();
|
||||
for (i = 0; jp->GetObjectIdx("rail", i, &element); i++) {
|
||||
debug (0, "%s:%d DelJSONRailway Element %s", __FILE__, __LINE__, element.ToString().c_str());
|
||||
r = server->GetRailwayFromJSON(&element);
|
||||
r.type = RAILWAY_NOTHING;
|
||||
server->RailwayChange(&r);
|
||||
jout.Clear();
|
||||
jout.AddObject("railway", server->RailwayGetJSONRailway(r.x, r.y));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// add new interface
|
||||
//
|
||||
void Session::AddJSONInterface(JSONParse *jp) {
|
||||
Interface iface;
|
||||
JSONParse jiface;
|
||||
JSONParse jout;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("interface", &jiface);
|
||||
iface = server->InterfaceFromJSON(&jiface);
|
||||
if (iface.name[0] != 0) {
|
||||
debug (0, "%s:%d AddJSONInterface Element %s", __FILE__, __LINE__, iface.name);
|
||||
// add element
|
||||
server->InterfaceChange(&iface);
|
||||
jout.Clear();
|
||||
jout.AddObject("interface", server->InterfaceGetJSON(iface.name));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Delete interface
|
||||
//
|
||||
void Session::DelJSONInterface(JSONParse *jp) {
|
||||
Interface iface;
|
||||
JSONParse jiface;
|
||||
JSONParse jout;
|
||||
string s;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("interface", &jiface);
|
||||
iface = server->InterfaceFromJSON(&jiface);
|
||||
if (iface.name[0] != 0) {
|
||||
debug (0, "%s:%d DelJSONInterface Element %s", __FILE__, __LINE__, iface.name);
|
||||
// add element
|
||||
server->InterfaceDelete(iface.name);
|
||||
jout.Clear();
|
||||
s = iface.name;
|
||||
jout.AddObject("interfacedelete", s);
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// add new Sensor
|
||||
//
|
||||
void Session::AddJSONSensor(JSONParse *jp) {
|
||||
Sensor se;
|
||||
JSONParse jtmp;
|
||||
JSONParse jout;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("sensor", &jtmp);
|
||||
se = server->SensorFromJSON(&jtmp);
|
||||
if (se.name[0] != 0) {
|
||||
debug (0, "%s:%d AddJSONSensor Element %s", __FILE__, __LINE__, se.name);
|
||||
// add element
|
||||
server->SensorChange(&se);
|
||||
jout.Clear();
|
||||
jout.AddObject("sensor", server->SensorGetJSON(se.name));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Delete Sensor
|
||||
//
|
||||
void Session::DelJSONSensor(JSONParse *jp) {
|
||||
Sensor se;
|
||||
JSONParse jtmp;
|
||||
JSONParse jout;
|
||||
string s;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("sensor", &jtmp);
|
||||
se = server->SensorFromJSON(&jtmp);
|
||||
if (se.name[0] != 0) {
|
||||
debug (0, "%s:%d DelJSONTurnout Element %s", __FILE__, __LINE__, se.name);
|
||||
// add element
|
||||
server->SensorDelete(se.name);
|
||||
jout.Clear();
|
||||
s = se.name;
|
||||
jout.AddObject("sensordelete", s);
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// add new Locomotive
|
||||
//
|
||||
void Session::AddJSONLocomotive(JSONParse *jp) {
|
||||
Locomotive loco;
|
||||
JSONParse jloco;
|
||||
JSONParse jout;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("locomotive", &jloco);
|
||||
loco = server->LocomotiveFromJSON(&jloco);
|
||||
if (loco.name[0] != 0) {
|
||||
debug (0, "%s:%d AddJSONLocomotive Element %s", __FILE__, __LINE__, loco.name);
|
||||
// add element
|
||||
server->LocomotiveChange(&loco);
|
||||
jout.Clear();
|
||||
jout.AddObject("locomotive", server->LocomotiveGetJSON(loco.name));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Set Locomotive
|
||||
//
|
||||
void Session::SetJSONLocomotive(JSONParse *jp) {
|
||||
JSONParse jloco;
|
||||
JSONParse jout;
|
||||
string loconame;
|
||||
int speed;
|
||||
int func;
|
||||
int value;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("locomotive", &jloco);
|
||||
jloco.GetValue("name", &loconame);
|
||||
if (loconame.length() > 0) {
|
||||
if (jloco.GetValueInt("speed", &speed) == 1) {
|
||||
//
|
||||
// set speed
|
||||
debug (0, "%s:%d SetJSONLocomotive Element %s Speed:%d", __FILE__, __LINE__, loconame.c_str(), speed);
|
||||
server->LocomotiveSetSpeed(loconame, speed);
|
||||
}
|
||||
if (jloco.GetValueInt("function", &func) == 1 && jloco.GetValueInt("value", &value) == 1) {
|
||||
//
|
||||
// set function
|
||||
debug (0, "%s:%d SetJSONLocomotive Element %s Function:%d Value:%d", __FILE__, __LINE__, loconame.c_str(), func, value);
|
||||
server->LocomotiveSetFunction(loconame, func, speed);
|
||||
}
|
||||
jout.Clear();
|
||||
jout.AddObject("locomotive", server->LocomotiveGetJSON(loconame));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Delete Locomotive
|
||||
//
|
||||
void Session::DelJSONLocomotive(JSONParse *jp) {
|
||||
Locomotive loco;
|
||||
JSONParse jloco;
|
||||
JSONParse jout;
|
||||
string s;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("locomotive", &jloco);
|
||||
loco = server->LocomotiveFromJSON(&jloco);
|
||||
if (loco.name[0] != 0) {
|
||||
debug (0, "%s:%d DelJSONLocomotive Element %s", __FILE__, __LINE__, loco.name);
|
||||
// add element
|
||||
server->LocomotiveDelete(loco.name);
|
||||
jout.Clear();
|
||||
s = loco.name;
|
||||
jout.AddObject("locomotivedelete", s);
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// add new Turnout
|
||||
//
|
||||
void Session::AddJSONTurnout(JSONParse *jp) {
|
||||
Turnout to;
|
||||
JSONParse jtmp;
|
||||
JSONParse jout;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("turnout", &jtmp);
|
||||
to = server->TurnoutFromJSON(&jtmp);
|
||||
if (to.name[0] != 0) {
|
||||
debug (0, "%s:%d AddJSONTurnout Element %s", __FILE__, __LINE__, to.name);
|
||||
// add element
|
||||
server->TurnoutChange(&to);
|
||||
jout.Clear();
|
||||
jout.AddObject("turnout", server->TurnoutGetJSON(to.name));
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Delete Turnout
|
||||
//
|
||||
void Session::DelJSONTurnout(JSONParse *jp) {
|
||||
Turnout to;
|
||||
JSONParse jtmp;
|
||||
JSONParse jout;
|
||||
string s;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetObject("turnout", &jtmp);
|
||||
to = server->TurnoutFromJSON(&jtmp);
|
||||
if (to.name[0] != 0) {
|
||||
debug (0, "%s:%d DelJSONTurnout Element %s", __FILE__, __LINE__, to.name);
|
||||
// add element
|
||||
server->TurnoutDelete(to.name);
|
||||
jout.Clear();
|
||||
s = to.name;
|
||||
jout.AddObject("turnoutdelete", s);
|
||||
if (network) network->_ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
server->UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Set Turnout
|
||||
//
|
||||
void Session::SetJSONTurnout(JSONParse *jp) {
|
||||
JSONParse jout;
|
||||
string name;
|
||||
int active;
|
||||
|
||||
server->LockThread();
|
||||
|
||||
jp->GetValue("name", &name);
|
||||
jp->GetValueInt("activate", &active);
|
||||
|
||||
if (name.length() > 0) {
|
||||
//
|
||||
// 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();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
res = json.GetValue("command", &value);
|
||||
if (res && value.compare("addelemens") == 0) {
|
||||
for (i = 0; json.GetObjectIdx("elements", i, &jelement) != 0; i++) {
|
||||
s = "";
|
||||
jelement.GetValue("type", &s);
|
||||
// printf ("i:%d t:'%s'\n", i, s.c_str());
|
||||
}
|
||||
}
|
||||
snprintf (bufferout, BUFFERSIZE, "{\"success\":1,\"sid\":123}");
|
||||
client->Write(bufferout, strlen(bufferout));
|
||||
debug (0, "* write:\n%s\n* %d bytes", bufferout, strlen(bufferout));
|
||||
result = 1;
|
||||
|
||||
*/
|
@ -0,0 +1,26 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
string input;
|
||||
string json_line;
|
||||
JSONParse json;
|
||||
list<JSONElement> l;
|
||||
list<JSONElement>::iterator iter;
|
||||
|
||||
for (json_line = "", input = ""; getline(cin, input);)
|
||||
json_line += input;
|
||||
|
||||
json.Set(json_line);
|
||||
l = json.GetElements();
|
||||
|
||||
for (iter = l.begin(); iter != l.end(); iter++) {
|
||||
cout << iter->name << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
@ -0,0 +1,262 @@
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "turnout.h"
|
||||
|
||||
Turnouts::Turnouts() {
|
||||
changed = 0;
|
||||
turnouts = (Turnout*) malloc(sizeof(Turnout)*TURNOUTS_MAX);
|
||||
max = TURNOUTS_MAX;
|
||||
};
|
||||
|
||||
Turnouts::~Turnouts() {
|
||||
free (turnouts);
|
||||
max = 0;
|
||||
turnouts = NULL;
|
||||
};
|
||||
|
||||
|
||||
int Turnouts::Lock() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
int Turnouts::UnLock() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
JSONParse Turnouts::_GetJSON(int idx) {
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
string s = "";
|
||||
|
||||
json.Clear();
|
||||
|
||||
s = turnouts[idx].name; json.AddObject("name", s);
|
||||
s = turnouts[idx].ifname; json.AddObject("ifname", s);
|
||||
json.AddObject("addr", turnouts[idx].addr);
|
||||
json.AddObject("activetimeout", turnouts[idx].activetimeout);
|
||||
json.AddObject("flags", turnouts[idx].flags);
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
JSONParse Turnouts::GetJSON(string name) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
jp.Clear();
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
|
||||
if (name.compare(turnouts[i].name) == 0) {
|
||||
jp = _GetJSON(i);
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return jp;
|
||||
};
|
||||
|
||||
|
||||
void Turnouts::GetJSONAll(JSONParse *json) {
|
||||
int i, cnt;
|
||||
JSONElement je;
|
||||
|
||||
Lock();
|
||||
|
||||
//
|
||||
// write all railway data
|
||||
// create json object array manualy
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "turnouts";
|
||||
for (cnt = 0, i = 0; i < max; i++)
|
||||
if (turnouts[i].name[0] != 0) {
|
||||
if (cnt != 0) je.value += ","; // not first element
|
||||
je.value += _GetJSON(i).ToString();
|
||||
cnt++;
|
||||
}
|
||||
json->AddObject(je);
|
||||
|
||||
UnLock();
|
||||
};
|
||||
|
||||
|
||||
Turnout Turnouts::GetTurnoutFromJSON(JSONParse *j) {
|
||||
Turnout to;
|
||||
string s;
|
||||
|
||||
to.name[0] = 0;
|
||||
to.ifname[0] = 0;
|
||||
to.addr = 0;
|
||||
to.activetimeout = TURNOUT_DEFAULT_ACTIVETIMEOUT; // default active timeout in MS
|
||||
to.flags = 0;
|
||||
|
||||
j->GetValue("name", &s);
|
||||
strncpy (to.name, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValue("ifname", &s);
|
||||
strncpy (to.ifname, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValueInt("addr", &to.addr);
|
||||
j->GetValueInt("activetimeout", &to.activetimeout);
|
||||
j->GetValueInt("flags", &to.flags);
|
||||
|
||||
return to;
|
||||
};
|
||||
|
||||
|
||||
int Turnouts::Change(Turnout *to) {
|
||||
int i;
|
||||
int ifree = -1;
|
||||
|
||||
Lock();
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (turnouts[i].name[0] != 0) {
|
||||
// found element
|
||||
if (strncmp(turnouts[i].name, to->name, REFERENCENAME_LEN) == 0) {
|
||||
ifree = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ifree == -1) ifree = i;
|
||||
}
|
||||
// element not found add new element
|
||||
if (ifree != -1 && ifree < max) {
|
||||
turnouts[ifree] = *to;
|
||||
strncpy (turnouts[ifree].name, to->name, REFERENCENAME_LEN);
|
||||
strncpy (turnouts[ifree].ifname, to->ifname, REFERENCENAME_LEN);
|
||||
turnouts[ifree].activetimeout = to->activetimeout;
|
||||
}
|
||||
|
||||
changed = 1;
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Turnouts::Delete(string name) {
|
||||
int i;
|
||||
|
||||
Lock();
|
||||
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
|
||||
if (name.compare(turnouts[i].name) == 0) {
|
||||
turnouts[i].name[0] = 0;
|
||||
turnouts[i].ifname[0] = 0;
|
||||
turnouts[i].addr = 0;
|
||||
turnouts[i].flags = 0;
|
||||
turnouts[i].activetimeout = TURNOUT_DEFAULT_ACTIVETIMEOUT;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Turnouts::Set(string name, int value) {
|
||||
int i;
|
||||
|
||||
//
|
||||
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' : '-',
|
||||
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-',
|
||||
value);
|
||||
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
|
||||
gettimeofday (&turnouts[i].activatetime, NULL);
|
||||
changed = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
UnLock();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
//
|
||||
// got some data from bus
|
||||
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);
|
||||
|
||||
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' : '-',
|
||||
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
|
||||
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-');
|
||||
|
||||
// if (value) turnouts[i].flags |= TURNOUT_F_ACTIVE;
|
||||
// else turnouts[i].flags &= ~TURNOUT_F_ACTIVE;
|
||||
|
||||
if (turnouts[i].flags & TURNOUT_F_INVERSE) {
|
||||
if (value) turnouts[i].flags &= ~TURNOUT_F_TURNOUT;
|
||||
else turnouts[i].flags |= TURNOUT_F_TURNOUT;
|
||||
}
|
||||
else {
|
||||
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' : '-',
|
||||
(turnouts[i].flags & TURNOUT_F_ACTIVE) ? 'A' : '-',
|
||||
(turnouts[i].flags & TURNOUT_F_TURNOUT) ? 'T' : '-');
|
||||
|
||||
jp.AddObject("turnout", _GetJSON(i));
|
||||
if(network) network->ChangeListPushToAll(jp.ToString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// this loop is important: Turnout motors needs to be deactivated after a short time
|
||||
//
|
||||
void Turnouts::Loop() {
|
||||
int i;
|
||||
struct timeval curtime;
|
||||
|
||||
gettimeofday(&curtime, NULL);
|
||||
|
||||
Lock();
|
||||
|
||||
for (i = 0; i < max; i++) if (turnouts[i].name[0] != 0) {
|
||||
if (turnouts[i].flags & TURNOUT_F_ACTIVE) {
|
||||
//
|
||||
// motor 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);
|
||||
|
||||
// debug (0, "%s:%d timediff: %d", __FILE__, __LINE__, timediff);
|
||||
|
||||
if (timediff > turnouts[i].activetimeout) {
|
||||
int active = turnouts[i].flags & TURNOUT_F_TURNOUT;
|
||||
if (turnouts[i].flags & TURNOUT_F_INVERSE)
|
||||
server->interfaces.SetTurnout(&turnouts[i], !active, 0); // motor on
|
||||
else
|
||||
server->interfaces.SetTurnout(&turnouts[i], active, 0); // motor on
|
||||
turnouts[i].flags &= ~TURNOUT_F_ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
UnLock();
|
||||
};
|
@ -0,0 +1,56 @@
|
||||
|
||||
#ifndef _TURNOUT_H_
|
||||
#define _TURNOUT_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
//
|
||||
#define TURNOUT_F_INVERSE 0x0001 // inverse output
|
||||
#define TURNOUT_F_ACTIVE 0x0002 // motor active
|
||||
#define TURNOUT_F_TURNOUT 0x0004 // turnout active
|
||||
|
||||
#define TURNOUT_DEFAULT_ACTIVETIMEOUT 250 // active timeout default value
|
||||
|
||||
struct s_Turnout {
|
||||
char name[REFERENCENAME_LEN]; // reference name
|
||||
char ifname[REFERENCENAME_LEN]; // controllername
|
||||
int addr; // address on bus
|
||||
int flags; // setup of some flags;
|
||||
int activetimeout; // time in ms // 0 will be set to DEFAULT
|
||||
struct timeval activatetime; // set both to 0 for inactive
|
||||
} typedef Turnout;
|
||||
|
||||
|
||||
class Turnouts {
|
||||
private:
|
||||
Turnout *turnouts;
|
||||
int max;
|
||||
int changed;
|
||||
|
||||
pthread_mutex_t mtx;
|
||||
int Lock();
|
||||
int UnLock();
|
||||
|
||||
// not thread safe
|
||||
JSONParse _GetJSON(int idx);
|
||||
public:
|
||||
Turnouts();
|
||||
~Turnouts();
|
||||
|
||||
bool IsChanged() { return changed; };
|
||||
void ClearChanged() { changed = 0; };
|
||||
|
||||
int Change(Turnout *to);
|
||||
int Delete(string name);
|
||||
int Set(string name, int active);
|
||||
|
||||
void Loop();
|
||||
|
||||
JSONParse GetJSON(string name);
|
||||
void GetJSONAll(JSONParse *json);
|
||||
Turnout GetTurnoutFromJSON(JSONParse *j);
|
||||
|
||||
void SetFromBus(string name, int addr, int active);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,213 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
var blocks = [];
|
||||
|
||||
//
|
||||
// update or add a new element
|
||||
//
|
||||
function block_Update(blockdata) {
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (blockdata.name == blocks[i].name) {
|
||||
blocks[i].name = blockdata.name;
|
||||
blocks[i].flags = blockdata.flags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not found add element
|
||||
//debug ("Add Interface:" + intdata.name + "(" + intdata.host + ")");
|
||||
blocks.push ({
|
||||
name: blockdata.name,
|
||||
flags: blockdata.flags
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// delete element from the list
|
||||
// in arrays we can not delete just an element, so we create a new one
|
||||
// and replace this one.
|
||||
//
|
||||
function block_Delete(name) {
|
||||
var l = new Array();
|
||||
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (name != blocks[i].name) {
|
||||
l.push (blocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// clear list and replace list with new data.
|
||||
blocks.lenght = 0;
|
||||
blocks = l;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send new element to server
|
||||
//
|
||||
function block_server_Add(elm) {
|
||||
var request = { command: "addblock", block: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send delete element to server
|
||||
//
|
||||
function block_server_Del(elm) {
|
||||
var request = { command: "delblock", block: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
|
||||
function blockdetail_show(name) {
|
||||
var win = document.getElementById("blockdetail");
|
||||
|
||||
debug ("blockdetail_show");
|
||||
|
||||
if (!win) {
|
||||
debug ("blockdetail_show create window");
|
||||
win = gWindowCreate("blockdetail", "Block", 400, 300, " \
|
||||
<div style=\"float: left\"> \
|
||||
Block Name: <input id=\"blockdet_name\" style=\"width: 100\"> \
|
||||
</div> <div style=\"float: right\"> \
|
||||
<button id=\"blockdet_PREV\"><</button> \
|
||||
<button id=\"blockdet_NEXT\">></button> \
|
||||
</div> <br> <hr>\
|
||||
<div> \
|
||||
<table><tr><td><table>\
|
||||
</td></tr></table> </div> <hr>\
|
||||
<div align=right> \
|
||||
<button id=\"blockdet_SAVE\" type=\"button\">Save</button> \
|
||||
<button id=\"blockdet_DELETE\" type=\"button\">Delete</button> \
|
||||
<button id=\"blockdet_CLOSE\">Close</button> \
|
||||
</div> \
|
||||
\
|
||||
");
|
||||
|
||||
gAddEventListener("blockdet_CLOSE", 'click', blockdetail_cb_close);
|
||||
gAddEventListener("blockdet_DELETE", 'click', blockdetail_cb_delete);
|
||||
gAddEventListener("blockdet_SAVE", 'click', blockdetail_cb_save);
|
||||
|
||||
gAddEventListener("blockdet_NEXT", 'click', blockdetail_cb_next);
|
||||
gAddEventListener("blockdet_PREV", 'click', blockdetail_cb_prev);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (name == blocks[i].name) blockdetail_setData(blocks[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function blockdetail_cb_close () {
|
||||
var win = document.getElementById("blockdetail");
|
||||
|
||||
if (win) document.body.removeChild(win);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Delete Button
|
||||
//
|
||||
function blockdetail_cb_delete () {
|
||||
var elm = {};
|
||||
|
||||
elm = blockdetail_getData();
|
||||
block_Delete(elm.name);
|
||||
block_server_Del(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Save Button
|
||||
//
|
||||
function blockdetail_cb_save () {
|
||||
var elm = {};
|
||||
|
||||
elm = blockdetail_getData();
|
||||
block_Update(elm);
|
||||
block_server_Add(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Next Button
|
||||
//
|
||||
function blockdetail_cb_next () {
|
||||
var cursel = -1;
|
||||
var name = document.getElementById("blockdet_name");
|
||||
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (name.value == blocks[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel + 1;
|
||||
if (cursel >= blocks.length) cursel = 0;
|
||||
if (cursel < 0) cursel = 0;
|
||||
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (i == cursel) blockdetail_setData(blocks[i]);
|
||||
}
|
||||
|
||||
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Prev Button
|
||||
//
|
||||
function blockdetail_cb_prev () {
|
||||
var cursel = -1;
|
||||
var name = document.getElementById("blockdet_name");
|
||||
|
||||
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (name.value == blocks[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel - 1;
|
||||
if (cursel < 0 || cursel >= blocks.length) cursel = blocks.length - 1;
|
||||
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
if (i == cursel) blockdetail_setData(blocks[i]);
|
||||
}
|
||||
|
||||
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// fill out all the elements on the dialogbox
|
||||
//
|
||||
function blockdetail_setData(elm) {
|
||||
var name = document.getElementById("blockdet_name");
|
||||
var flags = document.getElementById("blockdet_flags");
|
||||
|
||||
if (elm) {
|
||||
if (name) name.value = elm.name;
|
||||
if (flags) flags.value = elm.flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// return all elements from the dialogbox
|
||||
//
|
||||
function blockdetail_getData() {
|
||||
var res = { name: "", flags:0 };
|
||||
var name = document.getElementById("blockdet_name");
|
||||
var flags = document.getElementById("blockdet_flags");
|
||||
|
||||
if (name) res.name = name.value;
|
||||
if (flags) res.flags = flags.value;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
.GUIwindow {
|
||||
float:left;
|
||||
border: 2px solid black;
|
||||
margin: 1px;
|
||||
padding: 0px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.GUIwindowHead {
|
||||
border: 1px solid black;
|
||||
background: blue;
|
||||
color: white;
|
||||
margin: 0px;
|
||||
padding: 5px;
|
||||
cursor: move;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.GUIwindowClient {
|
||||
overflow: auto;
|
||||
padding: 5px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
.GUIbutton {
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
//
|
||||
// init all variables with the class givin
|
||||
$(document).ready(function() {
|
||||
// debug ("init");
|
||||
|
||||
$(".GUIwindow").each( function (i) {
|
||||
gWindowDragElement(this);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
function gAddEventListener (id, eventname, callback) {
|
||||
var obj = document.getElementById(id);
|
||||
|
||||
if (obj) obj.addEventListener(eventname, callback);
|
||||
};
|
||||
|
@ -0,0 +1,9 @@
|
||||
|
||||
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;
|
||||
};
|
||||
|
@ -0,0 +1,137 @@
|
||||
|
||||
|
||||
|
||||
|
||||
function gWindowGetClient(elmnt) {
|
||||
var notes = null;
|
||||
var result = null;
|
||||
|
||||
for (var i = 0; i < elmnt.childNodes.length; i++) {
|
||||
if (elmnt.childNodes[i].className == "GUIwindowClient") {
|
||||
result = elmnt.childNodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function gWindowGetHead(elmnt) {
|
||||
var notes = null;
|
||||
var result = null;
|
||||
|
||||
for (var i = 0; i < elmnt.childNodes.length; i++) {
|
||||
if (elmnt.childNodes[i].className == "GUIwindowHead") {
|
||||
result = elmnt.childNodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
function gWindowDragElement(elmnt) {
|
||||
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||
|
||||
if (gWindowGetHead(elmnt) != null) {
|
||||
// if present, the header is where you move the DIV from:
|
||||
gWindowGetHead(elmnt).onmousedown = dragMouseDown;
|
||||
} else {
|
||||
// otherwise, move the DIV from anywhere inside the DIV:
|
||||
elmnt.onmousedown = dragMouseDown;
|
||||
}
|
||||
|
||||
function dragMouseDown(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// get the mouse cursor position at startup:
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.top = (elmnt.offsetTop - pos2 - 1) + "px";
|
||||
elmnt.style.left = (elmnt.offsetLeft - pos1 - 1) + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
// stop moving when mouse button is released:
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
}
|
||||
|
||||
function gWindowCreate(id, title, sizex, sizey, clientHTML) {
|
||||
var win = document.getElementById(id);
|
||||
if (!win) {
|
||||
debug("create Title:" + title);
|
||||
|
||||
var head = document.createElement("div");
|
||||
head.setAttribute("id", id+"Head");
|
||||
head.setAttribute("class", "GUIwindowHead");
|
||||
head.innerHTML = title;
|
||||
|
||||
var client = document.createElement("div");
|
||||
client.setAttribute("id", id+"Client");
|
||||
client.setAttribute("class", "GUIwindowClient");
|
||||
client.setAttribute("style", "max-height:"+sizey+"px;max-width:"+sizex+"px;");
|
||||
client.innerHTML = clientHTML;
|
||||
|
||||
win = document.createElement("div");
|
||||
win.setAttribute("id", id);
|
||||
win.setAttribute("class", "GUIwindow");
|
||||
win.appendChild (head);
|
||||
win.appendChild (client);
|
||||
|
||||
document.body.appendChild(win);
|
||||
gWindowDragElement(win);
|
||||
debug ("move to 100px from top");
|
||||
win.style.top = "100px";
|
||||
}
|
||||
return win;
|
||||
}
|
||||
|
||||
|
||||
function gWindowCreateSize(id, title, sizex, sizey) {
|
||||
var win = document.getElementById(id);
|
||||
if (!win) {
|
||||
debug("create Title:" + title);
|
||||
|
||||
var head = document.createElement("div");
|
||||
head.setAttribute("id", id+"Head");
|
||||
head.setAttribute("class", "GUIwindowHead");
|
||||
head.innerHTML = title;
|
||||
|
||||
var client = document.createElement("div");
|
||||
client.setAttribute("id", id+"Client");
|
||||
client.setAttribute("class", "GUIwindowClient");
|
||||
client.setAttribute("style", "max-height:"+sizey+"px;max-width:"+sizex+"px;");
|
||||
client.style.height = sizey+"px";
|
||||
client.style.width = sizex+"px";
|
||||
|
||||
win = document.createElement("div");
|
||||
win.setAttribute("id", id);
|
||||
win.setAttribute("class", "GUIwindow");
|
||||
win.appendChild (head);
|
||||
win.appendChild (client);
|
||||
document.body.appendChild(win);
|
||||
gWindowDragElement(win);
|
||||
debug ("move to 100px from top");
|
||||
win.style.top = "100px";
|
||||
}
|
||||
return win;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 376 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 365 B |
@ -0,0 +1,107 @@
|
||||
<html>
|
||||
<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>
|
||||
<script src="interface.js"></script>
|
||||
<script src="railways.js"></script>
|
||||
<script src="locomotive.js"></script>
|
||||
<script src="sensor.js"></script>
|
||||
<script src="track.js"></script>
|
||||
<script src="side.js"></script>
|
||||
<script src="block.js"></script>
|
||||
<script src="testwindow.js"></script>
|
||||
<link rel="stylesheet" href="gui/gui.css">
|
||||
<link rel="stylesheet" href="layout.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar">
|
||||
<a href="#home">Home</a>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn">Server
|
||||
<i class="fa fa-caret-down"></i>
|
||||
</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">
|
||||
<button class="dropbtn">Configuration
|
||||
<i class="fa fa-caret-down"></i>
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
<a href="#" onclick="side_Display(SIDE_DISPLAY_EDITTRACK);">Track</a>
|
||||
<a href="#" onclick="intdetail_show(this);">Interfaces</a>
|
||||
<a href="#" onclick="turndetail_show(this);">Turnouts</a>
|
||||
<a href="#" onclick="locodetail_show(this);">Locomotives</a>
|
||||
<a href="#" onclick="sensordetail_show(this);">Sensors</a>
|
||||
<a href="#" onclick="blockdetail_show(this);">Block</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="infoserverstatus" style="float:right; padding: 8px 8px;">notconnected</div>
|
||||
<div id="infoline" style="float:right; padding: 8px 8px;">editinfo</div>
|
||||
</div>
|
||||
|
||||
<div class="page_side">
|
||||
<button class="side_btn" id="btn-onoff" onclick="sideBtnOnOffClick(this);" value="0">
|
||||
<img src="images/btnonoff.png"></button>
|
||||
<br><br>
|
||||
<div class="page_side_edit" id="side_trackedit" style="display: none;">
|
||||
<button class="side_btn_mode side_btn_selected" id="mode-none" onclick="sideBtnModeClick(this);" value="none">
|
||||
<img src="images/btnarrow.png"></button>
|
||||
<button class="side_btn_mode" id="mode-move" onclick="sideBtnModeClick(this);" value="move">
|
||||
<img src="images/btnmove.png"></button>
|
||||
<button class="side_btn_mode" id="mode-delete" onclick="sideBtnModeClick(this);" value="delete">
|
||||
<img src="images/btndelete.png"></button>
|
||||
<button class="side_btn_mode" id="mode-rail" onclick="sideBtnModeClick(this);" value="rail">
|
||||
<img src="images/btnrail.png"></button>
|
||||
<button class="side_btn_mode" id="mode-turn" onclick="sideBtnModeClick(this);" value="turnout">
|
||||
<img src="images/btnturnout.png"></button>
|
||||
<br><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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");
|
||||
var canvas = trackCreate(5, 5);
|
||||
|
||||
var text = document.getElementById("infoline");
|
||||
text.innerHTML = "---";
|
||||
|
||||
client.appendChild (canvas);
|
||||
|
||||
trackDraw();
|
||||
|
||||
serverinout_AutoUpdate();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,273 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
var interfaces = [];
|
||||
|
||||
//
|
||||
// update or add a new element
|
||||
//
|
||||
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 + ")");
|
||||
|
||||
if (!(intdata.flags & 0x0001)) sideBtnOnOffMode (3); // not connected
|
||||
else if ((intdata.flags & 0x0010)) sideBtnOnOffMode (3); // programming mode
|
||||
else if ((intdata.flags & 0x0008)) sideBtnOnOffMode (3); // short circuit
|
||||
else if ((intdata.flags & 0x0004)) sideBtnOnOffMode (2); // stop
|
||||
else if (!(intdata.flags & 0x0002)) sideBtnOnOffMode (1); // power on
|
||||
else sideBtnOnOffMode (0);
|
||||
|
||||
interfaces[i].name = intdata.name;
|
||||
interfaces[i].host = intdata.host;
|
||||
interfaces[i].flags = intdata.flags;
|
||||
interfaces[i].type = intdata.type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not found add element
|
||||
//debug ("Add Interface:" + intdata.name + "(" + intdata.host + ")");
|
||||
interfaces.push ({
|
||||
name: intdata.name,
|
||||
host: intdata.host,
|
||||
flags: intdata.flags,
|
||||
type: intdata.type
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// delete element from the list
|
||||
// in arrays we can not delete just an element, so we create a new one
|
||||
// and replace this one.
|
||||
//
|
||||
function interface_Delete(name) {
|
||||
var l = new Array();
|
||||
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (name != interfaces[i].name) {
|
||||
l.push (interfaces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// clear list and replace list with new data.
|
||||
interfaces.lenght = 0;
|
||||
interfaces = l;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send new element to server
|
||||
//
|
||||
function interface_server_Add(elm) {
|
||||
var request = { command: "addinterface", interface: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send delete element to server
|
||||
//
|
||||
function interface_server_Del(elm) {
|
||||
var request = { command: "delinterface", interface: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
|
||||
function intdetail_show(intname) {
|
||||
var win = document.getElementById("intdetail");
|
||||
|
||||
debug ("intdetail_show");
|
||||
|
||||
if (!win) {
|
||||
debug ("intdetail_show create window");
|
||||
win = gWindowCreate("intdetail", "Interface", 400, 300, " \
|
||||
<div style=\"float: left\"> \
|
||||
Interface Name: <input id=\"intdet_name\" style=\"width: 100\"> \
|
||||
</div> <div style=\"float: right\"> \
|
||||
<button id=\"intdet_PREV\"><</button> \
|
||||
<button id=\"intdet_NEXT\">></button> \
|
||||
</div> <br> <hr>\
|
||||
<div> \
|
||||
<table><tr><td><table>\
|
||||
<tr><td>Host:</td><td><input id=\"intdet_host\" style=\"width: 200\"></td></tr> \
|
||||
<tr><td>Flags:</td><td><input id=\"intdet_flags\" style=\"width: 50\"></td></tr> \
|
||||
</table></td><td> \
|
||||
<fieldset><legend>Type</legend> \
|
||||
Type: <input id=\"intdet_type\" style=\"width: 25\"><br> \
|
||||
<label><input type=\"radio\" id=\"intdet_typeunknown\" name=\"Type\" value=\"0\">Unkown</label><br> \
|
||||
<label><input type=\"radio\" id=\"intdet_typez21\" name=\"Type\" value=\"1\">Z21</label><br> \
|
||||
</fieldset> \
|
||||
</td></tr></table> </div> <hr>\
|
||||
<div align=right> \
|
||||
<button id=\"intdet_SAVE\" type=\"button\">Save</button> \
|
||||
<button id=\"intdet_DELETE\" type=\"button\">Delete</button> \
|
||||
<button id=\"intdet_CLOSE\">Close</button> \
|
||||
</div> \
|
||||
\
|
||||
");
|
||||
|
||||
gAddEventListener("intdet_type", 'change', intdetail_cb_typechange);
|
||||
gAddEventListener("intdet_typeunknown", 'click', intdetail_cb_typeselector);
|
||||
gAddEventListener("intdet_typez21", 'click', intdetail_cb_typeselector);
|
||||
|
||||
|
||||
gAddEventListener("intdet_CLOSE", 'click', intdetail_cb_close);
|
||||
gAddEventListener("intdet_DELETE", 'click', intdetail_cb_delete);
|
||||
gAddEventListener("intdet_SAVE", 'click', intdetail_cb_save);
|
||||
|
||||
gAddEventListener("intdet_NEXT", 'click', intdetail_cb_next);
|
||||
gAddEventListener("intdet_PREV", 'click', intdetail_cb_prev);
|
||||
}
|
||||
|
||||
if (intname) {
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (intname == interfaces[i].name) intdetail_setData(interfaces[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function intdetail_cb_close () {
|
||||
var win = document.getElementById("intdetail");
|
||||
|
||||
if (win) document.body.removeChild(win);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Delete Button
|
||||
//
|
||||
function intdetail_cb_delete () {
|
||||
var elm = {};
|
||||
|
||||
elm = intdetail_getData();
|
||||
interface_Delete(elm.name);
|
||||
interface_server_Del(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Save Button
|
||||
//
|
||||
function intdetail_cb_save () {
|
||||
var elm = {};
|
||||
|
||||
elm = intdetail_getData();
|
||||
interface_Update(elm);
|
||||
interface_server_Add(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Next Button
|
||||
//
|
||||
function intdetail_cb_next () {
|
||||
var cursel = -1;
|
||||
var if_name = document.getElementById("intdet_name");
|
||||
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (if_name.value == interfaces[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel + 1;
|
||||
if (cursel >= interfaces.length) cursel = 0;
|
||||
if (cursel < 0) cursel = 0;
|
||||
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (i == cursel) intdetail_setData(interfaces[i]);
|
||||
}
|
||||
|
||||
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Prev Button
|
||||
//
|
||||
function intdetail_cb_prev () {
|
||||
var cursel = -1;
|
||||
var if_name = document.getElementById("intdet_name");
|
||||
|
||||
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (if_name.value == interfaces[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel - 1;
|
||||
if (cursel < 0 || cursel >= interfaces.length) cursel = interfaces.length - 1;
|
||||
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (i == cursel) intdetail_setData(interfaces[i]);
|
||||
}
|
||||
|
||||
// debug ("Cursel: " + cursel + " interfaces.lenght:" + interfaces.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// fill out all the elements on the dialogbox
|
||||
//
|
||||
function intdetail_setData(elm) {
|
||||
var if_name = document.getElementById("intdet_name");
|
||||
var if_host = document.getElementById("intdet_host");
|
||||
var if_flags = document.getElementById("intdet_flags");
|
||||
var if_type = document.getElementById("intdet_type");
|
||||
|
||||
if (elm) {
|
||||
if (if_name) if_name.value = elm.name;
|
||||
if (if_host) if_host.value = elm.host;
|
||||
if (if_flags) if_flags.value = elm.flags;
|
||||
if (if_flags) if_type.value = elm.type;
|
||||
}
|
||||
|
||||
intdetail_cb_typechange();
|
||||
};
|
||||
|
||||
|
||||
function intdetail_cb_typechange () {
|
||||
var type = document.getElementById("intdet_type");
|
||||
var typez21 = document.getElementById("intdet_typez21");
|
||||
var typeunknown = document.getElementById("intdet_typeunknown");
|
||||
|
||||
switch(Number(type.value)) {
|
||||
case 0: typeunknown.checked = true; break;
|
||||
case 1: typez21.checked = true; break;
|
||||
default:
|
||||
type.value = 0;
|
||||
typeunknown.checked = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function intdetail_cb_typeselector () {
|
||||
var type = document.getElementById("intdet_type");
|
||||
|
||||
type.value = this.value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// return all elements from the dialogbox
|
||||
//
|
||||
function intdetail_getData() {
|
||||
var res = { name: "", host: "", flags:0, type:0 };
|
||||
var if_name = document.getElementById("intdet_name");
|
||||
var if_host = document.getElementById("intdet_host");
|
||||
var if_flags = document.getElementById("intdet_flags");
|
||||
var if_type = document.getElementById("intdet_type");
|
||||
|
||||
if (if_name) res.name = if_name.value;
|
||||
if (if_host) res.host = if_host.value;
|
||||
if (if_flags) res.flags = if_flags.value;
|
||||
if (if_type) res.type = if_type.value;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
@ -0,0 +1,158 @@
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
:root {
|
||||
--top-height: 34px;
|
||||
--side-width: 37px;
|
||||
--bottom-height: 32px;
|
||||
--menu-bg-color: #333;
|
||||
--menu-fg-color: linen;
|
||||
}
|
||||
|
||||
.page_side {
|
||||
position: absolute;
|
||||
top: var(--top-height);
|
||||
left: 0px;
|
||||
width: var(--side-width);
|
||||
height: calc(100vh - var(--top-height) - var(--bottom-height));
|
||||
max-height: calc(100vh - var(--top-height) - var(--bottom-height));
|
||||
color: var(--menu-fg-color);
|
||||
background: var(--menu-bg-color);
|
||||
}
|
||||
|
||||
.side_btn_mode {
|
||||
background-color: lightgray;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.side_btn {
|
||||
background-color: lightgray;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
|
||||
.side_btn_selected{
|
||||
background-color: gray;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.side_btn_poweron{
|
||||
background-color: lightgreen;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.side_btn_poweroff{
|
||||
background-color: lightgray;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.side_btn_shortcircuit{
|
||||
background-color: red;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.side_btn_stop{
|
||||
background-color: yellow;
|
||||
padding: 0px 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.side_btn:hover {
|
||||
background-color: white;
|
||||
}
|
||||
.side_btn_mode:hover {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
.page_main {
|
||||
position: absolute;
|
||||
top: var(--top-height);
|
||||
left: var(--side-width);
|
||||
width: calc(100vw - var(--side-width));
|
||||
height: calc(100vh - var(--top-height) - var(--bottom-height));
|
||||
background: lightgray;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.page_bottom {
|
||||
position: absolute;
|
||||
top: calc(100vh - var(--bottom-height));
|
||||
left: 0px;
|
||||
height: var(--bottom-height);
|
||||
width: 100vw;
|
||||
background: var(--menu-bg-color);
|
||||
color: var(--menu-fg-color);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
overflow: hidden;
|
||||
color: var(--menu-fg-color);
|
||||
background: var(--menu-bg-color);
|
||||
}
|
||||
|
||||
|
||||
.navbar a {
|
||||
float: left;
|
||||
font-size: 16px;
|
||||
color: var(--menu-fg-color);
|
||||
text-align: center;
|
||||
padding: 8px 8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dropdown .dropbtn {
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: var(--menu-fg-color);
|
||||
padding: 8px 8px;
|
||||
background-color: inherit;
|
||||
font-family: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar a:hover, .dropdown:hover .dropbtn {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #f9f9f9;
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dropdown-content a {
|
||||
float: none;
|
||||
color: black;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.dropdown-content a:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown-content {
|
||||
display: block;
|
||||
}
|
||||
|
@ -0,0 +1,360 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
var locomotives = [];
|
||||
|
||||
|
||||
//
|
||||
// update or add a new element
|
||||
//
|
||||
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);
|
||||
locomotives[i].name = data.name;
|
||||
locomotives[i].ifname = data.ifname;
|
||||
locomotives[i].addr = data.addr;
|
||||
locomotives[i].steps = data.steps;
|
||||
locomotives[i].speed = data.speed;
|
||||
locomotives[i].vmin = data.vmin;
|
||||
locomotives[i].vslow = data.vslow;
|
||||
locomotives[i].vmid = data.vmid;
|
||||
locomotives[i].vfast = data.vfast;
|
||||
locomotives[i].vmax = data.vmax;
|
||||
locomotives[i].flags = data.flags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not found add element
|
||||
debug ("Add Locomotive:" + data.name);
|
||||
locomotives.push ({
|
||||
name: data.name,
|
||||
ifname: data.ifname,
|
||||
addr: data.addr,
|
||||
steps: data.steps,
|
||||
vmin: data.vmin,
|
||||
vslow: data.vslow,
|
||||
speed: data.speed,
|
||||
vmid: data.vmid,
|
||||
vfast: data.vfast,
|
||||
vmax: data.vmax,
|
||||
flags: data.flags
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// delete element from the list
|
||||
// in arrays we can not delete just an element, so we create a new one
|
||||
// and replace this one.
|
||||
//
|
||||
function locomotive_Delete(name) {
|
||||
var l = new Array();
|
||||
|
||||
for (var i = 0; i < locomotives.length; i++) {
|
||||
if (name != locomotives[i].name) {
|
||||
l.push (locomotives[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// clear list and replace list with new data.
|
||||
locomotives.lenght = 0;
|
||||
locomotives = l;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send new element to server
|
||||
//
|
||||
function locomotive_server_Add(elm) {
|
||||
var request = { command: "addlocomotive", locomotive: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send delete element to server
|
||||
//
|
||||
function locomotive_server_Del(elm) {
|
||||
var request = { command: "dellocomotive", locomotive: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send delete element to server
|
||||
//
|
||||
function locomotive_server_Set(elm) {
|
||||
var request = { command: "setlocomotive", locomotive: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
|
||||
function locodetail_show(loconame) {
|
||||
var win = document.getElementById("locodetail");
|
||||
|
||||
debug ("locodetail_show");
|
||||
|
||||
if (!win) {
|
||||
debug ("loco_showdetail create window");
|
||||
win = gWindowCreate("locodetail", "Locomotive", 400, 500, " \
|
||||
<div style=\"float: left\"> \
|
||||
Name: <input id=\"locodet_name\" style=\"width: 100\"> \
|
||||
</div> <div style=\"float: right\"> \
|
||||
<button id=\"locodet_PREV\"><</button> \
|
||||
<button id=\"locodet_NEXT\">></button> \
|
||||
</div> <br> <hr>\
|
||||
<div> \
|
||||
Interface: <input id=\"locodet_ifname\" style=\"width: 50\"> \
|
||||
Adress: <input id=\"locodet_addr\" style=\"width: 50\"> \
|
||||
Flags: <input id=\"locodet_flags\" style=\"width: 50\"> \
|
||||
</div> <hr>\
|
||||
<div> <table><tr><td> \
|
||||
<fieldset><legend>Speed</legend> <table>\
|
||||
<tr><td></td><td>Stop</td><td><button id=\"locodet_btnvstop\" type=\"button\" value=\"vstop\">X</button> </td></tr>\
|
||||
<tr><td>Vmin:</td><td><input id=\"locodet_vmin\" style=\"width: 50\"></td><td><button id=\"locodet_btnvmin\" type=\"button\" value=\"vmin\">X</button> </td></tr>\
|
||||
<tr><td>Vslow:</td><td><input id=\"locodet_vslow\" style=\"width: 50\"></td><td><button id=\"locodet_btnvslow\" type=\"button\" value=\"vslow\">X</button> </td></tr> \
|
||||
<tr><td>Vmid:</td><td><input id=\"locodet_vmid\" style=\"width: 50\"></td><td><button id=\"locodet_btnvmid\" type=\"button\" value=\"vmid\">X</button> </td></tr> \
|
||||
<tr><td>Vfast:</td><td><input id=\"locodet_vfast\" style=\"width: 50\"></td><td><button id=\"locodet_btnvfast\" type=\"button\" value=\"vfast\">X</button> </td></tr> \
|
||||
<tr><td>Vmax:</td><td><input id=\"locodet_vmax\" style=\"width: 50\"></td><td><button id=\"locodet_btnvmax\" type=\"button\" value=\"vmax\">X</button> </td></tr> \
|
||||
</table></td></fieldset> \
|
||||
<td> \
|
||||
Steps: <input id=\"locodet_steps\" style=\"width: 50\"><br> \
|
||||
Speed: <input id=\"locodet_speed\" style=\"width: 50\"><br> \
|
||||
<label><input id=\"locodet_reverse\" type=\"checkbox\" value=\"\"> Reverse</label> \
|
||||
</td></tr></table></div> <hr>\
|
||||
<div align=right> \
|
||||
<button id=\"locodet_SAVE\" type=\"button\">Save</button> \
|
||||
<button id=\"locodet_DELETE\" type=\"button\">Delete</button> \
|
||||
<button id=\"locodet_CLOSE\" type=\"button\">Close</button> \
|
||||
</div> \
|
||||
\
|
||||
");
|
||||
|
||||
gAddEventListener("locodet_btnvstop", 'click', locodetail_cb_btnmove);
|
||||
gAddEventListener("locodet_btnvmin", 'click', locodetail_cb_btnmove);
|
||||
gAddEventListener("locodet_btnvslow", 'click', locodetail_cb_btnmove);
|
||||
gAddEventListener("locodet_btnvmid", 'click', locodetail_cb_btnmove);
|
||||
gAddEventListener("locodet_btnvfast", 'click', locodetail_cb_btnmove);
|
||||
gAddEventListener("locodet_btnvmax", 'click', locodetail_cb_btnmove);
|
||||
gAddEventListener("locodet_reverse", 'click', locodetail_cb_reverse);
|
||||
|
||||
gAddEventListener("locodet_CLOSE", 'click', locodetail_cb_close);
|
||||
gAddEventListener("locodet_DELETE", 'click', locodetail_cb_delete);
|
||||
gAddEventListener("locodet_SAVE", 'click', locodetail_cb_save);
|
||||
|
||||
gAddEventListener("locodet_NEXT", 'click', locodetail_cb_next);
|
||||
gAddEventListener("locodet_PREV", 'click', locodetail_cb_prev);
|
||||
}
|
||||
|
||||
//
|
||||
// load default values
|
||||
var res = { name: "", ifname: "", addr: "", flags: 0, steps: "",
|
||||
vmin: "20", vslow: "40", vmid:"60", vfast:"80", vmax:"100" };
|
||||
locodetail_setData(res);
|
||||
|
||||
if (loconame) {
|
||||
for (var i = 0; i < locomotives.length; i++) {
|
||||
if (loconame == locomotives[i].name) locodetail_setData(locomotives[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// reverse selected, setup flags
|
||||
function locodetail_cb_reverse () {
|
||||
var cbreverse = document.getElementById("locodet_reverse");
|
||||
var flags = document.getElementById("locodet_flags");
|
||||
|
||||
if (cbreverse.checked) {
|
||||
flags.value = Number(flags.value) | 1;
|
||||
}
|
||||
|
||||
else {
|
||||
flags.value = Number(flags.value) & (0xFFFF-1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function locodetail_cb_btnmove () {
|
||||
var win = document.getElementById("locodetail");
|
||||
var loco_name = document.getElementById("locodet_name");
|
||||
var loco_vmin = document.getElementById("locodet_vmin");
|
||||
var loco_vslow = document.getElementById("locodet_vslow");
|
||||
var loco_vmid = document.getElementById("locodet_vmid");
|
||||
var loco_vfast = document.getElementById("locodet_vfast");
|
||||
var loco_vmax = document.getElementById("locodet_vmax");
|
||||
var loco_reverse = document.getElementById("locodet_reverse");
|
||||
|
||||
var speed = 0;
|
||||
|
||||
if (this.value == "vmin") speed = Number(loco_vmin.value);
|
||||
if (this.value == "vslow") speed = Number(loco_vslow.value);
|
||||
if (this.value == "vmid") speed = Number(loco_vmid.value);
|
||||
if (this.value == "vfast") speed = Number(loco_vfast.value);
|
||||
if (this.value == "vmax") speed = Number(loco_vmax.value);
|
||||
|
||||
if (loco_reverse.checked) {
|
||||
speed = 0 - speed;
|
||||
}
|
||||
|
||||
locomotive_server_Set ({name: loco_name.value, speed: speed});
|
||||
debug ("Locomotive: '" + loco_name.value +"' Speed: " + speed);
|
||||
};
|
||||
|
||||
|
||||
function locodetail_cb_close () {
|
||||
var win = document.getElementById("locodetail");
|
||||
|
||||
if (win) document.body.removeChild(win);
|
||||
};
|
||||
|
||||
//
|
||||
// Callback: Delete Button
|
||||
//
|
||||
function locodetail_cb_delete () {
|
||||
var elm = {};
|
||||
|
||||
elm = locodetail_getData();
|
||||
locomotive_Delete(elm.name);
|
||||
locomotive_server_Del(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Save Button
|
||||
//
|
||||
function locodetail_cb_save () {
|
||||
var elm = {};
|
||||
|
||||
elm = locodetail_getData();
|
||||
locomotive_Update(elm);
|
||||
locomotive_server_Add(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Next Button
|
||||
//
|
||||
function locodetail_cb_next () {
|
||||
var cursel = -1;
|
||||
var loconame = document.getElementById("locodet_name");
|
||||
|
||||
for (var i = 0; i < locomotives.length; i++) {
|
||||
if (loconame.value == locomotives[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel + 1;
|
||||
if (cursel >= locomotives.length) cursel = 0;
|
||||
if (cursel < 0) cursel = 0;
|
||||
|
||||
for (var i = 0; i < locomotives.length; i++) {
|
||||
if (i == cursel) locodetail_setData(locomotives[i]);
|
||||
}
|
||||
|
||||
debug ("Cursel: " + cursel + " locomotives.lenght:" + locomotives.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Prev Button
|
||||
//
|
||||
function locodetail_cb_prev () {
|
||||
var cursel = -1;
|
||||
var loconame = document.getElementById("locodet_name");
|
||||
|
||||
|
||||
for (var i = 0; i < locomotives.length; i++) {
|
||||
if (loconame.value == locomotives[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel - 1;
|
||||
if (cursel < 0 || cursel >= locomotives.length) cursel = locomotives.length - 1;
|
||||
|
||||
for (var i = 0; i < locomotives.length; i++) {
|
||||
if (i == cursel) locodetail_setData(locomotives[i]);
|
||||
}
|
||||
|
||||
debug ("Cursel: " + cursel + " locomotives.lenght:" + locomotives.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// fill out all the elements on the dialogbox
|
||||
//
|
||||
function locodetail_setData(elm) {
|
||||
var loco_name = document.getElementById("locodet_name");
|
||||
var loco_ifname = document.getElementById("locodet_ifname");
|
||||
var loco_addr = document.getElementById("locodet_addr");
|
||||
var loco_speed = document.getElementById("locodet_speed");
|
||||
var loco_flags = document.getElementById("locodet_flags");
|
||||
var loco_steps = document.getElementById("locodet_steps");
|
||||
var loco_vmin = document.getElementById("locodet_vmin");
|
||||
var loco_vslow = document.getElementById("locodet_vslow");
|
||||
var loco_vmid = document.getElementById("locodet_vmid");
|
||||
var loco_vfast = document.getElementById("locodet_vfast");
|
||||
var loco_vmax = document.getElementById("locodet_vmax");
|
||||
var loco_reverse = document.getElementById("locodet_reverse");
|
||||
|
||||
if (elm) {
|
||||
if (loco_name) loco_name.value = elm.name;
|
||||
if (loco_ifname) loco_ifname.value = elm.ifname;
|
||||
if (loco_flags) loco_flags.value = elm.flags;
|
||||
if (loco_addr) loco_addr.value = elm.addr;
|
||||
if (loco_speed) loco_speed.value = elm.speed;
|
||||
if (loco_steps) loco_steps.value = elm.steps;
|
||||
if (loco_vmin) loco_vmin.value = elm.vmin;
|
||||
if (loco_vslow) loco_vslow.value = elm.vslow;
|
||||
if (loco_vmid) loco_vmid.value = elm.vmid;
|
||||
if (loco_vfast) loco_vfast.value = elm.vfast;
|
||||
if (loco_vmax) loco_vmax.value = elm.vmax;
|
||||
if (loco_reverse) {
|
||||
if (Number(elm.flags) & 1) loco_reverse.checked = true;
|
||||
else loco_reverse.checked = false;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// return all elements from the dialogbox
|
||||
//
|
||||
function locodetail_getData() {
|
||||
var res = { name: "", ifname: "", addr: "", flags: 0, steps: "",
|
||||
vmin: "20", vslow: "40", vmid:"60", vfast:"80", vmax:"100" };
|
||||
|
||||
var loco_name = document.getElementById("locodet_name");
|
||||
var loco_ifname = document.getElementById("locodet_ifname");
|
||||
var loco_flags = document.getElementById("locodet_flags");
|
||||
var loco_addr = document.getElementById("locodet_addr");
|
||||
var loco_steps = document.getElementById("locodet_steps");
|
||||
var loco_vmin = document.getElementById("locodet_vmin");
|
||||
var loco_vslow = document.getElementById("locodet_vslow");
|
||||
var loco_vmid = document.getElementById("locodet_vmid");
|
||||
var loco_vfast = document.getElementById("locodet_vfast");
|
||||
var loco_vmax = document.getElementById("locodet_vmax");
|
||||
|
||||
if (loco_name) res.name = loco_name.value;
|
||||
if (loco_ifname) res.ifname = loco_ifname.value;
|
||||
if (loco_flags) res.flags = loco_flags.value;
|
||||
if (loco_addr) res.addr = loco_addr.value;
|
||||
if (loco_steps) res.steps = loco_steps.value;
|
||||
if (loco_vmin) res.vmin = loco_vmin.value;
|
||||
if (loco_vslow) res.vslow = loco_vslow.value;
|
||||
if (loco_vmid) res.vmid = loco_vmid.value;
|
||||
if (loco_vfast) res.vfast = loco_vfast.value;
|
||||
if (loco_vmax) res.vmax = loco_vmax.value;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
@ -0,0 +1,524 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
const TURNOUT_F_INVERSE = 1;
|
||||
const TURNOUT_F_MOTORACTIVE = 2;
|
||||
const TURNOUT_F_TURNOUT = 4;
|
||||
|
||||
|
||||
function rwdetail_requestcallback(response) {
|
||||
debug ("rwdetail_requestcallback");
|
||||
};
|
||||
|
||||
|
||||
function rwdetail_request(posx, posy) {
|
||||
var request = {locoid: locoID, parameter1: -1, name:"Otto"};
|
||||
|
||||
debug ("rwdetail_request");
|
||||
|
||||
serverinout(request, rwdetail_requestcallback);
|
||||
};
|
||||
|
||||
function rwdetail_show(posx, posy) {
|
||||
var win = document.getElementById("rwdetail");
|
||||
|
||||
debug ("rwdetail_show");
|
||||
|
||||
if (!win) {
|
||||
debug ("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 +"\"> \
|
||||
</div> <br> <hr>\
|
||||
<div> <table><tr><td><table> \
|
||||
<tr><td>Ref.Name:</td><td><input id=\"rwdet_name\" style=\"width: 100\"></td></tr> \
|
||||
<tr><td>Dir:</td><td><input id=\"rwdet_dir\" style=\"width: 25\"></td></tr> \
|
||||
<tr><td>Alt Dir:</td><td><input id=\"rwdet_altdir\" style=\"width: 25\"></td></tr> \
|
||||
</table><br> \
|
||||
<center><canvas id=\"rwdet_canvas\" height=\""+track.scale+"\" width=\""+track.scale+"\" style=\"border:1px solid #000000;\"></center> <br>\
|
||||
</td><td> \
|
||||
<fieldset><legend>Type</legend> \
|
||||
Type: <input id=\"rwdet_type\" style=\"width: 25\"><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typenothing\" name=\"Type\" value=\"0\">Nothing</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typenormal\" name=\"Type\" value=\"1\">Normal</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typecrossing\" name=\"Type\" value=\"2\">Crossing</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typeturnout\" name=\"Type\" value=\"3\">Turnout</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typesensor\" name=\"Type\" value=\"4\">Sensor</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typeconnector\" name=\"Type\" value=\"5\">Connector</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typebutton\" name=\"Type\" value=\"6\">Button</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typetext\" name=\"Type\" value=\"7\">Text</label><br> \
|
||||
<label><input type=\"radio\" id=\"rwdet_typeblock\" name=\"Type\" value=\"8\">Block</label><br> \
|
||||
</fieldset> \
|
||||
\
|
||||
</td></tr></table></div> <hr>\ \
|
||||
\
|
||||
<div align=right> \
|
||||
<button id=\"rwdet_SAVE\" type=\"button\">Save</button> \
|
||||
<button id=\"rwdet_CLOSE\">Close</button> \
|
||||
</div> \
|
||||
\
|
||||
");
|
||||
|
||||
gAddEventListener("rwdet_dir", 'change', rwdetail_cb_dirchange);
|
||||
gAddEventListener("rwdet_type", 'change', rwdetail_cb_typechange);
|
||||
gAddEventListener("rwdet_altdir", 'change', rwdetail_cb_dirchange);
|
||||
gAddEventListener("rwdet_typenothing", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typenormal", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typecrossing", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typeturnout", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typesensor", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typeconnector", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typebutton", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typetext", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_typeblock", 'click', rwdetail_cb_typeselector);
|
||||
gAddEventListener("rwdet_SAVE", 'click', rwdetail_cb_save);
|
||||
gAddEventListener("rwdet_CLOSE", 'click', rwdetail_cb_close);
|
||||
|
||||
}
|
||||
else {
|
||||
var x = document.getElementById("rwdet_X");
|
||||
var y = document.getElementById("rwdet_Y");
|
||||
|
||||
x.value = posx;
|
||||
y.value = posy;
|
||||
}
|
||||
|
||||
rwdetail_setData({type: 0, x: posx, y: posy, dir: 0, altdir: 0, name: ""});
|
||||
if (track.elements[posx + posy * track.size.x]) {
|
||||
rwdetail_setData(track.elements[posx + posy * track.size.x]);
|
||||
}
|
||||
};
|
||||
|
||||
function rwdetail_cb_dirchange () {
|
||||
rwdetail_DrawSample ();
|
||||
};
|
||||
|
||||
|
||||
function rwdetail_cb_typechange () {
|
||||
var type = document.getElementById("rwdet_type");
|
||||
var typenothing = document.getElementById("rwdet_typenothing");
|
||||
var typenormal = document.getElementById("rwdet_typenormal");
|
||||
var typecrossing = document.getElementById("rwdet_typecrossing");
|
||||
var typeturnout = document.getElementById("rwdet_typeturnout");
|
||||
var typesensor = document.getElementById("rwdet_typesensor");
|
||||
var typeconnector = document.getElementById("rwdet_typeconnector");
|
||||
var typebutton = document.getElementById("rwdet_typebutton");
|
||||
var typetext = document.getElementById("rwdet_typetext");
|
||||
var typeblock = document.getElementById("rwdet_typeblock");
|
||||
|
||||
switch(Number(type.value)) {
|
||||
case 0: typenothing.checked = true; break;
|
||||
case 1: typenormal.checked = true; break;
|
||||
case 2: typecrossing.checked = true; break;
|
||||
case 3: typeturnout.checked = true; break;
|
||||
case 4: typesensor.checked = true; break;
|
||||
case 5: typeconnector.checked = true; break;
|
||||
case 6: typebutton.checked = true; break;
|
||||
case 7: typetext.checked = true; break;
|
||||
case 8: typeblock.checked = true; break;
|
||||
default:
|
||||
type.value = 0;
|
||||
typenothing.checked = true;
|
||||
break;
|
||||
}
|
||||
rwdetail_DrawSample();
|
||||
};
|
||||
|
||||
|
||||
function rwdetail_cb_typeselector () {
|
||||
var type = document.getElementById("rwdet_type");
|
||||
|
||||
type.value = this.value;
|
||||
rwdetail_DrawSample ();
|
||||
};
|
||||
|
||||
|
||||
function rwdetail_cb_save () {
|
||||
var name = document.getElementById("rwdet_name");
|
||||
var type = document.getElementById("rwdet_type");
|
||||
var dir = document.getElementById("rwdet_dir");
|
||||
var altdir = document.getElementById("rwdet_altdir");
|
||||
var x = document.getElementById("rwdet_X");
|
||||
var y = document.getElementById("rwdet_Y");
|
||||
|
||||
var rws = new Array();
|
||||
|
||||
rws.length = 0;
|
||||
rws.push({name: name.value, x: Number(x.value), y: Number(y.value), type: type.value,
|
||||
dir: dir.value, altdir: altdir.value});
|
||||
serverinout_addTrack(rws);
|
||||
trackAddElement(rws[0]);
|
||||
};
|
||||
|
||||
|
||||
function rwdetail_cb_close () {
|
||||
var win = document.getElementById("rwdetail");
|
||||
|
||||
if (win) document.body.removeChild(win);
|
||||
};
|
||||
|
||||
|
||||
function rwdetail_DrawSample() {
|
||||
var type = document.getElementById("rwdet_type");
|
||||
var dir = document.getElementById("rwdet_dir");
|
||||
var altdir = document.getElementById("rwdet_altdir");
|
||||
var c = document.getElementById("rwdet_canvas");
|
||||
var ctx = c.getContext("2d");
|
||||
|
||||
ctx.fillRect(0, 0, track.scale, track.scale);
|
||||
trackDrawElement(ctx, { type: type.value, x: 0, y: 0,
|
||||
dir: dir.value, altdir: altdir.value }, 0);
|
||||
};
|
||||
|
||||
|
||||
|
||||
function rwdetail_setData(rw) {
|
||||
var name = document.getElementById("rwdet_name");
|
||||
var type = document.getElementById("rwdet_type");
|
||||
var dir = document.getElementById("rwdet_dir");
|
||||
var altdir = document.getElementById("rwdet_altdir");
|
||||
|
||||
if (rw) {
|
||||
name.value = rw.name;
|
||||
type.value = rw.type;
|
||||
dir.value = rw.dir;
|
||||
altdir.value = rw.altdir;
|
||||
}
|
||||
|
||||
rwdetail_cb_typechange();
|
||||
rwdetail_DrawSample();
|
||||
};
|
||||
|
||||
|
||||
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) {
|
||||
if (track.elements[idx].name != "") {
|
||||
if (turnout_IsActive(track.elements[idx].name)) {
|
||||
turnout_server_Activate(track.elements[idx].name, 0);
|
||||
}
|
||||
else {
|
||||
turnout_server_Activate(track.elements[idx].name, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Sensor
|
||||
if (track.elements[idx].type == RAILWAY_SENSOR) {
|
||||
if (track.elements[idx].name != "") {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
// * *
|
||||
// * TURNOUTS *
|
||||
// * *
|
||||
// *******************************************************************************************************
|
||||
|
||||
|
||||
var turnouts = [];
|
||||
|
||||
//
|
||||
// update or add a new element
|
||||
//
|
||||
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);
|
||||
turnouts[i].name = data.name;
|
||||
turnouts[i].ifname = data.ifname;
|
||||
turnouts[i].addr = data.addr;
|
||||
turnouts[i].flags = data.flags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not found add element
|
||||
debug ("Add turnout:" + data.name);
|
||||
turnouts.push ({
|
||||
name: data.name,
|
||||
ifname: data.ifname,
|
||||
addr: data.addr,
|
||||
flags: data.flags
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return if the turnout is active or not
|
||||
//
|
||||
function turnout_IsActive(name) {
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (name == turnouts[i].name) {
|
||||
if (turnouts[i].flags & TURNOUT_F_TURNOUT) 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
|
||||
// and replace this one.
|
||||
//
|
||||
function turnout_Delete(name) {
|
||||
var l = new Array();
|
||||
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (name != turnouts[i].name) {
|
||||
l.push (turnouts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// clear list and replace list with new data.
|
||||
turnouts.lenght = 0;
|
||||
turnouts = l;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send new element to server
|
||||
//
|
||||
function turnout_server_Add(elm) {
|
||||
var request = { command: "addturnout", turnout: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send delete element to server
|
||||
//
|
||||
function turnout_server_Del(elm) {
|
||||
var request = { command: "delturnout", turnout: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
//
|
||||
// send activate to the server (onoff must be 0 or 1)
|
||||
//
|
||||
function turnout_server_Activate(name, onoff) {
|
||||
var request = { command: "setturnout", name: name, activate: onoff };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
|
||||
function turndetail_show(turnname) {
|
||||
var win = document.getElementById("turndetail");
|
||||
|
||||
debug ("turndetail_show");
|
||||
|
||||
if (!win) {
|
||||
debug ("turndetail_show create window");
|
||||
win = gWindowCreate("turndetail", "Turnout", 400, 500, " \
|
||||
<div style=\"float: left\"> \
|
||||
Name: <input id=\"turndet_name\" style=\"width: 100\"> \
|
||||
</div> <div style=\"float: right\"> \
|
||||
<button id=\"turndet_PREV\"><</button> \
|
||||
<button id=\"turndet_NEXT\">></button> \
|
||||
</div> <br> <hr>\
|
||||
<div> <table><tr><td><table> \
|
||||
<tr><td>Interface:</td><td><input id=\"turndet_ifname\" style=\"width: 50\"></td></tr> \
|
||||
<tr><td>Adress:</td><td><input id=\"turndet_addr\" style=\"width: 50\"></td></tr> \
|
||||
<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_active\" type=\"checkbox\" value=\"\"><dfn title=\"save first\"> Active</dfn></label>\
|
||||
\
|
||||
</td></tr></table></div> <hr>\
|
||||
<div align=right> \
|
||||
<button id=\"turndet_SAVE\" type=\"button\">Save</button> \
|
||||
<button id=\"turndet_DELETE\" type=\"button\">Delete</button> \
|
||||
<button id=\"turndet_CLOSE\" type=\"button\">Close</button> \
|
||||
</div> \
|
||||
\
|
||||
");
|
||||
|
||||
gAddEventListener("turndet_inverse", 'click', turndetail_cb_inverse);
|
||||
gAddEventListener("turndet_active", 'click', turndetail_cb_active);
|
||||
|
||||
gAddEventListener("turndet_CLOSE", 'click', turndetail_cb_close);
|
||||
gAddEventListener("turndet_DELETE", 'click', turndetail_cb_delete);
|
||||
gAddEventListener("turndet_SAVE", 'click', turndetail_cb_save);
|
||||
|
||||
gAddEventListener("turndet_NEXT", 'click', turndetail_cb_next);
|
||||
gAddEventListener("turndet_PREV", 'click', turndetail_cb_prev);
|
||||
|
||||
}
|
||||
|
||||
if (turnname) {
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (turnname == turnouts[i].name) turndetail_setData(turnouts[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// inverse selected, setup flags
|
||||
function turndetail_cb_inverse () {
|
||||
var cbinverse = document.getElementById("turndet_inverse");
|
||||
var flags = document.getElementById("turndet_flags");
|
||||
|
||||
if (cbinverse.checked) {
|
||||
flags.value = Number(flags.value) | TURNOUT_F_INVERSE;
|
||||
}
|
||||
|
||||
else {
|
||||
flags.value = Number(flags.value) & (0xFFFF-TURNOUT_F_INVERSE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// activate turnout
|
||||
function turndetail_cb_active () {
|
||||
var cbact = document.getElementById("turndet_active");
|
||||
var flags = document.getElementById("turndet_flags");
|
||||
var name = document.getElementById("turndet_name");
|
||||
|
||||
if (cbact.checked) {
|
||||
flags.value = Number(flags.value) | TURNOUT_F_TURNOUT;
|
||||
turnout_server_Activate(name.value, 1);
|
||||
}
|
||||
|
||||
else {
|
||||
flags.value = Number(flags.value) & (0xFFFF-TURNOUT_F_TURNOUT);
|
||||
turnout_server_Activate(name.value, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function turndetail_cb_close () {
|
||||
var win = document.getElementById("turndetail");
|
||||
|
||||
if (win) document.body.removeChild(win);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Delete Button
|
||||
//
|
||||
function turndetail_cb_delete () {
|
||||
var elm = {};
|
||||
|
||||
elm = turndetail_getData();
|
||||
turnout_Delete(elm.name);
|
||||
turnout_server_Del(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Save Button
|
||||
//
|
||||
function turndetail_cb_save () {
|
||||
var elm = {};
|
||||
|
||||
elm = turndetail_getData();
|
||||
turnout_Update(elm);
|
||||
turnout_server_Add(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Next Button
|
||||
//
|
||||
function turndetail_cb_next () {
|
||||
var cursel = -1;
|
||||
var turnname = document.getElementById("turndet_name");
|
||||
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (turnname.value == turnouts[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel + 1;
|
||||
if (cursel >= turnouts.length) cursel = 0;
|
||||
if (cursel < 0) cursel = 0;
|
||||
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (i == cursel) turndetail_setData(turnouts[i]);
|
||||
}
|
||||
|
||||
// debug ("Cursel: " + cursel + " turnouts.lenght:" + turnouts.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Prev Button
|
||||
//
|
||||
function turndetail_cb_prev () {
|
||||
var cursel = -1;
|
||||
var turnname = document.getElementById("turndet_name");
|
||||
|
||||
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (turnname.value == turnouts[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel - 1;
|
||||
if (cursel < 0 || cursel >= turnouts.length) cursel = turnouts.length - 1;
|
||||
|
||||
for (var i = 0; i < turnouts.length; i++) {
|
||||
if (i == cursel) turndetail_setData(turnouts[i]);
|
||||
}
|
||||
|
||||
// debug ("Cursel: " + cursel + " turnouts.lenght:" + turnouts.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// fill out all the elements on the dialogbox
|
||||
//
|
||||
function turndetail_setData(elm) {
|
||||
var turnname = document.getElementById("turndet_name");
|
||||
var turnifname = document.getElementById("turndet_ifname");
|
||||
var turnaddr = document.getElementById("turndet_addr");
|
||||
var turnflags = document.getElementById("turndet_flags");
|
||||
var cbinverse = document.getElementById("turndet_inverse");
|
||||
var cbactive = document.getElementById("turndet_active");
|
||||
|
||||
if (elm) {
|
||||
if (turnname) turnname.value = elm.name;
|
||||
if (turnifname) turnifname.value = elm.ifname;
|
||||
if (turnaddr) turnaddr.value = elm.addr;
|
||||
if (turnflags) turnflags.value = elm.flags;
|
||||
if (cbinverse) {
|
||||
if (Number(elm.flags) & 1) cbinverse.checked = true;
|
||||
else cbinverse.checked = false;
|
||||
}
|
||||
if (cbactive) {
|
||||
if (Number(elm.flags) & 2) cbactive.checked = true;
|
||||
else cbactive.checked = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// return all elements from the dialogbox
|
||||
//
|
||||
function turndetail_getData() {
|
||||
var res = { name: "", ifname: "", addr: "", flags: 0 };
|
||||
var turnname = document.getElementById("turndet_name");
|
||||
var turnifname = document.getElementById("turndet_ifname");
|
||||
var turnaddr = document.getElementById("turndet_addr");
|
||||
var turnflags = document.getElementById("turndet_flags");
|
||||
|
||||
if (turnname) res.name = turnname.value;
|
||||
if (turnifname) res.ifname = turnifname.value;
|
||||
if (turnaddr) res.addr = turnaddr.value;
|
||||
if (turnflags) res.flags = turnflags.value;
|
||||
|
||||
return res;
|
||||
};
|
@ -0,0 +1,248 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
const SENSOR_F_INVERSE = 1;
|
||||
const SENSOR_F_ACTIVE = 2;
|
||||
|
||||
var sensors = [];
|
||||
|
||||
|
||||
//
|
||||
// update or add a new element
|
||||
//
|
||||
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);
|
||||
sensors[i].name = sdata.name;
|
||||
sensors[i].ifname = sdata.ifname;
|
||||
sensors[i].addr = sdata.addr;
|
||||
sensors[i].flags = sdata.flags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not found add element
|
||||
debug ("Add Sensor:" + sdata.name);
|
||||
sensors.push ({
|
||||
name: sdata.name,
|
||||
ifname: sdata.ifname,
|
||||
addr: sdata.addr,
|
||||
flags: sdata.flags
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// delete element from the list
|
||||
// in arrays we can not delete just an element, so we create a new one
|
||||
// and replace this one.
|
||||
//
|
||||
function sensor_Delete(name) {
|
||||
var l = new Array();
|
||||
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (name != sensors[i].name) {
|
||||
l.push (sensors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// clear list and replace list with new data.
|
||||
sensors.lenght = 0;
|
||||
sensors = l;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send new element to server
|
||||
//
|
||||
function sensor_server_Add(elm) {
|
||||
var request = { command: "addsensor", sensor: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// send delete element to server
|
||||
//
|
||||
function sensor_server_Del(elm) {
|
||||
var request = { command: "delsensor", sensor: elm };
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return if the sensor is active or not
|
||||
//
|
||||
function sensor_IsActive(name) {
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (name == sensors[i].name) {
|
||||
if (sensors[i].flags & SENSOR_F_ACTIVE) return 1
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function sensordetail_show(name) {
|
||||
var win = document.getElementById("sensordetail");
|
||||
|
||||
debug ("sensordetail_show");
|
||||
|
||||
if (!win) {
|
||||
debug ("sensordetail_show create window");
|
||||
win = gWindowCreate("sensordetail", "Sensor", 400, 300, " \
|
||||
<div style=\"float: left\"> \
|
||||
Sensor Name: <input id=\"sensor_name\" style=\"width: 100\"> \
|
||||
</div> <div style=\"float: right\"> \
|
||||
<button id=\"sensor_PREV\"><</button> \
|
||||
<button id=\"sensor_NEXT\">></button> \
|
||||
</div> <br> <hr>\
|
||||
<div> \
|
||||
Interface: <input id=\"sensor_ifname\" style=\"width: 200\"> \
|
||||
Addr: <input id=\"sensor_addr\" style=\"width: 50\"> \
|
||||
Flags: <input id=\"sensor_flags\" style=\"width: 50\"> \
|
||||
</div> <hr>\
|
||||
<div align=right> \
|
||||
<button id=\"sensor_SAVE\" type=\"button\">Save</button> \
|
||||
<button id=\"sensor_DELETE\" type=\"button\">Delete</button> \
|
||||
<button id=\"sensor_CLOSE\">Close</button> \
|
||||
</div> \
|
||||
\
|
||||
");
|
||||
|
||||
gAddEventListener("sensor_CLOSE", 'click', sensordetail_cb_close);
|
||||
gAddEventListener("sensor_DELETE", 'click', sensordetail_cb_delete);
|
||||
gAddEventListener("sensor_SAVE", 'click', sensordetail_cb_save);
|
||||
|
||||
gAddEventListener("sensor_NEXT", 'click', sensordetail_cb_next);
|
||||
gAddEventListener("sensor_PREV", 'click', sensordetail_cb_prev);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (name == sensors[i].name) sensordetail_setData(sensors[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function sensordetail_cb_close () {
|
||||
var win = document.getElementById("sensordetail");
|
||||
|
||||
if (win) document.body.removeChild(win);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Delete Button
|
||||
//
|
||||
function sensordetail_cb_delete () {
|
||||
var elm = {};
|
||||
|
||||
elm = sensordetail_getData();
|
||||
sensor_Delete(elm.name);
|
||||
sensor_server_Del(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Save Button
|
||||
//
|
||||
function sensordetail_cb_save () {
|
||||
var elm = {};
|
||||
|
||||
elm = sensordetail_getData();
|
||||
sensor_Update(elm);
|
||||
sensor_server_Add(elm);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Next Button
|
||||
//
|
||||
function sensordetail_cb_next () {
|
||||
var cursel = -1;
|
||||
var name = document.getElementById("sensor_name");
|
||||
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (name.value == sensors[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel + 1;
|
||||
if (cursel >= sensors.length) cursel = 0;
|
||||
if (cursel < 0) cursel = 0;
|
||||
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (i == cursel) sensordetail_setData(sensors[i]);
|
||||
}
|
||||
|
||||
debug ("Cursel: " + cursel + " sensors.lenght:" + sensors.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Callback: Prev Button
|
||||
//
|
||||
function sensordetail_cb_prev () {
|
||||
var cursel = -1;
|
||||
var name = document.getElementById("sensor_name");
|
||||
|
||||
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (name.value == sensors[i].name) cursel = i;
|
||||
}
|
||||
|
||||
cursel = cursel - 1;
|
||||
if (cursel < 0 || cursel >= sensors.length) cursel = sensors.length - 1;
|
||||
|
||||
for (var i = 0; i < sensors.length; i++) {
|
||||
if (i == cursel) sensordetail_setData(sensors[i]);
|
||||
}
|
||||
|
||||
debug ("Cursel: " + cursel + " sensors.lenght:" + sensors.length);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// fill out all the elements on the dialogbox
|
||||
//
|
||||
function sensordetail_setData(elm) {
|
||||
var name = document.getElementById("sensor_name");
|
||||
var ifname = document.getElementById("sensor_ifname");
|
||||
var addr = document.getElementById("sensor_addr");
|
||||
var flags = document.getElementById("sensor_flags");
|
||||
|
||||
if (elm) {
|
||||
if (name) name.value = elm.name;
|
||||
if (ifname) ifname.value = elm.ifname;
|
||||
if (addr) addr.value = elm.addr;
|
||||
if (flags) flags.value = elm.flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// return all elements from the dialogbox
|
||||
//
|
||||
function sensordetail_getData() {
|
||||
var res = { name: "", ifname: "", addr: 0, flags:0 };
|
||||
var name = document.getElementById("sensor_name");
|
||||
var ifname = document.getElementById("sensor_ifname");
|
||||
var addr = document.getElementById("sensor_addr");
|
||||
var flags = document.getElementById("sensor_flags");
|
||||
|
||||
if (name) res.name = name.value;
|
||||
if (ifname) res.ifname = ifname.value;
|
||||
if (flags) res.flags = flags.value;
|
||||
if (addr) res.addr = addr.value;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
@ -0,0 +1,218 @@
|
||||
//
|
||||
//
|
||||
// mit jedem Paket eine eindeutige ID generieren.
|
||||
// (ein Teil generiert der Server ein anderer die Anwendung)
|
||||
//
|
||||
|
||||
|
||||
var sessionID = "";
|
||||
var randomID = "";
|
||||
var request_running = 0;
|
||||
|
||||
function serverinout_getRand(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
};
|
||||
|
||||
function serverinout(request, callback) {
|
||||
|
||||
//
|
||||
// generate random ID
|
||||
if (randomID == "") {
|
||||
randomID = serverinout_getRand(10000000, 99999999);
|
||||
}
|
||||
|
||||
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")
|
||||
{
|
||||
var serverstatus = document.getElementById("infoserverstatus");
|
||||
serverstatus.innerHTML = "connected";
|
||||
callback(jsonData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var serverstatus = document.getElementById("infoserverstatus");
|
||||
serverstatus.innerHTML = "-trying-";
|
||||
}
|
||||
// ENABLE LATER } catch(err) {
|
||||
// ENABLE LATER var serverstatus = document.getElementById("infoserverstatus");
|
||||
// ENABLE LATER serverstatus.innerHTML = "-error-";
|
||||
// ENABLE LATER }
|
||||
},
|
||||
error: function(error) {
|
||||
var serverstatus = document.getElementById("infoserverstatus");
|
||||
serverstatus.innerHTML = "ajax error";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
function serverinout_Power(onoff) {
|
||||
var request = {};
|
||||
|
||||
if (onoff) request = {command: "poweron"};
|
||||
else request = {command: "poweroff"};
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
}
|
||||
|
||||
|
||||
function serverinout_addTrack(tracks) {
|
||||
var request = { command: "addrailway", rail: tracks };
|
||||
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
function serverinout_delTrack(tracks) {
|
||||
var request = { command: "delrailway", rail: tracks };
|
||||
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
function serverinout_Save(data) {
|
||||
var request = { command: "save" };
|
||||
|
||||
serverinout (request, serverinout_defaultCallback);
|
||||
};
|
||||
|
||||
|
||||
function serverinout_defaultCallback(data) {
|
||||
// if (data.changes) if (data.changes.length > 0) debug ("From Server :" + JSON.stringify(data));
|
||||
if (data.info) {
|
||||
}
|
||||
if (data.sid && data.rid) {
|
||||
//
|
||||
// valid data from server
|
||||
if (data.rid == randomID && data.sid == sessionID) {
|
||||
//
|
||||
// loop through all the changes
|
||||
if (data.changes) {
|
||||
for (var i = 0; i < data.changes.length; i++) {
|
||||
//
|
||||
// infoline
|
||||
if (data.changes[i].infoline) {
|
||||
var text = document.getElementById("infoline");
|
||||
text.innerHTML = data.changes[i].infoline;
|
||||
}
|
||||
|
||||
//
|
||||
// railway changes
|
||||
if (data.changes[i].track) {
|
||||
trackSetup(data.changes[i].track);
|
||||
}
|
||||
if (data.changes[i].railway) {
|
||||
trackAddElement(data.changes[i].railway);
|
||||
}
|
||||
|
||||
//
|
||||
// Interface changes
|
||||
if (data.changes[i].interfaces) {
|
||||
for (var j = 0; j < data.changes[i].interfaces.length; j++) {
|
||||
interface_Update(data.changes[i].interfaces[j]);
|
||||
}
|
||||
}
|
||||
if (data.changes[i].interface) {
|
||||
interface_Update(data.changes[i].interface);
|
||||
}
|
||||
if (data.changes[i].interfacedelete) {
|
||||
interface_Delete(data.changes[i].interfacedelete);
|
||||
}
|
||||
|
||||
//
|
||||
// Locomotives changes
|
||||
if (data.changes[i].locomotives) {
|
||||
for (var j = 0; j < data.changes[i].locomotives.length; j++) {
|
||||
locomotive_Update(data.changes[i].locomotives[j]);
|
||||
}
|
||||
}
|
||||
if (data.changes[i].locomotive) {
|
||||
locomotive_Update(data.changes[i].locomotive);
|
||||
}
|
||||
if (data.changes[i].locomotivedelete) {
|
||||
locomotive_Delete(data.changes[i].locomotivedelete);
|
||||
}
|
||||
|
||||
//
|
||||
// Turnout changes
|
||||
if (data.changes[i].turnouts) {
|
||||
for (var j = 0; j < data.changes[i].turnouts.length; j++) {
|
||||
turnout_Update(data.changes[i].turnouts[j]);
|
||||
}
|
||||
}
|
||||
if (data.changes[i].turnout) {
|
||||
turnout_Update(data.changes[i].turnout);
|
||||
}
|
||||
if (data.changes[i].turnoutdelete) {
|
||||
turnout_Delete(data.changes[i].turnoutdelete);
|
||||
}
|
||||
|
||||
//
|
||||
// Sensor changes
|
||||
if (data.changes[i].sensors) {
|
||||
for (var j = 0; j < data.changes[i].sensors.length; j++) {
|
||||
sensor_Update(data.changes[i].sensors[j]);
|
||||
}
|
||||
}
|
||||
if (data.changes[i].sensor) {
|
||||
sensor_Update(data.changes[i].sensor);
|
||||
}
|
||||
if (data.changes[i].sensordelete) {
|
||||
sensor_Delete(data.changes[i].sensordelete);
|
||||
}
|
||||
}
|
||||
trackDraw();
|
||||
}
|
||||
}
|
||||
//
|
||||
// new session?
|
||||
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");
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug ("ERROR: serverinout_defaultCallback no data.sid && data.rid");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// starte timeout timer fuer Updates on 1/sec
|
||||
function serverinout_AutoUpdateCallback(data) {
|
||||
serverinout_defaultCallback(data);
|
||||
request_running = 0;
|
||||
};
|
||||
|
||||
|
||||
function serverinout_AutoUpdate() {
|
||||
// debug ("serverinout_AutoUpdate");
|
||||
if (request_running == 0) {
|
||||
request_running = 0;
|
||||
serverinout({}, serverinout_defaultCallback);
|
||||
}
|
||||
setTimeout(function() { serverinout_AutoUpdate() },1000);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
session_start();
|
||||
|
||||
//
|
||||
// work around for globals registers.
|
||||
// we will not use them at all
|
||||
//
|
||||
|
||||
|
||||
if (ini_get('register_globals'))
|
||||
{
|
||||
foreach ($_SESSION as $key=>$value)
|
||||
{
|
||||
if (isset($GLOBALS[$key]))
|
||||
unset($GLOBALS[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function debug($text) {
|
||||
$f = fopen("/tmp/modelbahn-php.log",'a+');
|
||||
fwrite($f, $text.PHP_EOL);
|
||||
fclose($f);
|
||||
};
|
||||
|
||||
|
||||
function readsend_data() {
|
||||
$data = "";
|
||||
$input = "";
|
||||
debug ("opening connection");
|
||||
$fp = stream_socket_client("unix:///tmp/modelbahn.socket", $errno, $errstr, 30);
|
||||
if (stream_set_blocking ($fp, FALSE) == FALSE) debug ("stream_set_blocking error");
|
||||
else debug ("stream_set_blocking ok");
|
||||
|
||||
if (!$fp) {
|
||||
debug ($errstr . " " . $errno);
|
||||
} else {
|
||||
$json = file_get_contents("php://input");
|
||||
debug("Send to Server :".$json);
|
||||
fwrite($fp, $json);
|
||||
$timestart = gettimeofday();
|
||||
$deltatime = 0;
|
||||
while (!feof($fp) && $deltatime < 1000) {
|
||||
$input = fgets($fp, 1024);
|
||||
$data = $data.$input;
|
||||
$timeend = gettimeofday();
|
||||
|
||||
if ($timeend["usec"] < $timestart["usec"]) $deltatime = 1000 + ($timeend["usec"] - $timestart["usec"])/1000;
|
||||
else $deltatime = ($timeend["usec"] - $timestart["usec"])/1000;
|
||||
|
||||
$deltatime = $deltatime + ($timeend["sec"] - $timestart["sec"]) * 1000;
|
||||
}
|
||||
fclose($fp);
|
||||
debug ("got: $data");
|
||||
debug ("connection closed");
|
||||
return $data;
|
||||
}
|
||||
return $data;
|
||||
};
|
||||
|
||||
$timerstart = microtime(true);
|
||||
debug("*** php script called");
|
||||
|
||||
$request = 0;
|
||||
$resultdata = array();
|
||||
|
||||
echo readsend_data();
|
||||
$timeused = microtime(true) - $timerstart;
|
||||
debug ("*** php script finished ********************************* ".$timeused."ms");
|
||||
|
@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
const SIDE_DISPLAY_NONE = 1;
|
||||
const SIDE_DISPLAY_EDITTRACK = 2;
|
||||
|
||||
function side_Display(type) {
|
||||
var x = document.getElementById("side_trackedit");
|
||||
var btn = document.getElementById("mode-none");
|
||||
|
||||
debug ("side_display(" + type +")");
|
||||
|
||||
if (type == SIDE_DISPLAY_EDITTRACK) {
|
||||
x.style.display = "block";
|
||||
}
|
||||
else {
|
||||
sideBtnModeClick(btn);
|
||||
x.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// on off switch
|
||||
//
|
||||
// value 0-off, 1-on, 2-stop, 3-shortciruit
|
||||
function sideBtnOnOffClick (obj) {
|
||||
side_Display(SIDE_DISPLAY_NONE);
|
||||
if (obj.value == 0) {
|
||||
serverinout_Power(1);
|
||||
}
|
||||
else {
|
||||
serverinout_Power(0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// if the power status changed, this function will be called.
|
||||
function sideBtnOnOffMode (mode) {
|
||||
var btn = document.getElementById("btn-onoff");
|
||||
btn.value = mode;
|
||||
|
||||
if (mode == 1) {
|
||||
btn.className = "side_btn_poweron";
|
||||
btn.value = 1;
|
||||
}
|
||||
else if (mode == 2) {
|
||||
btn.className = "side_btn_stop";
|
||||
btn.value = 2;
|
||||
}
|
||||
else if (mode == 3) {
|
||||
btn.className = "side_btn_shortcircuit";
|
||||
btn.value = 3;
|
||||
}
|
||||
else {
|
||||
btn.className = "side_btn_poweroff";
|
||||
btn.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// deselect all elements and select new one
|
||||
//
|
||||
function sideBtnModeClick (obj) {
|
||||
$('.side_btn_mode').each(function(i, objiter) {
|
||||
if (obj.id == objiter.id) {
|
||||
objiter.className = "side_btn_mode side_btn_selected";
|
||||
}
|
||||
else {
|
||||
objiter.className = "side_btn_mode";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
function sideBtnModeGet () {
|
||||
var i, selected = "";
|
||||
|
||||
i = 0;
|
||||
$('.side_btn_mode').each(function(j, objiter) {
|
||||
i++;
|
||||
if (objiter.className == "side_btn_mode side_btn_selected") selected = objiter.id;
|
||||
});
|
||||
|
||||
// debug ("Selected: '" + selected + "'");
|
||||
|
||||
return selected;
|
||||
};
|
||||
|
@ -0,0 +1,9 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
function testwinbtnclick() {
|
||||
debug ("Test Button");
|
||||
locodetail_show("");
|
||||
}
|
||||
|
@ -0,0 +1,662 @@
|
||||
//
|
||||
// draw track
|
||||
//
|
||||
|
||||
const RAILWAY_NOTHING = 0;
|
||||
const RAILWAY_NORMAL = 1;
|
||||
const RAILWAY_CROSSING = 2;
|
||||
const RAILWAY_TURNOUT = 3;
|
||||
const RAILWAY_SENSOR = 4;
|
||||
const RAILWAY_CONNECTOR = 5;
|
||||
const RAILWAY_BUTTON = 6;
|
||||
const RAILWAY_TEXT = 7;
|
||||
const RAILWAY_BLOCK = 8;
|
||||
|
||||
var track = {
|
||||
size: {x: -1, y: -1},
|
||||
scale: 24,
|
||||
dbuf: {},
|
||||
elements: []
|
||||
};
|
||||
|
||||
var trackMouse = {
|
||||
pos: {x: -1, y: -1, subx: 0.5, suby: 0.5},
|
||||
down: {x :-1 , y: -1, subx: 0.5, suby: 0.5}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// mode: 0 = normal
|
||||
// mode: 1 = selected
|
||||
// mode: 2 = mouseover
|
||||
//
|
||||
// direktion (object type)
|
||||
//
|
||||
// +---+ +---+ +---+ +---+
|
||||
// | | | | | | | |/ |
|
||||
// 0| | 1| | | 2|---| 3| |
|
||||
// | | | | | | | | |
|
||||
// +---+ +---+ +---+ +---+
|
||||
//
|
||||
// +---+ +---+ +---+ +---+
|
||||
// | \| | | | | | |
|
||||
// 4| | 5| | 6| | 7| |
|
||||
// | | | /| |\ | | |
|
||||
// +---+ +---+ +---+ +---+
|
||||
//
|
||||
// direction (arrow type)
|
||||
//
|
||||
// 0
|
||||
// 7 | 1
|
||||
// \|/
|
||||
// 6--+--2
|
||||
// /|\
|
||||
// 5 | 3
|
||||
// 4
|
||||
//
|
||||
|
||||
function trackDrawTrack(ctx, pos, dirtype) {
|
||||
var s = { x:0 , y:0 };
|
||||
var e = { x:0 , y:0 };
|
||||
|
||||
if (dirtype == 1) {
|
||||
s = { x: 0.5, y: 0.0 };
|
||||
e = { x: 0.5, y: 1.0 };
|
||||
}
|
||||
else if (dirtype == 2) {
|
||||
s = { x: 0.0, y: 0.5 };
|
||||
e = { x: 1.0, y: 0.5 };
|
||||
}
|
||||
else if (dirtype == 3) {
|
||||
s = { x: 0.5, y: 0.0 };
|
||||
e = { x: 0.0, y: 0.5 };
|
||||
}
|
||||
else if (dirtype == 4) {
|
||||
s = { x: 0.5, y: 0.0 };
|
||||
e = { x: 1.0, y: 0.5 };
|
||||
}
|
||||
else if (dirtype == 5) {
|
||||
s = { x: 0.5, y: 1.0 };
|
||||
e = { x: 1.0, y: 0.5 };
|
||||
}
|
||||
else if (dirtype == 6) {
|
||||
s = { x: 0.5, y: 1.0 };
|
||||
e = { x: 0.0, y: 0.5 };
|
||||
}
|
||||
else {
|
||||
s = { x: 0, y: 0 };
|
||||
e = { x: 0, y: 0 };
|
||||
}
|
||||
|
||||
if (s.x != e.x || s.y != e.x) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0.5+(pos.x+s.x) * track.scale, 0.5+(pos.y+s.y) * track.scale);
|
||||
ctx.lineTo(0.5+(pos.x+e.x) * track.scale, 0.5+(pos.y+e.y) * track.scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function trackDrawElement(ctx, element, mode) {
|
||||
var dx = 0, dy = 0;
|
||||
var modcol = "#B0B0B0";
|
||||
|
||||
if (element) {
|
||||
|
||||
if (mode == 1) modcol = "#FF0000";
|
||||
|
||||
if (element.type) {
|
||||
if (element.type == RAILWAY_TURNOUT) {
|
||||
//
|
||||
// turnout
|
||||
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));
|
||||
altdir = element.dir;
|
||||
dir = element.altdir;
|
||||
}
|
||||
ctx.lineWidth = 4;
|
||||
ctx.setLineDash([0,0]);
|
||||
ctx.strokeStyle = modcol;
|
||||
trackDrawTrack (ctx, {x: element.x, y: element.y}, dir);
|
||||
ctx.setLineDash([0,0]);
|
||||
if (element.name == "") ctx.strokeStyle = "DeepPink";
|
||||
else ctx.strokeStyle = "DimGray";
|
||||
trackDrawTrack (ctx, {x: element.x, y: element.y}, altdir);
|
||||
}
|
||||
else if (element.type == RAILWAY_NORMAL || element.type == RAILWAY_SENSOR) {
|
||||
//
|
||||
// normal
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([0,0]);
|
||||
ctx.strokeStyle = modcol;
|
||||
trackDrawTrack (ctx, {x: element.x, y: element.y}, element.dir);
|
||||
}
|
||||
else if (element.type == RAILWAY_CROSSING) {
|
||||
//
|
||||
// crossing
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([0,0]);
|
||||
ctx.strokeStyle = modcol;
|
||||
trackDrawTrack (ctx, {x: element.x, y: element.y}, element.dir);
|
||||
trackDrawTrack (ctx, {x: element.x, y: element.y}, element.altdir);
|
||||
}
|
||||
else if (element.type == RAILWAY_TEXT) {
|
||||
ctx.font = "14px Arial";
|
||||
ctx.textAlign = "left";
|
||||
if (element.name != "") {
|
||||
ctx.fillStyle = "lightblue";
|
||||
ctx.fillText(element.name, (element.x+0.5) * track.scale, 6+(element.y+0.5) * track.scale);
|
||||
}
|
||||
else {
|
||||
ctx.fillStyle = "DeepPink";
|
||||
ctx.fillText("------", (element.x+0.5) * track.scale, (element.y+0.5) * track.scale);
|
||||
}
|
||||
}
|
||||
else if (element.type == RAILWAY_CONNECTOR) {
|
||||
ctx.font = "bold 12px Arial";
|
||||
ctx.textAlign = "center";
|
||||
if (element.name != "") {
|
||||
ctx.fillStyle = "#FFFFFF";
|
||||
ctx.fillText(element.name, (element.x+0.5) * track.scale, 6+(element.y+0.5) * track.scale);
|
||||
}
|
||||
else {
|
||||
ctx.fillStyle = "DeepPink";
|
||||
ctx.fillText("------", (element.x+0.5) * track.scale, (element.y+0.5) * track.scale);
|
||||
}
|
||||
}
|
||||
else if (element.type != RAILWAY_NOTHING) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([0,0]);
|
||||
ctx.strokeStyle = "DeepPink";
|
||||
ctx.moveTo((element.x+0.25) * track.scale, (element.y+0.25) * track.scale);
|
||||
ctx.lineTo((element.x+0.75) * track.scale, (element.y+0.75) * track.scale);
|
||||
ctx.moveTo((element.x+0.75) * track.scale, (element.y+0.25) * track.scale);
|
||||
ctx.lineTo((element.x+0.25) * track.scale, (element.y+0.75) * track.scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
//
|
||||
// additional draing of elements
|
||||
if (element.type == RAILWAY_SENSOR) {
|
||||
ctx.beginPath();
|
||||
ctx.arc((element.x+0.5) * track.scale, (element.y+0.5) * track.scale, track.scale*0.25, 0, 2 * Math.PI);
|
||||
if (element.name == "") ctx.fillStyle = 'DeepPink';
|
||||
else if (sensor_IsActive(element.name)) ctx.fillStyle = 'LightGreen';
|
||||
else ctx.fillStyle = 'DimGray';
|
||||
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeStyle = "#000000";
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
//
|
||||
// draw ref. name
|
||||
if (element.name && sideBtnModeGet() == "mode-turn") {
|
||||
if (element.type != RAILWAY_TEXT && element.type != RAILWAY_CONNECTOR) {
|
||||
ctx.font = "10px Arial";
|
||||
ctx.textAlign = "left";
|
||||
if (element.name != "") {
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillText(element.name, (element.x) * track.scale -1, 6+(element.y+0.5) * track.scale );
|
||||
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale );
|
||||
ctx.fillText(element.name, (element.x) * track.scale , 6+(element.y+0.5) * track.scale -1);
|
||||
ctx.fillText(element.name, (element.x) * track.scale , 6+(element.y+0.5) * track.scale +1);
|
||||
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale +1);
|
||||
ctx.fillText(element.name, (element.x) * track.scale -1, 6+(element.y+0.5) * track.scale -1);
|
||||
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale -1);
|
||||
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale +1);
|
||||
ctx.fillText(element.name, (element.x) * track.scale -1, 6+(element.y+0.5) * track.scale +1);
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillText(element.name, (element.x) * track.scale , 6+(element.y+0.5) * track.scale );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function trackDraw() {
|
||||
var ctx = track.dbuf.getContext("2d");
|
||||
var elm = {};
|
||||
|
||||
// debug ("trackDraw pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
|
||||
// " down: " + trackMouse.down.x + "," + trackMouse.down.y);
|
||||
|
||||
|
||||
//
|
||||
// clear screen
|
||||
ctx.fillStyle = "#808080";
|
||||
ctx.fillRect(0, 0, track.size.x * track.scale, track.size.y * track.scale);
|
||||
|
||||
//
|
||||
//
|
||||
for (var i = 0; i < track.elements.length; i++) {
|
||||
trackDrawElement(ctx, track.elements[i], 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 = "#0000FF";
|
||||
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;
|
||||
ctx.lineJoin="round";
|
||||
ctx.miterLimit = 1;
|
||||
ctx.setLineDash([2,2]);
|
||||
ctx.strokeStyle = "#000000";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0.5+(trackMouse.pos.x + 0) * track.scale, 0.5+(trackMouse.pos.y+0) * track.scale);
|
||||
ctx.lineTo(0.5+(trackMouse.pos.x + 1) * track.scale, 0.5+(trackMouse.pos.y+0) * track.scale);
|
||||
ctx.lineTo(0.5+(trackMouse.pos.x + 1) * track.scale, 0.5+(trackMouse.pos.y+1) * track.scale);
|
||||
ctx.lineTo(0.5+(trackMouse.pos.x + 0) * track.scale, 0.5+(trackMouse.pos.y+1) * track.scale);
|
||||
ctx.lineTo(0.5+(trackMouse.pos.x + 0) * track.scale, 0.5+(trackMouse.pos.y+0) * track.scale);
|
||||
ctx.stroke();
|
||||
|
||||
//
|
||||
// draw mouseselection
|
||||
var mode = sideBtnModeGet();
|
||||
|
||||
if ((mode == "mode-rail" || mode == "mode-delete") &&
|
||||
trackMouse.down.x >= 0 && trackMouse.down.y >= 0) {
|
||||
var selected = new Array();
|
||||
|
||||
selected.length = 0;
|
||||
selected = trackGetElementList(trackMouse.down, trackMouse.pos, trackMouse.direction);
|
||||
for (i = 0; i < selected.length; i++) {
|
||||
trackDrawElement(ctx, selected[i], 1);
|
||||
}
|
||||
selected.length = 0;
|
||||
var infoline = document.getElementById("infoline");
|
||||
if (infoline) infoline.innerHTML = trackMouse.direction;
|
||||
}
|
||||
|
||||
//
|
||||
// draw possible turnout
|
||||
else if (mode == "mode-turn") {
|
||||
var t = trackGetTurnout({x: trackMouse.pos.x, y: trackMouse.pos.y});
|
||||
}
|
||||
|
||||
//
|
||||
// flip screen - double buffering
|
||||
trackFlipScreen();
|
||||
};
|
||||
|
||||
|
||||
function trackFlipScreen() {
|
||||
var c = document.getElementById("TrackCanvas");
|
||||
var ctx = c.getContext("2d");
|
||||
|
||||
ctx.drawImage(track.dbuf, 0, 0);
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// callback functionen
|
||||
//
|
||||
|
||||
function trackMouseGetPos(event) {
|
||||
var p = { x: 0, y: 0, subx: 0.5, suby: 0.5 };
|
||||
var x, dx;
|
||||
var y, dy;
|
||||
|
||||
p.x = Math.floor((event.pageX - 1 - $('#TrackCanvas').offset().left) / track.scale);
|
||||
p.y = Math.floor((event.pageY - 1 - $('#TrackCanvas').offset().top) / track.scale);
|
||||
|
||||
x = (event.pageX - 1 - $('#TrackCanvas').offset().left) / track.scale;
|
||||
y = (event.pageY - 1 - $('#TrackCanvas').offset().top) / track.scale;
|
||||
p.subx = x - p.x;
|
||||
p.suby = y - p.y;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
function trackMousemove(event) {
|
||||
var mode = sideBtnModeGet();
|
||||
|
||||
trackMouse.pos = trackMouseGetPos(event);
|
||||
// debug ("trackMousemove pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
|
||||
// " subx: " + trackMouse.pos.subx + " suby:" + trackMouse.pos.suby);
|
||||
|
||||
trackDraw();
|
||||
};
|
||||
|
||||
|
||||
function trackMousedown(event) {
|
||||
var mode = sideBtnModeGet();
|
||||
var tmp = trackMouseGetPos(event);
|
||||
|
||||
if (mode == "mode-rail" || mode == "mode-delete") {
|
||||
trackMouse.down = trackMouseGetPos(event);
|
||||
}
|
||||
|
||||
// debug ("trackMousedown pos: " + tmp.x + "," + tmp.y + " subx: " + tmp.subx + " suby:" + tmp.suby);
|
||||
|
||||
trackDraw();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
function trackMouseup(event) {
|
||||
var mode = sideBtnModeGet();
|
||||
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);
|
||||
|
||||
if (mode == "mode-rail") {
|
||||
var pos = {};
|
||||
var selected = new Array();
|
||||
|
||||
selected.length = 0;
|
||||
selected = trackGetElementList(trackMouse.down, trackMouse.pos, trackMouse.direction);
|
||||
serverinout_addTrack(selected);
|
||||
selected.length = 0;
|
||||
}
|
||||
|
||||
else if (mode == "mode-turn") {
|
||||
rwdetail_show(trackMouse.pos.x, trackMouse.pos.y);
|
||||
}
|
||||
|
||||
else if (mode == "mode-delete") {
|
||||
var pos = {};
|
||||
var xs, ys, xe ,ye;
|
||||
var selected = new Array();
|
||||
|
||||
selected.length = 0;
|
||||
|
||||
//
|
||||
// determine which direction to count.
|
||||
if (trackMouse.down.x <= trackMouse.pos.x) {
|
||||
xs = trackMouse.down.x;
|
||||
xe = trackMouse.pos.x;
|
||||
}
|
||||
else {
|
||||
xs = trackMouse.pos.x;
|
||||
xe = trackMouse.down.x;
|
||||
}
|
||||
|
||||
if (trackMouse.down.y <= trackMouse.pos.y) {
|
||||
ys = trackMouse.down.y;
|
||||
ye = trackMouse.pos.y;
|
||||
}
|
||||
else {
|
||||
ys = trackMouse.pos.y;
|
||||
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;
|
||||
}
|
||||
else {
|
||||
rw_Click(trackMouse.pos.x, trackMouse.pos.y);
|
||||
}
|
||||
|
||||
trackMouse.down.x = -1;
|
||||
trackMouse.down.y = -1;
|
||||
trackMouse.step = 0;
|
||||
|
||||
trackDraw();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
if (track.size.x > 0 && track.size.y > 0) {
|
||||
track.elements[elm.x + track.size.y * elm.y] = elm;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// init the track view screen
|
||||
// bind callback functions
|
||||
function trackCreate(sizex, sizey) {
|
||||
debug ("trackCreate " + sizex + " , " + sizey);
|
||||
var canvas = document.createElement("canvas");
|
||||
|
||||
track.size.x = sizex;
|
||||
track.size.y = sizey;
|
||||
|
||||
canvas.setAttribute("id", "TrackCanvas");
|
||||
canvas.height = track.size.y * track.scale;
|
||||
canvas.width = track.size.x * track.scale;
|
||||
canvas.addEventListener('mousemove', trackMousemove);
|
||||
canvas.addEventListener('mousedown', trackMousedown);
|
||||
canvas.addEventListener('mouseup', trackMouseup);
|
||||
track.dbuf = document.createElement("canvas");
|
||||
track.dbuf.setAttribute("id", "TrackCanvasDBUF");
|
||||
track.dbuf.height = track.size.y * track.scale;
|
||||
track.dbuf.width = track.size.x * track.scale;
|
||||
|
||||
track.array = new Array();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// get the size fo track from server, setup all data
|
||||
function trackSetup(tracksetup) {
|
||||
debug ("trackSetup");
|
||||
|
||||
var client = document.getElementById("page_main");
|
||||
var oldc = document.getElementById("TrackCanvas");
|
||||
var olddbuf = document.getElementById("TrackCanvasDBUF");
|
||||
|
||||
if (oldc) oldc.remove();
|
||||
if (olddbuf) olddbuf.remove();
|
||||
|
||||
// client.removeChild(oldc);
|
||||
|
||||
var canvas = trackCreate (tracksetup.width, tracksetup.height);
|
||||
client.appendChild (canvas);
|
||||
|
||||
trackDraw();
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// return a new list of railways elements
|
||||
// this list can be added to the server or deleted from.
|
||||
// or useing this list for drawing preview
|
||||
// START: will contain the position with the sub position (clockwise: 0, 3, 6, 9)
|
||||
//
|
||||
function trackGetElementList(start, end) {
|
||||
var list = new Array();
|
||||
|
||||
var pstart;
|
||||
var pend;
|
||||
|
||||
if (start.x > end.x) {
|
||||
pstart = {x: end.x, y:end.y, subx: end.subx, suby: end.suby};
|
||||
pend = {x: start.x, y:start.y, subx: start.subx, suby: start.suby};
|
||||
}
|
||||
else {
|
||||
pstart = {x: start.x, y:start.y, subx: start.subx, suby: start.suby};
|
||||
pend = {x: end.x, y:end.y, subx: end.subx, suby: end.suby};
|
||||
}
|
||||
|
||||
//
|
||||
// clicked on a singlke field.
|
||||
if (pstart.x == pend.x && pstart.y == pend.y) {
|
||||
x = pstart.x;
|
||||
y = pstart.y;
|
||||
if (pstart.subx <= 0.33 && pstart.suby <= 0.33)
|
||||
list.push ({x: x, y: y, dir: 3, type: 1});
|
||||
if (pstart.subx <= 0.33 && pstart.suby >= 0.66)
|
||||
list.push ({x: x, y: y, dir: 6, type: 1});
|
||||
|
||||
if (pstart.subx >= 0.66 && pstart.suby <= 0.33)
|
||||
list.push ({x: x, y: y, dir: 4, type: 1});
|
||||
if (pstart.subx >= 0.66 && pstart.suby >= 0.66)
|
||||
list.push ({x: x, y: y, dir: 5, type: 1});
|
||||
|
||||
if (pstart.subx >= 0.33 && pstart.subx <= 0.66 && (pstart.suby <= 0.33 || pstart.suby >= 0.66))
|
||||
list.push ({x: x, y: y, dir: 1, type: 1});
|
||||
if (pstart.suby >= 0.33 && pstart.suby <= 0.66 && (pstart.subx <= 0.33 || pstart.subx >= 0.66))
|
||||
list.push ({x: x, y: y, dir: 2, type: 1});
|
||||
}
|
||||
else {
|
||||
var dx = pend.x - pstart.x;
|
||||
var dy = pend.y - pstart.y;
|
||||
var m, x, y;
|
||||
|
||||
if (dx != 0 && dy != 0) m = dy / dx;
|
||||
else if (dx == 0) m = 100; // Y
|
||||
else m = 0; // X
|
||||
|
||||
x = pstart.x;
|
||||
y = pstart.y;
|
||||
if (Math.abs(m) > 0.5 && Math.abs(m) < 2) {
|
||||
var elm; // save last element
|
||||
|
||||
if (m < 0) { // "/"
|
||||
// select starting point
|
||||
if (pstart.suby < 0.5) elm = 3;
|
||||
else elm = 5;
|
||||
|
||||
for (; x <= pend.x && y >= pend.y;) {
|
||||
if (elm == 3) {
|
||||
list.push ({x: x, y: y, dir: elm, type: 1});
|
||||
elm = 5;
|
||||
y = y - 1;
|
||||
}
|
||||
else if (elm == 5) {
|
||||
list.push ({x: x, y: y, dir: elm, type: 1});
|
||||
elm = 3;
|
||||
x = x + 1;
|
||||
}
|
||||
else {
|
||||
// should not possible but somehow we ended up here
|
||||
debug ("trackGetElementList: ERROR elm 3 or 5 expected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // "\"
|
||||
// select starting point
|
||||
if (pstart.suby < 0.5) elm = 4;
|
||||
else elm = 6;
|
||||
|
||||
for (; x <= pend.x && y <= pend.y;) {
|
||||
if (elm == 4) {
|
||||
list.push ({x: x, y: y, dir: elm, type: 1});
|
||||
elm = 6;
|
||||
x = x + 1;
|
||||
}
|
||||
else if (elm == 6) {
|
||||
list.push ({x: x, y: y, dir: elm, type: 1});
|
||||
elm = 4;
|
||||
y = y + 1;
|
||||
}
|
||||
else {
|
||||
// should not possible but somehow we ended up here
|
||||
debug ("trackGetElementList: ERROR elm 4 or 6 expected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Math.abs(m) >= 2) {
|
||||
if (m > 0) {
|
||||
dirtype = 1;
|
||||
for (; y <= pend.y; y++)
|
||||
list.push ({x: x, y: y, dir: dirtype, type: 1});
|
||||
}
|
||||
else {
|
||||
dirtype = 1;
|
||||
for (; y >= pend.y; y--)
|
||||
list.push ({x: x, y: y, dir: dirtype, type: 1});
|
||||
}
|
||||
}
|
||||
else { // m < 0.5
|
||||
if (m >= 0) {
|
||||
dirtype = 2;
|
||||
for (; x <= pend.x; x++)
|
||||
list.push ({x: x, y: y, dir: dirtype, type: 1});
|
||||
}
|
||||
else {
|
||||
dirtype = 2;
|
||||
for (; x >= pend.x; x--)
|
||||
list.push ({x: x, y: y, dir: dirtype, type: 1});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
//
|
||||
// returns the element at the givin point
|
||||
function trackGetTurnout(mousepos) {
|
||||
var pos = {x: mousepos.x, y: mousepos.y};
|
||||
var elm = {};
|
||||
|
||||
for (var i = 0; i < track.elements.length; i++) {
|
||||
if (track.elements[i]) {
|
||||
if (track.elements[i].x == pos.x && track.elements[i].y == pos.y) elm = track.elements[i];
|
||||
}
|
||||
}
|
||||
|
||||
return elm;
|
||||
};
|
||||
|