InterfaceZ21 is now a subclass of Interface

master
Steffen Pohle 4 years ago
parent 206871b2c0
commit 9b1eb38f29

@ -1,3 +1,6 @@
2022-02-13:
- Interfaces are now virtual classes.
2021-12-19:
- adding sensor context menu for sensor simulation

@ -17,8 +17,8 @@ DEPENDFILE=.depend
TARGET=modelbahn-server
SERVEROBJ=server.o network.o session.o server-loadsave.o debug.o \
json.o main.o sensor.o turnout.o railway.o interface.o locomotive.o \
block.o interface-z21.o
json.o main.o sensor.o turnout.o railway.o interfaces.o locomotive.o \
block.o interface.o interface-z21.o
CURDIR=`pwd`

@ -33,11 +33,14 @@ static unsigned char RX_RMBUS_DATACHANGED[] { 0x0F, 0x00, 0x80, 0x00 };
#define Z21_IDX_SETTURNOUT_CHK 8
InterfaceZ21::InterfaceZ21 () {
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21:%s", __FUNCTION__);
status_connected = false;
status_poweron = false;
status_programmingmode = false;
status_shortcircuit = false;
status_emergencystop = false;
timer_start(&turnouttimeout);
send_logon = false;
@ -45,7 +48,6 @@ InterfaceZ21::InterfaceZ21 () {
rmsensorinit = 0;
serial = "";
hostname = "";
timeout = time(NULL);
rmgetdatatimeout = time(NULL) - INTF_Z21_RMGETDATA_TIMEOUT;
};
@ -55,11 +57,11 @@ InterfaceZ21::~InterfaceZ21() {
};
void InterfaceZ21::Connect (string destination) {
debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Connect to: %s", __FILE__, __LINE__, destination.c_str());
void InterfaceZ21::Connect () {
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21: Connect to: %s", host);
if (status_connected) Disconnect();
hostname = destination;
if (udp.Listen(0) == 0) {
debug (DEBUG_ERROR | DEBUG_IFACE, "%s:%d Error could not bind UDP socket (%s)",
@ -102,7 +104,14 @@ int InterfaceZ21::Loop(string interfacename) {
string source;
int inlen;
int i;
int update = false;
int needs_update = false;
// debug (DEBUG_INFO | DEBUG_IFACE, "* InterfaceZ21 (%s) Loop", name);
flags &= ~(INTF_F_CONNECTED | INTF_F_POWER | INTF_F_STOP | INTF_F_SHORT_CIRCUIT | INTF_F_PROGRAMMING);
if (needs_update) {
needs_update = 0;
}
if (status_connected) {
//
@ -110,14 +119,14 @@ int InterfaceZ21::Loop(string interfacename) {
if ((timeout + 2 * INTF_Z21_TIMEOUT) < curtime) {
debug (DEBUG_ERROR | DEBUG_IFACE, "%s:%d connection timed out (%d)", __FILE__, __LINE__, curtime-(timeout + 2 * INTF_Z21_TIMEOUT));
Disconnect();
update = true;
needs_update = true;
}
else if (send_logon == false && (timeout + INTF_Z21_TIMEOUT) < curtime) {
send_logon = true;
send_GET_SERIAL_NUMBER();
send_SET_BROADCASTFLAGS();
timeout = time(NULL);
update = true;
needs_update = true;
}
//
@ -173,7 +182,7 @@ int InterfaceZ21::Loop(string interfacename) {
debug (0, "%s:%d cs:%d csex:%d", __FILE__, __LINE__, cs, csex);
update = true;
needs_update = true;
//if ( old_poweron != status_poweron ||
// old_shortcircuit != status_shortcircuit ||
// old_programmingmode != status_programmingmode ||
@ -286,7 +295,7 @@ int InterfaceZ21::Loop(string interfacename) {
}
}
return update;
return needs_update;
};
@ -294,14 +303,14 @@ int InterfaceZ21::Loop(string interfacename) {
// send_SET_BROADCASTFLAGS();
void InterfaceZ21::send_SET_BROADCASTFLAGS() {
unsigned char buffer[] = { 0x08, 0x00, 0x50, 0x00, 0x0F, 0x01, 0x00, 0x03 };
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
//
// send_GET_SERIAL_NUMBER
void InterfaceZ21::send_GET_SERIAL_NUMBER() {
unsigned char buffer[] = { 0x04, 0x00, 0x10, 0x00 };
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
@ -311,7 +320,7 @@ void InterfaceZ21::send_RM_GETDATA(int group) {
unsigned char buffer[] = { 0x05, 0x00, 0x81, 0x00, 0x00 };
if (group < INTF_Z21_RMSENSOR_GROUPS) {
buffer[4] = (unsigned char)group;
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
}
@ -322,7 +331,7 @@ void InterfaceZ21::send_LOGOFF() {
if (status_connected == false) return;
unsigned char buffer[] = { 0x04, 0x00, 0x30, 0x00 };
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
}
@ -383,7 +392,7 @@ void InterfaceZ21::SetLocoSpeed(Locomotive *l, int step) {
printf ("%02x:", z);
}
printf ("\n");
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
loconet_last.addr = l->addr;
loconet_last.dir = l->flags & LOCO_F_REVERSE;
loconet_last.speed = l->speed;
@ -404,6 +413,17 @@ void InterfaceZ21::SetLocoFunction(Locomotive *l, int func, int value) {
void InterfaceZ21::SetTurnout(Turnout *t, int activate, int outputactive) {
unsigned char buffer[] = { 0x09, 0x00, 0x40, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00 };
debug (DEBUG_INFO | DEBUG_IFACE, "InterfaceZ21 (%s) SetTurnout Addr:%d Acitve:%d Output:%d", name,
t->addr, activate, outputactive);
//
//
if (outputactive == 1 && timer_get(&turnouttimeout) < 100) {
debug (0, "%s:%d Interface need to wait between two turnout commands", __FILE__, __LINE__);
return;
}
timer_start(&turnouttimeout);
//
// setup turnout addr
buffer[Z21_IDX_SETTURNOUT_ADRL] = (unsigned char) (t->addr & 0xFF);
@ -420,14 +440,14 @@ void InterfaceZ21::SetTurnout(Turnout *t, int activate, int outputactive) {
for (int i = 4; i < (int) sizeof (buffer)-1; i++)
buffer[Z21_IDX_SETTURNOUT_CHK] = (unsigned char)buffer[Z21_IDX_SETTURNOUT_CHK] xor (unsigned char)buffer[i];
/* printf ("Send Data:");
for (int i = 0; i < sizeof (buffer); i++) {
int z = (unsigned char) buffer[i];
printf ("%02x:", z);
}
printf ("\n");
*/
udp.Write(hostname, (char*)buffer, sizeof (buffer));
udp.Write(host, (char*)buffer, sizeof (buffer));
//
// set the output flag
if (outputactive) t->flags |= TURNOUT_F_ACTIVE;
else t->flags &= ~TURNOUT_F_ACTIVE;
gettimeofday (&t->activatetime, NULL);
};
@ -438,9 +458,9 @@ 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));
udp.Write(host, (char*)TX_X_SET_TRACK_POWER_ON, sizeof (TX_X_SET_TRACK_POWER_ON));
}
else {
udp.Write(hostname, (char*)TX_X_SET_TRACK_POWER_OFF, sizeof (TX_X_SET_TRACK_POWER_OFF));
udp.Write(host, (char*)TX_X_SET_TRACK_POWER_OFF, sizeof (TX_X_SET_TRACK_POWER_OFF));
}
};

@ -28,9 +28,8 @@ struct s_loconet_map{
int maxspeed;
};
class InterfaceZ21 {
class InterfaceZ21: public Interface {
private:
string hostname;
string serial;
char inbuffer[INTF_Z21_INBUFFER];
struct s_loconet_map loconet_map[INTF_Z21_LOCONET_MAXADDR];
@ -39,6 +38,7 @@ class InterfaceZ21 {
UDP udp;
time_t timeout;
time_t rmgetdatatimeout;
struct timeval turnouttimeout;
bool send_logon;
bool status_poweron;
@ -61,7 +61,7 @@ class InterfaceZ21 {
InterfaceZ21();
~InterfaceZ21();
void Connect(string destination);
void Connect();
void Disconnect();
bool IsConnected() { return status_connected; };

@ -10,12 +10,13 @@
// **************************************************************************
Interface::Interface() {
debug (DEBUG_INFO | DEBUG_IFACE, "Interface:%s", __FUNCTION__);
name[0] = 0;
host[0] = 0;
flags = 0;
type = INTF_T_OFF_UNKNOWN;
needs_update = true;
timer_start(&turnouttimeout);
};
Interface::~Interface() {
@ -24,31 +25,16 @@ 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;
}
};
/*
@ -61,25 +47,6 @@ void Interface::SetTurnout(Turnout *t, int active, int outputactive) {
debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Interface (%s) SetTurnout Addr:%d Acitve:%d Output:%d", __FILE__, __LINE__, name,
t->addr, active, outputactive);
//
//
if (outputactive == 1 && timer_get(&turnouttimeout) < 100) {
debug (0, "%s:%d Interface need to wait between two turnout commands", __FILE__, __LINE__);
return;
}
timer_start(&turnouttimeout);
switch (type) {
case INTF_T_Z21: intz21.SetTurnout(t, active, outputactive); break;
default: break;
}
//
// set the output flag
if (outputactive) t->flags |= TURNOUT_F_ACTIVE;
else t->flags &= ~TURNOUT_F_ACTIVE;
gettimeofday (&t->activatetime, NULL);
};
//
@ -87,329 +54,42 @@ void Interface::SetTurnout(Turnout *t, int active, int outputactive) {
//
void Interface::SetLocoSpeed(Locomotive *l, int step) {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) SetLocoSpeed Addr:%d Speed:%d ", name, l->addr, step);
switch (type) {
case INTF_T_Z21: intz21.SetLocoSpeed(l, step); break;
default: break;
}
};
void Interface::SetLocoFunction(Locomotive *l, int func, int value) {
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) SetLocoFunction Addr:%d Func:%d:%d", name, l->addr, func, value);
switch (type) {
case INTF_T_Z21: intz21.SetLocoFunction(l, func, value); break;
default: break;
}
};
//
// if update is needed return 1
//
int Interface::Loop() {
int ret = 0;
// debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) Loop", name);
flags &= ~(INTF_F_CONNECTED | INTF_F_POWER | INTF_F_STOP | INTF_F_SHORT_CIRCUIT | INTF_F_PROGRAMMING);
if (needs_update) {
ret = 1;
needs_update = 0;
}
switch (type) {
case INTF_T_Z21:
ret = intz21.Loop(name);
if (intz21.IsConnected()) flags |= INTF_F_CONNECTED;
if (intz21.IsPoweron()) flags |= INTF_F_POWER;
if (intz21.IsEmergencyStop()) flags |= INTF_F_STOP;
if (intz21.IsSortCircuit()) flags |= INTF_F_SHORT_CIRCUIT;
break;
default: break;
}
// debug (DEBUG_INFO | DEBUG_IFACE, "%s:%d Interface: name:'%s' , Flags: %d", __FILE__, __LINE__, name, flags);
return ret;
};
bool Interface::IsConnected() {
bool ret = false;
switch (type) {
case INTF_T_Z21: ret = intz21.IsConnected(); break;
default: break;
}
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsConnected", name);
return ret;
}
bool Interface::IsPoweron() {
bool ret = false;
switch (type) {
case 1: ret = intz21.IsPoweron(); break;
default: break;
}
debug (DEBUG_INFO | DEBUG_IFACE, "* Interface (%s) IsPoweron", name);
return ret;
}
// **************************************************************************
// *
// * I N T E R F A C E S (gateway to all devices)
// *
// **************************************************************************
Interfaces::Interfaces () {
max = INTERFACES_MAX;
changed = 0;
};
Interfaces::~Interfaces() {
max = 0;
};
int Interfaces::LockThread() {
if (pthread_mutex_lock(&mtx) == 0) return 1;
else return 0;
}
int Interfaces::UnLockThread() {
if (pthread_mutex_unlock(&mtx) == 0) return 1;
else return 0;
}
JSONParse Interfaces::_GetJSON(int idx) {
JSONParse json;
JSONElement je;
string s = "";
json.Clear();
s = interfaces[idx].name; json.AddObject("name", s);
s = interfaces[idx].host; json.AddObject("host", s);
json.AddObject("flags", interfaces[idx].flags);
json.AddObject("type", interfaces[idx].type);
return json;
};
JSONParse Interfaces::GetJSON(string name) {
int i;
JSONParse jp;
jp.Clear();
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (name.compare(interfaces[i].name) == 0) {
jp = _GetJSON(i);
}
}
UnLockThread();
return jp;
};
void Interfaces::GetJSONAll(JSONParse *json) {
int i, cnt;
JSONElement je;
LockThread();
//
// write all railway data
// create json object array manualy
je.type = JSON_T_ARRAY;
je.name = "interfaces";
for (cnt = 0, i = 0; i < max; i++)
if (interfaces[i].name[0] != 0) {
if (cnt != 0) je.value += ","; // not first element
je.value += _GetJSON(i).ToString();
cnt++;
}
json->AddObject(je);
UnLockThread();
};
Interface Interfaces::GetInterfaceFromJSON(JSONParse *j) {
Interface i;
string s;
i.name[0] = 0;
i.host[0] = 0;
j->GetValue("name", &s);
strncpy (i.name, s.c_str(), REFERENCENAME_LEN);
j->GetValue("host", &s);
strncpy (i.host, s.c_str(), REFERENCENAME_LEN);
j->GetValueInt("flags", &i.flags);
j->GetValueInt("type", &i.type);
return i;
};
int Interfaces::Change(Interface *iface) {
int i;
int ifree = -1;
LockThread();
for (i = 0; i < max; i++) {
if (interfaces[i].name[0] != 0) {
// found element
if (strncmp(interfaces[i].name, iface->name, REFERENCENAME_LEN) == 0) {
ifree = i;
break;
}
}
else if (ifree == -1) ifree = i;
}
// element not found add new element
if (ifree != -1 && ifree < max) {
strncpy (interfaces[ifree].name, iface->name, REFERENCENAME_LEN);
strncpy (interfaces[ifree].host, iface->host, REFERENCENAME_LEN);
interfaces[ifree].flags = iface->flags;
interfaces[ifree].type = iface->type;
interfaces[ifree].Connect();
}
changed = 1;
UnLockThread();
return 1;
};
int Interfaces::Delete(string name) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (name.compare(interfaces[i].name) == 0) {
interfaces[i].Disconnect();
interfaces[i].name[0] = 0;
interfaces[i].host[0] = 0;
interfaces[i].flags = 0;
interfaces[i].type = INTF_T_OFF_UNKNOWN;
changed = 1;
break;
}
}
UnLockThread();
return 1;
};
void Interfaces::PowerOnOff(int onoff) {
int i;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
interfaces[i].PowerOnOff(onoff);
}
UnLockThread();
};
//
// Turnouts
//
void Interfaces::SetTurnout(Turnout *t, int active, int motoractive) {
int i;
if (t == NULL) return;
LockThread();
debug (0, "%s:%d Interfaces::SetTurnout Name:%s active:%d Output%d", __FILE__, __LINE__, t->name, active, motoractive);
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
if (strncmp(t->ifname, interfaces[i].name, REFERENCENAME_LEN) == 0)
interfaces[i].SetTurnout(t, active, motoractive);
}
UnLockThread();
};
//
// Locomotives
//
void Interfaces::SetLocoSpeed(Locomotive *l, int speed) {
int i;
int step = 0, maxstep = 0;
switch(l->stepcode) {
case LOCO_INT_DCC14: maxstep = 14; break;
case LOCO_INT_DCC28: maxstep = 28; break;
case LOCO_INT_DCC128: maxstep = 126; break;
default: maxstep = 0; break;
}
if (abs(speed) < l->vmin) step = 0;
if (abs(speed) >= l->vmin) step = (speed * (maxstep)) / l->vmax;
if (abs(speed) > l->vmax) step = maxstep;
l->speed = speed;
LockThread();
for (i = 0; i < max; i++) if (interfaces[i].name[0] != 0) {
if (!interfaces[i].IsConnected()) interfaces[i].Connect();
if (strncmp(l->ifname, interfaces[i].name, REFERENCENAME_LEN) == 0)
interfaces[i].SetLocoSpeed(l, step);
}
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());
}
}
};

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

@ -117,11 +117,15 @@ int Interfaces::Change(Interface *iface) {
int i;
int ifree = -1;
printf ("Interface Type:%d\n", iface->type);
LockThread();
for (i = 0; i < max; i++) {
if (interfaces[i] != NULL) {
// found element
if (strncmp(interfaces[i]->name, iface->name, REFERENCENAME_LEN) == 0) {
delete interfaces[i];
interfaces[i] = NULL;
ifree = i;
break;
}
@ -129,7 +133,7 @@ int Interfaces::Change(Interface *iface) {
else if (ifree == -1) ifree = i;
}
// element not found add new element
// element found or we need to add the element.
if (ifree != -1 && ifree < max) {
if (iface->type == INTF_T_Z21) interfaces[ifree] = new InterfaceZ21();
else interfaces[ifree] = new Interface();

@ -1,12 +1,13 @@
#ifndef _INTERFACE_H_
#define _INTERFACE_H_
#ifndef _INTERFACES_H_
#define _INTERFACES_H_
#include "modelbahn.h"
#include "server.h"
#include "UDPTCPNetwork.h"
#include "json.h"
#include "interface-z21.h"
#include "interface.h"
#include "interfaces.h"
#define INTF_F_CONNECTED 0x0001
#define INTF_F_POWER 0x0002
@ -15,39 +16,12 @@
#define INTF_F_PROGRAMMING 0x0010
#define INTF_F_NEEDUPDATE 0x8000 // if something changes during the Loop
#define INTF_T_OFF_UNKNOWN 0
#define INTF_T_Z21 1
class Interface {
private:
InterfaceZ21 intz21;
bool needs_update;
struct timeval turnouttimeout;
public:
char name[REFERENCENAME_LEN];
char host[NET_HOSTLEN];
int flags;
int type;
Interface();
virtual ~Interface();
virtual void Connect();
virtual void Disconnect();
virtual void PowerOnOff(int onoff);
virtual void SetLocoSpeed(Locomotive *l, int step);
virtual void SetLocoFunction(Locomotive *l, int func, int value);
virtual void SetTurnout(Turnout *t, int active, int motoractive);
virtual bool IsConnected();
virtual bool IsPoweron();
virtual int Loop();
enum {
INTF_T_OFF_UNKNOWN = 0,
INTF_T_Z21,
INTF_T_MAX
};
class Interfaces {
private:
Interface *interfaces[INTERFACES_MAX];

@ -27,7 +27,7 @@
#include "railway.h"
#include "locomotive.h"
#include "sensor.h"
#include "interface.h"
#include "interfaces.h"
#include "block.h"
enum SMODE {

Loading…
Cancel
Save