]> rtime.felk.cvut.cz Git - hydro.git/blobdiff - app-bohyn/src/uldy_server.cc
Added monitoring web system. Minor changes in regulator and in control.
[hydro.git] / app-bohyn / src / uldy_server.cc
diff --git a/app-bohyn/src/uldy_server.cc b/app-bohyn/src/uldy_server.cc
new file mode 100644 (file)
index 0000000..7f16daf
--- /dev/null
@@ -0,0 +1,275 @@
+#include "uldy_server.h"
+
+using namespace std;
+
+extern CidPool cidPool;
+
+bool AddressPool::blockAddress(long sn, int addr) {
+    if (!assignedAddrs.contains(sn) && !assignedAddrs.values().contains(addr)) {
+        assignedAddrs.insert(sn, addr);
+        holes.remove(addr);
+    }
+    return false;
+}
+
+int AddressPool::getFreeAddress(long sn) {
+//     return 60;  // DOCASNE
+    if (assignedAddrs.size() == MAX_ADDR) return 0;
+    int retval;
+    if (holes.size() == 0) {
+        retval = assignedAddrs.size() + 1;
+    } else {
+        QMutableSetIterator<int> it(holes);
+        it.next();
+        retval = it.value();
+        it.remove();
+    }
+    assignedAddrs.insert(sn, retval);
+    return retval;
+}
+
+void AddressPool::freeAddress(long sn) {
+//     return;     // DOCASNE
+    if (assignedAddrs.contains(sn)) {
+        int addr = assignedAddrs.value(sn);
+        if (addr != assignedAddrs.size())
+            holes.insert(addr);
+        assignedAddrs.remove(sn);
+    }
+}
+AddressPool addressPool;
+
+
+void ULDYServer::sendNewAddress(int addr, long sn) const {
+    int ret;
+    QByteArray buf_out;
+    ul_fd_t ul_fd = ul_open(UL_DEV_NAME, NULL);
+    if (ul_fd == UL_FD_INVALID) {
+        logToFile("[EE] ULDYSRV - chyba pri zasilani adresy: neplatny deskriptor...");
+        return;
+    }
+    buf_out.append(ULNCS_SET_ADDR);    /* SN0 SN1 SN2 SN3 NEW_ADR */
+    buf_out += sn2buf(sn);
+    buf_out.append(addr);
+    ret = ul_send_command(ul_fd, 0, UL_CMD_NCS, UL_BFL_NORE, (uchar*)buf_out.constData(), buf_out.size()); //UL_BFL_ARQ
+//     logToFile(QString("[II] odeslana zprava, status: %1, len: %2 data %3").arg(ret).arg(buf_out.size()).arg(buf_out.toHex().constData()));
+    ul_close(ul_fd);
+}
+
+void ULDYServer::requestIdentification(int addr) const {
+    int ret;
+    QByteArray buf_out;
+    ul_fd_t ul_fd = ul_open(UL_DEV_NAME, NULL);
+    if (ul_fd == UL_FD_INVALID) {
+        logToFile("[EE] ULDYSRV - chyba pri dotazu na identifikaci: neplatny deskriptor...");
+        return;
+    }
+    buf_out.append(ULNCS_SID_RQ);
+    ret = ul_send_command(ul_fd, addr, UL_CMD_NCS, UL_BFL_NORE, (uchar*)buf_out.constData(), buf_out.size()); //UL_BFL_ARQ
+    logToFile(QString("[II] odeslana zadost o identifikaci na adresu %1").arg(addr));
+    ul_close(ul_fd);
+}
+
+void ULDYServer::processPDOMessage(int saddr, int cid, int data) {
+//     logToFile(QString("PDO msg: CID = %1, DATA = %2").arg(cid).arg(data));
+    if (nodes.contains(saddr)) {
+        Node &node = nodes.getNodeRef(saddr);
+        if (cid == HEARTBEAT_CID) {
+            
+            logToFile(QString("[II] - HEARTBEAT from address %1").arg(saddr));
+            node.refreshLastUpdate();
+
+        } else {
+
+            try {
+                NodeVar tmpVar = node.hasCid(cid);
+                float fdata = ((float)data) / pow(10.0, (double)tmpVar.getDecimalPlaces());
+                valueCache.insertValue(node.getSN(), tmpVar.getId(), fdata);
+            } catch (NodeVarError) { }
+            node.refreshLastUpdate();
+
+        }
+    } else if (saddr != NOT_ASSIGNED_ADDR) {
+
+        requestIdentification(saddr);
+
+    }
+//     logToFile(QString("PDO zpracovana %1").arg((unsigned long)QThread::currentThreadId()));
+}
+
+void ULDYServer::stopServer(void) {
+    logToFile("[II] ULDYSRV - stopping uldy server...");
+    this->running = false;
+}
+
+void ULDYServer::run() {
+    int ret;
+    int addr, saddr, msg_len;
+    long sn;
+    QByteArray buf_in;
+    ul_msginfo msginfo;
+    
+    QTime timer;
+    timer.start();
+#ifdef TEST_RUN
+    Node *newNode = new Node(30, 102);
+    this->nodes.insert(30, newNode);
+
+    while (this->running) {
+        sleep(5);
+        int data = getRandom();
+        int cid = 16;
+        processPDOMessage(30, cid, data);
+    }
+#else
+    ul_fd_t ul_fd = ul_open(UL_DEV_NAME, NULL);
+    if (ul_fd == UL_FD_INVALID) {
+        logToFile("[EE] ULDYSRV - neplatny deskriptor");
+        return;
+    }
+
+    memset(&msginfo, 0, sizeof(ul_msginfo));
+    ul_addfilt(ul_fd, &msginfo);
+
+    logToFile("[II] ULDYSRV - cekam na zpravu...");
+
+    while (this->running) {     // main loop
+
+        while ((ul_fd_wait(ul_fd, 1) <= 0) && this->running) ;
+
+        if ((ul_inepoll(ul_fd) > 0) && (ul_acceptmsg(ul_fd, &msginfo)) >= 0) {
+            if (msginfo.cmd == UL_CMD_NCS) {
+                msg_len = msginfo.len;
+                saddr = msginfo.sadr;
+                buf_in.resize(msg_len);
+                ret = ul_read(ul_fd, buf_in.data(), msg_len);        // nacteni SN do bufferu
+//                 logToFile(QString("[II] prijata zprava, sadr: %1, dadr: %2, len: %3 data %4").arg(msginfo.sadr).arg(msginfo.dadr).arg(msginfo.len).arg(buf_in.toHex().constData()));
+                ul_freemsg(ul_fd);
+                switch ((uchar)buf_in[0]) {
+                    case ULNCS_ADR_RQ:
+                        sn = buf2sn(buf_in);
+                        if (sn == -1) {
+                            logToFile(QString("[WW] ULDYSRV - neplatna zadost o adresu, ocekavam delku minimalne 5").arg(msg_len));
+                            break;
+                        }
+//                         logToFile(QString("[II] prijmam zadost o adresu, SN %1").arg(sn));
+                        if ((addr = addressPool.getFreeAddress(sn)) != 0) {
+                            logToFile(QString("[II] ULDYSRV - sending new address \"%1\" to SN \"%2\"...").arg(addr).arg(sn));
+                            if (!(this->nodes.contains(addr))) {
+                                sendNewAddress(addr, sn);
+                                Node *newNode = new Node(addr, sn);
+                                this->nodes.insert(addr, newNode);
+                                logToFile(QString("[II] mapa nodu nyni obsahuje %1 polozek...").arg(this->nodes.size()));
+                            } else { logToFile("nod uz tam je"); }
+                        } else {
+                            logToFile("[WW] ULDYSRV - address pool is full, try again later, please...");
+                        }
+                        break;
+                    case ULNCS_SID_RPLY:
+                        sn = buf2sn(buf_in);
+                        logToFile(QString("[II] - received identification from unknown node, addr %1").arg(saddr));
+                        if (!(this->nodes.contains(saddr))) {
+                            Node *newNode = new Node(saddr, sn);
+                            addressPool.blockAddress(sn, saddr);
+                            this->nodes.insert(saddr, newNode);
+                            logToFile(QString("[II] mapa nodu nyni obsahuje %1 polozek...").arg(this->nodes.size()));
+                        } else { logToFile("nod uz tam je"); }
+                        break;
+
+                    default:
+                        break;
+                } /* switch */
+
+            } else if (msginfo.cmd == UL_CMD_PDO) {
+                msg_len = msginfo.len;
+                saddr = msginfo.sadr;
+                buf_in.resize(msg_len);
+                ret = ul_read(ul_fd, buf_in.data(), msg_len);
+                ul_freemsg(ul_fd);
+                
+                buf_in = buf_in.mid(PDO_SKIP_BYTES);
+
+                while (1) {
+                    bool success = true;
+
+                    int cid = takeCid(buf_in, &success);
+                    if (!success) break;
+
+                    int len = takeLen(buf_in, &success);
+                    if (!success) break;
+
+                    int data = takeData(buf_in, len, &success);
+                    if (!success) break;
+
+                    processPDOMessage(saddr, cid, data);
+                }
+            } else
+                ul_freemsg(ul_fd);
+
+        } /* ul_inepool && ul_acceptmsg */
+
+    } /* while(running) */
+#endif
+}
+
+int ULDYServer::takeCid(QByteArray &buf, bool *success) const {
+    if (buf.size() < 2) { *success = false; /*logToFile("nedostatecna delka CID");*/ return 0; }
+    int ret = buf2uint16(buf);
+    buf = buf.mid(2);
+    *success = true;
+    return ret;
+}
+
+int ULDYServer::takeLen(QByteArray &buf, bool *success) const {
+//     return takeCid(buf, success);
+    if (buf.size() < 2) { *success = false; /*logToFile("nedostatecna delka LEN");*/ return 0; }
+//     int ret = buf[0];
+    int ret = buf2uint16(buf);
+    buf = buf.mid(2);
+    *success = true;
+    return ret;
+}
+
+int ULDYServer::takeData(QByteArray &buf, int len, bool *success) const {
+    if (buf.size() < len) { *success = false; return 0; }
+    int ret = 0;
+    for (int i = 0; i < len; i++) {
+        ret += (uchar)buf[i]<<(i * 8);
+    }
+    buf = buf.mid(len);
+    *success = true;
+    return ret;
+}
+
+const NodeMap &ULDYServer::getNodes() const {
+    return this->nodes;
+}
+
+NodeMap &ULDYServer::getNodesRef() {
+    return this->nodes;
+}
+
+ValueCache &ULDYServer::getValueCacheRef() {
+    return this->valueCache;
+}
+
+void ULDYServer::tryRemoveNodes() {
+    NodeMapMutableIterator it(this->nodes);
+    QDateTime curr, last;
+    while (it.hasNext()) {
+        it.next();
+        int addr = it.key();
+        curr = currentDateTime();
+        last = this->nodes.getNodeRef(addr).getLastUpdate();
+        last.setTimeSpec(Qt::UTC);
+        if ((curr.toTime_t() - last.toTime_t()) > NODE_CLEANER_PERIOD_SECS) {
+            logToFile(QString("[II] - Removing node SN %1...").arg(this->nodes.getNodeRef(addr).getSN()));
+            addressPool.freeAddress(this->nodes.getNodeRef(addr).getSN());
+            cidPool.freeCids(this->nodes.getNodeRef(addr).getUsedCidsRef());
+            Node *tmpNode = this->nodes.value(addr);
+            this->nodes.remove(addr);
+            delete tmpNode;
+        }
+    }
+}
+