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