]> rtime.felk.cvut.cz Git - hydro.git/blob - 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
1 #include "uldy_server.h"
2
3 using namespace std;
4
5 extern CidPool cidPool;
6
7 bool AddressPool::blockAddress(long sn, int addr) {
8     if (!assignedAddrs.contains(sn) && !assignedAddrs.values().contains(addr)) {
9         assignedAddrs.insert(sn, addr);
10         holes.remove(addr);
11     }
12     return false;
13 }
14
15 int AddressPool::getFreeAddress(long sn) {
16 //     return 60;  // DOCASNE
17     if (assignedAddrs.size() == MAX_ADDR) return 0;
18     int retval;
19     if (holes.size() == 0) {
20         retval = assignedAddrs.size() + 1;
21     } else {
22         QMutableSetIterator<int> it(holes);
23         it.next();
24         retval = it.value();
25         it.remove();
26     }
27     assignedAddrs.insert(sn, retval);
28     return retval;
29 }
30
31 void AddressPool::freeAddress(long sn) {
32 //     return;     // DOCASNE
33     if (assignedAddrs.contains(sn)) {
34         int addr = assignedAddrs.value(sn);
35         if (addr != assignedAddrs.size())
36             holes.insert(addr);
37         assignedAddrs.remove(sn);
38     }
39 }
40 AddressPool addressPool;
41
42
43 void ULDYServer::sendNewAddress(int addr, long sn) const {
44     int ret;
45     QByteArray buf_out;
46     ul_fd_t ul_fd = ul_open(UL_DEV_NAME, NULL);
47     if (ul_fd == UL_FD_INVALID) {
48         logToFile("[EE] ULDYSRV - chyba pri zasilani adresy: neplatny deskriptor...");
49         return;
50     }
51     buf_out.append(ULNCS_SET_ADDR);    /* SN0 SN1 SN2 SN3 NEW_ADR */
52     buf_out += sn2buf(sn);
53     buf_out.append(addr);
54     ret = ul_send_command(ul_fd, 0, UL_CMD_NCS, UL_BFL_NORE, (uchar*)buf_out.constData(), buf_out.size()); //UL_BFL_ARQ
55 //     logToFile(QString("[II] odeslana zprava, status: %1, len: %2 data %3").arg(ret).arg(buf_out.size()).arg(buf_out.toHex().constData()));
56     ul_close(ul_fd);
57 }
58
59 void ULDYServer::requestIdentification(int addr) const {
60     int ret;
61     QByteArray buf_out;
62     ul_fd_t ul_fd = ul_open(UL_DEV_NAME, NULL);
63     if (ul_fd == UL_FD_INVALID) {
64         logToFile("[EE] ULDYSRV - chyba pri dotazu na identifikaci: neplatny deskriptor...");
65         return;
66     }
67     buf_out.append(ULNCS_SID_RQ);
68     ret = ul_send_command(ul_fd, addr, UL_CMD_NCS, UL_BFL_NORE, (uchar*)buf_out.constData(), buf_out.size()); //UL_BFL_ARQ
69     logToFile(QString("[II] odeslana zadost o identifikaci na adresu %1").arg(addr));
70     ul_close(ul_fd);
71 }
72
73 void ULDYServer::processPDOMessage(int saddr, int cid, int data) {
74 //     logToFile(QString("PDO msg: CID = %1, DATA = %2").arg(cid).arg(data));
75     if (nodes.contains(saddr)) {
76         Node &node = nodes.getNodeRef(saddr);
77         if (cid == HEARTBEAT_CID) {
78             
79             logToFile(QString("[II] - HEARTBEAT from address %1").arg(saddr));
80             node.refreshLastUpdate();
81
82         } else {
83
84             try {
85                 NodeVar tmpVar = node.hasCid(cid);
86                 float fdata = ((float)data) / pow(10.0, (double)tmpVar.getDecimalPlaces());
87                 valueCache.insertValue(node.getSN(), tmpVar.getId(), fdata);
88             } catch (NodeVarError) { }
89             node.refreshLastUpdate();
90
91         }
92     } else if (saddr != NOT_ASSIGNED_ADDR) {
93
94         requestIdentification(saddr);
95
96     }
97 //     logToFile(QString("PDO zpracovana %1").arg((unsigned long)QThread::currentThreadId()));
98 }
99
100 void ULDYServer::stopServer(void) {
101     logToFile("[II] ULDYSRV - stopping uldy server...");
102     this->running = false;
103 }
104
105 void ULDYServer::run() {
106     int ret;
107     int addr, saddr, msg_len;
108     long sn;
109     QByteArray buf_in;
110     ul_msginfo msginfo;
111     
112     QTime timer;
113     timer.start();
114 #ifdef TEST_RUN
115     Node *newNode = new Node(30, 102);
116     this->nodes.insert(30, newNode);
117
118     while (this->running) {
119         sleep(5);
120         int data = getRandom();
121         int cid = 16;
122         processPDOMessage(30, cid, data);
123     }
124 #else
125     ul_fd_t ul_fd = ul_open(UL_DEV_NAME, NULL);
126     if (ul_fd == UL_FD_INVALID) {
127         logToFile("[EE] ULDYSRV - neplatny deskriptor");
128         return;
129     }
130
131     memset(&msginfo, 0, sizeof(ul_msginfo));
132     ul_addfilt(ul_fd, &msginfo);
133
134     logToFile("[II] ULDYSRV - cekam na zpravu...");
135
136     while (this->running) {     // main loop
137
138         while ((ul_fd_wait(ul_fd, 1) <= 0) && this->running) ;
139
140         if ((ul_inepoll(ul_fd) > 0) && (ul_acceptmsg(ul_fd, &msginfo)) >= 0) {
141             if (msginfo.cmd == UL_CMD_NCS) {
142                 msg_len = msginfo.len;
143                 saddr = msginfo.sadr;
144                 buf_in.resize(msg_len);
145                 ret = ul_read(ul_fd, buf_in.data(), msg_len);        // nacteni SN do bufferu
146 //                 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()));
147                 ul_freemsg(ul_fd);
148                 switch ((uchar)buf_in[0]) {
149                     case ULNCS_ADR_RQ:
150                         sn = buf2sn(buf_in);
151                         if (sn == -1) {
152                             logToFile(QString("[WW] ULDYSRV - neplatna zadost o adresu, ocekavam delku minimalne 5").arg(msg_len));
153                             break;
154                         }
155 //                         logToFile(QString("[II] prijmam zadost o adresu, SN %1").arg(sn));
156                         if ((addr = addressPool.getFreeAddress(sn)) != 0) {
157                             logToFile(QString("[II] ULDYSRV - sending new address \"%1\" to SN \"%2\"...").arg(addr).arg(sn));
158                             if (!(this->nodes.contains(addr))) {
159                                 sendNewAddress(addr, sn);
160                                 Node *newNode = new Node(addr, sn);
161                                 this->nodes.insert(addr, newNode);
162                                 logToFile(QString("[II] mapa nodu nyni obsahuje %1 polozek...").arg(this->nodes.size()));
163                             } else { logToFile("nod uz tam je"); }
164                         } else {
165                             logToFile("[WW] ULDYSRV - address pool is full, try again later, please...");
166                         }
167                         break;
168                     case ULNCS_SID_RPLY:
169                         sn = buf2sn(buf_in);
170                         logToFile(QString("[II] - received identification from unknown node, addr %1").arg(saddr));
171                         if (!(this->nodes.contains(saddr))) {
172                             Node *newNode = new Node(saddr, sn);
173                             addressPool.blockAddress(sn, saddr);
174                             this->nodes.insert(saddr, newNode);
175                             logToFile(QString("[II] mapa nodu nyni obsahuje %1 polozek...").arg(this->nodes.size()));
176                         } else { logToFile("nod uz tam je"); }
177                         break;
178
179                     default:
180                         break;
181                 } /* switch */
182
183             } else if (msginfo.cmd == UL_CMD_PDO) {
184                 msg_len = msginfo.len;
185                 saddr = msginfo.sadr;
186                 buf_in.resize(msg_len);
187                 ret = ul_read(ul_fd, buf_in.data(), msg_len);
188                 ul_freemsg(ul_fd);
189                 
190                 buf_in = buf_in.mid(PDO_SKIP_BYTES);
191
192                 while (1) {
193                     bool success = true;
194
195                     int cid = takeCid(buf_in, &success);
196                     if (!success) break;
197
198                     int len = takeLen(buf_in, &success);
199                     if (!success) break;
200
201                     int data = takeData(buf_in, len, &success);
202                     if (!success) break;
203
204                     processPDOMessage(saddr, cid, data);
205                 }
206             } else
207                 ul_freemsg(ul_fd);
208
209         } /* ul_inepool && ul_acceptmsg */
210
211     } /* while(running) */
212 #endif
213 }
214
215 int ULDYServer::takeCid(QByteArray &buf, bool *success) const {
216     if (buf.size() < 2) { *success = false; /*logToFile("nedostatecna delka CID");*/ return 0; }
217     int ret = buf2uint16(buf);
218     buf = buf.mid(2);
219     *success = true;
220     return ret;
221 }
222
223 int ULDYServer::takeLen(QByteArray &buf, bool *success) const {
224 //     return takeCid(buf, success);
225     if (buf.size() < 2) { *success = false; /*logToFile("nedostatecna delka LEN");*/ return 0; }
226 //     int ret = buf[0];
227     int ret = buf2uint16(buf);
228     buf = buf.mid(2);
229     *success = true;
230     return ret;
231 }
232
233 int ULDYServer::takeData(QByteArray &buf, int len, bool *success) const {
234     if (buf.size() < len) { *success = false; return 0; }
235     int ret = 0;
236     for (int i = 0; i < len; i++) {
237         ret += (uchar)buf[i]<<(i * 8);
238     }
239     buf = buf.mid(len);
240     *success = true;
241     return ret;
242 }
243
244 const NodeMap &ULDYServer::getNodes() const {
245     return this->nodes;
246 }
247
248 NodeMap &ULDYServer::getNodesRef() {
249     return this->nodes;
250 }
251
252 ValueCache &ULDYServer::getValueCacheRef() {
253     return this->valueCache;
254 }
255
256 void ULDYServer::tryRemoveNodes() {
257     NodeMapMutableIterator it(this->nodes);
258     QDateTime curr, last;
259     while (it.hasNext()) {
260         it.next();
261         int addr = it.key();
262         curr = currentDateTime();
263         last = this->nodes.getNodeRef(addr).getLastUpdate();
264         last.setTimeSpec(Qt::UTC);
265         if ((curr.toTime_t() - last.toTime_t()) > NODE_CLEANER_PERIOD_SECS) {
266             logToFile(QString("[II] - Removing node SN %1...").arg(this->nodes.getNodeRef(addr).getSN()));
267             addressPool.freeAddress(this->nodes.getNodeRef(addr).getSN());
268             cidPool.freeCids(this->nodes.getNodeRef(addr).getUsedCidsRef());
269             Node *tmpNode = this->nodes.value(addr);
270             this->nodes.remove(addr);
271             delete tmpNode;
272         }
273     }
274 }
275