You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
6.3 KiB
269 lines
6.3 KiB
/*
|
|
* z21prot.cc
|
|
*
|
|
* Created on: 15.12.2017
|
|
* Author: steffen
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "z21prot.h"
|
|
#include "z21emu.h"
|
|
#include "debug.h"
|
|
|
|
Z21Client::Z21Client() {
|
|
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
};
|
|
|
|
Z21Client::~Z21Client() {
|
|
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
};
|
|
|
|
bool Z21Client::LoopData (UDPConnection *udp, char *buffer, size_t len) {
|
|
short unsigned int pktlen = le16toh(bufgetint16(buffer, 0));
|
|
short int pktheader = le16toh(bufgetint16(buffer, 2));
|
|
int i, k;
|
|
|
|
// LAN_GET_SERIAL_NUMBER
|
|
if (pktlen == 4 && pktheader == 0x10) {
|
|
bufsetint16 (outbuf, 0, htole16(8));
|
|
bufsetint16 (outbuf, 2, htole16(0x10));
|
|
bufsetint32 (outbuf, 4, htole32(55555953));
|
|
udp->Send(source, outbuf, 8);
|
|
}
|
|
|
|
// LAN_LOGOFF
|
|
else if (pktlen == 4 && pktheader == 0x0030) {
|
|
return false;
|
|
}
|
|
|
|
// LAN_X_ Commandos
|
|
else if (pktheader == 0x0040) {
|
|
if (pktlen > len) {
|
|
printf ("ERROR: got broken udp paket? pktlen(%d) > len(%ld)\n", pktlen, len);
|
|
} else {
|
|
Z21_lan_x_data xdata;
|
|
int pos = 4;
|
|
int chksum;
|
|
char db;
|
|
|
|
while (pos < pktlen) {
|
|
xdata.xheader = buffer[pos++];
|
|
for (i = 0; i < Z21_X_LEN && (unsigned int) i+pos < len; i++)
|
|
xdata.db[i] = buffer[pos+i];
|
|
|
|
// LAN_X_GET_VERSION
|
|
if (xdata.xheader == 0x21 &&
|
|
xdata.db[0] == 0x21 && xdata.db[1] == 0x00) {
|
|
printf ("LAN_X_GET_VERSION\n");
|
|
pos += 2;
|
|
|
|
bufsetint16 (outbuf, 0, htole16(9));
|
|
bufsetint16 (outbuf, 2, htole16(0x40));
|
|
|
|
k = 4;
|
|
bufsetint8 (outbuf, k++, db=0x63); // XHeader
|
|
chksum = db;
|
|
|
|
bufsetint8 (outbuf, k++, db=0x21); // DB0
|
|
chksum = chksum ^ db;
|
|
|
|
bufsetint8 (outbuf, k++, db=0x30); // DB1
|
|
chksum = chksum ^ db;
|
|
|
|
bufsetint8 (outbuf, k++, db=0x12); // DB2
|
|
chksum = chksum ^ db;
|
|
|
|
bufsetint8 (outbuf, k++, chksum); // XOR-Byte
|
|
// debug_mem(outbuf, k);
|
|
udp->Send(source, outbuf, k);
|
|
}
|
|
|
|
// LAN_X_GET_FIRMWARE_VERSION
|
|
else if (xdata.xheader == 0xF1 &&
|
|
xdata.db[0] == 0x0A && xdata.db[1] == 0xFB) {
|
|
printf ("LAN_X_GET_FIRMWARE_VERSION\n");
|
|
pos += 3;
|
|
|
|
bufsetint16 (outbuf, 0, htole16(9)); // LEN
|
|
bufsetint16 (outbuf, 2, htole16(0x40)); // X_CMD
|
|
|
|
k = 4;
|
|
bufsetint8 (outbuf, k++, db=0xF3); // XHeader
|
|
chksum = db;
|
|
|
|
bufsetint8 (outbuf, k++, db=0x0A); // DB0
|
|
chksum = chksum ^ db;
|
|
|
|
bufsetint8 (outbuf, k++, db=0x01); // DB1
|
|
chksum = chksum ^ db;
|
|
|
|
bufsetint8 (outbuf, k++, db=0x20); // DB2
|
|
chksum = chksum ^ db;
|
|
|
|
bufsetint8 (outbuf, k++, chksum); // XOR-Byte
|
|
// debug_mem(outbuf, k);
|
|
udp->Send(source, outbuf, k);
|
|
}
|
|
|
|
// LAN_X_SET_TURNOUT
|
|
else if (xdata.xheader == 0x53) {
|
|
int addr = (xdata.db[0] << 8) + xdata.db[1];
|
|
int cmd = xdata.db[2];
|
|
int cmd_q = cmd & 0x20;
|
|
int cmd_a = cmd & 0x08;
|
|
int cmd_p = cmd & 0x01;
|
|
pos += 4;
|
|
printf ("LAN_X_SETTURNOUT addr: %d cmd: %x (q:%d a:%d p:%d)\n", addr, cmd, cmd_q, cmd_a, cmd_p);
|
|
xlan_turnout (addr, (cmd_a != 0));
|
|
}
|
|
|
|
else {
|
|
printf ("LAN_X command not understood: %x\n", xdata.xheader);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// LAN_RMBUS_GETDATA --> send LAN_RMBUS_DATACHANGED
|
|
else if (pktheader == 0x0081 && pktlen == 5) {
|
|
unsigned char rmbus_grpidx = bufgetint8(buffer, 4);
|
|
printf ("LAN_RMBUS_GETDATA\n");
|
|
Send_LAN_RMBUS_DATACHANGED(udp, rmbus_grpidx);
|
|
}
|
|
|
|
else {
|
|
printf ("unknown command: ");
|
|
// debug_mem (buffer, len);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void Z21Client::Send_LAN_RMBUS_DATACHANGED (UDPConnection *udp, unsigned char grpidx) {
|
|
int k, i;
|
|
|
|
printf ("Send LAN_RMBUS_DATACHANGED\n");
|
|
if (grpidx >= RBUS_GROUPS) {
|
|
printf (" giving group (%d) is not supported.\n", grpidx);
|
|
return;
|
|
}
|
|
bufsetint16 (outbuf, 0, htole16(15)); // LEN
|
|
bufsetint16 (outbuf, 2, htole16(0x80)); // X_CMD
|
|
|
|
k = 4;
|
|
bufsetint8 (outbuf, k++, grpidx); // Gruppenindex
|
|
|
|
for (i = 0; i < RBUS_BYTESPERGROUP; i++)
|
|
bufsetint8 (outbuf, k++, rbus[grpidx*RBUS_BYTESPERGROUP + i].status);
|
|
|
|
udp->Send(source, outbuf, k);
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
Z21Server::Z21Server () {
|
|
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
};
|
|
|
|
Z21Server::~Z21Server () {
|
|
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
};
|
|
|
|
void Z21Server::Start() {
|
|
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
udp.Listen(DEFAULT_Z21PORT);
|
|
};
|
|
|
|
|
|
int Z21Server::Loop() {
|
|
string source;
|
|
size_t len;
|
|
int newclient = 1;
|
|
list<Z21Client*>::iterator iter;
|
|
int i, grp;
|
|
|
|
if (udp.isListen()) {
|
|
//
|
|
// read new data from UDP
|
|
len = udp.ReadTimeout(&source, buffer, NET_BUFFERSIZE, 25); // timeout 25ms
|
|
if (len > 0) {
|
|
//
|
|
// check known connection
|
|
newclient = 1;
|
|
iter = clients.begin();
|
|
while (iter != clients.end()) {
|
|
if ((*iter)->isSource(source)) {
|
|
newclient = 0;
|
|
if (!((*iter)->LoopData(&udp, buffer, len))) {
|
|
printf ("remove client: '%s' count:%ld\n", source.c_str(), clients.size());
|
|
iter = clients.erase(iter);
|
|
}
|
|
break;
|
|
}
|
|
iter++;
|
|
}
|
|
|
|
//
|
|
// new connection
|
|
if (newclient && iter == clients.end()) {
|
|
Z21Client *client;
|
|
client = new Z21Client();
|
|
client->setSource(source);
|
|
if (client->LoopData(&udp, buffer, len)) {
|
|
clients.push_back(client);
|
|
printf ("add client: '%s' count:%ld\n", source.c_str(), clients.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// broadcast changed values
|
|
for (grp = 0; grp < RBUS_GROUPS; grp++) {
|
|
for (i = 0; i < RBUS_BYTESPERGROUP; i++)
|
|
if (rbus[grp*RBUS_BYTESPERGROUP+i].status != rbus[grp*RBUS_BYTESPERGROUP+i].last) break;
|
|
if (i != RBUS_BYTESPERGROUP) {
|
|
//
|
|
// send broadcast to all clients
|
|
for (iter = clients.begin(); iter != clients.end(); iter++)
|
|
(*iter)->Send_LAN_RMBUS_DATACHANGED(&udp, grp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return clients.size();
|
|
};
|
|
|
|
/************************************************************************/
|
|
|
|
uint8_t bufgetint8 (char *buf, int pos) {
|
|
int8_t i;
|
|
memcpy (&i, buf+pos, 1);
|
|
return i;
|
|
};
|
|
|
|
uint16_t bufgetint16 (char *buf, int pos) {
|
|
int16_t i;
|
|
memcpy (&i, buf+pos, 2);
|
|
return i;
|
|
};
|
|
|
|
uint32_t bufgetint32 (char *buf, int pos) {
|
|
int32_t i;
|
|
memcpy (&i, buf+pos, 4);
|
|
return i;
|
|
};
|
|
|
|
void bufsetint8 (char *buf, int pos, uint8_t i) {
|
|
memcpy (buf+pos, &i, 1);
|
|
};
|
|
|
|
void bufsetint16 (char *buf, int pos, uint16_t i) {
|
|
memcpy (buf+pos, &i, 2);
|
|
};
|
|
|
|
void bufsetint32 (char *buf, int pos, uint32_t i) {
|
|
memcpy (buf+pos, &i, 4);
|
|
};
|
|
|