cntronbase.cpp
Go to the documentation of this file.
00001 
00032 #include "nanotron_swarm/cntronbase.h"
00033 
00034 #include <unistd.h>
00035 #include <fcntl.h>
00036 #include <stdio.h>
00037 #include <iostream>
00038 #include <sstream>
00039 #include <string.h>
00040 #include <vector>
00041 
00042 CNTronBase::CNTronBase(int baseId) {
00043         m_portHandler = 0;
00044         m_baseId = baseId;
00045 }
00046 
00047 CNTronBase::~CNTronBase(void) {
00048         finish();
00049 }
00050 
00051 int CNTronBase::getBaseId(void) const {
00052         return m_baseId;
00053 }
00054 
00055 unsigned int CNTronBase::numBeacons() const {
00056         return m_nodes.size();
00057 }
00058 
00059 void CNTronBase::printBeacons() const {
00060         int nodeID;
00061         int penalization, failures;
00062         std::map<int, CNTronNode>::const_iterator it;
00063 
00064         std::cout << "\n[DEBUG] Detected Beacons (N = " << m_nodes.size() << "):"
00065                         << std::endl;
00066         for (unsigned int i = 0; i < m_nodes.size(); i++) {
00067 
00068                 nodeID = m_nodeIDs[i];
00069                 //std::cout << "[DEBUG] Node " << nodeID << std::endl;
00070                 penalization = m_nodes.at(nodeID).penalization;
00071                 failures = m_nodes.at(nodeID).failures;
00072 
00073                 std::cout << "[DEBUG] Node " << nodeID << " - Penalization: "
00074                                 << penalization << " - Failures: " << failures << std::endl;
00075         }
00076 }
00077 
00078 // Initialize the serial port to the given values
00079 int CNTronBase::init(const char *pDev) {
00080         struct termios my_termios;
00081 
00082         // Make sure port is closed 
00083         if (m_portHandler > 0)
00084                 close(m_portHandler);
00085 
00086         // Open the port in read-write mode 
00087         m_portHandler = open(pDev, O_RDWR | O_NOCTTY);
00088         if (m_portHandler < 0)
00089                 return -5;
00090 
00091         /* Get the port attributes and flush all data on queues*/
00092         tcgetattr(m_portHandler, &my_termios);
00093         tcflush(m_portHandler, TCIOFLUSH);
00094 
00095         /* Setup the communication */
00096         my_termios.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON
00097                         | INLCR | IGNCR | ICRNL);
00098         my_termios.c_iflag |= IGNBRK | IXOFF;
00099         my_termios.c_oflag &= ~(OPOST);
00100         my_termios.c_cflag |= CLOCAL | CREAD;
00101         my_termios.c_cflag &= ~PARENB;
00102         my_termios.c_cflag |= CS8;
00103         my_termios.c_cflag &= ~CSTOPB;
00104         my_termios.c_cflag &= ~CRTSCTS;
00105         my_termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | NOFLSH
00106                         | TOSTOP | ISIG | IEXTEN);
00107         my_termios.c_cc[VMIN] = 1; //Each simple read call will be blocked until receive at least one byte
00108 
00109         //VTIME = Timeout. Is a character count ranging from 0 to 255 characters.
00110         //It is time measured in 0.1 second intervals, (0 to 25.5 seconds).
00111         //More information in http://www.unixwiz.net/techtips/termios-vmin-vtime.html
00112 
00113         my_termios.c_cc[VTIME] = 2.5;   //0 = No timeout for reading
00114         cfsetispeed(&my_termios, B115200);
00115         cfsetospeed(&my_termios, B115200);
00116         tcsetattr(m_portHandler, TCSANOW, &my_termios);
00117 
00118         /* Read base node ID */
00119         if (m_baseId == DEFAULT_ID)
00120                 return readBaseID();
00121 
00122         /* Return 0 if no errors occurred */
00123         return 0;
00124 }
00125 
00126 // Close serial communication
00127 void CNTronBase::finish(void) {
00128         /* Close the port */
00129         if (m_portHandler > 0) {
00130                 close(m_portHandler);
00131                 m_portHandler = 0;
00132         }
00133 }
00134 
00135 // Método que lee el ID de la base.
00136 int CNTronBase::readBaseID() {
00137         std::string cmd = READNODEID;
00138         int result, size;
00139         char c;
00140 
00141         //Transformamos el objeto string 'cmd' en una cadena de caracteres char. 
00142         result = sendCommand(cmd.c_str(), cmd.size());
00143         if (result < 0)
00144                 return -1;
00145 
00146         //      std::cout << "[DEBUG] Reading base MAC ..." << std::endl;
00147 
00148         // Read result
00149         c = 0;
00150         size = 0;
00151         while (c != '\n') {
00152                 result = read(m_portHandler, &c, 1);
00153                 if (result < 0) {
00154                         usleep(10000);
00155                         return -5;
00156                 }
00157 
00158                 if (result == 1) {
00159                         m_readBuff[size++] = c;
00160                 }
00161         }
00162         m_readBuff[size] = '\0';
00163 
00164         //std::cout << "[DEBUG] Base MAC: " << m_readBuff;
00165 
00166         //Nos quedamos con los primeros 2 bytes de la dirección MAC.
00167         //En este punto limitamos el rango de valor de ID a 0-255.
00168 
00169         char dirMAC[12];
00170         strncpy(dirMAC,m_readBuff,12);
00171 
00172         m_baseId=chartohex(dirMAC);
00173 
00174         return 0;
00175         /* Posibles valores de return:
00176          return= -1; Error al enviar el comando.           [ SendCommand() devuelve -6 ].
00177          return= -5; Error al encontrarse el buffer vacío. [ read() devuelve 0 ].
00178          return= 0; Lectura del ID de la base realizada con éxito.
00179          */
00180 }
00181 
00182 // Send a new data stream to the serial port
00183 int CNTronBase::sendCommand(const char* command, int size) {
00184         int i = 1;
00185         int dataWritten;
00186 
00187         for (i = 0; i < size; i++) {
00188                 dataWritten = write(m_portHandler, command + i, 1);
00189                 if (dataWritten < 0)
00190                         return -6;
00191         }
00192         return 0;
00193 }
00194 
00195 // Sends a range command and reads the result which is returned to user
00196 int CNTronBase::readRange(unsigned int node, CNTronRange& pData,
00197                 std::string& msg) {
00198 
00199         int result, size, err_code, returnCode;
00200         float range;
00201         char c;
00202         int nodeID;
00203         std::map<int, CNTronNode>::iterator it;
00204         CNTronNode nodeInf;
00205 
00206         if (node < m_nodes.size()) {
00207                 nodeID = m_nodeIDs[node];
00208                 nodeInf = m_nodes[nodeID];
00209         } else {
00210                 msg = "Node not detected";
00211                 return -1;
00212         }
00213 
00214         if (checkPenalization(nodeInf) != 0) {
00215                 return 0;
00216         }
00217 
00218         // Send range request
00219         //std::cout<<"[DEBUG] RANGING: Tx "<< nodeInf.mac << std::endl;
00220         std::string cmd = RANGETO(nodeInf.mac);
00221         sendCommand(cmd.c_str(), cmd.length());
00222 
00223         // Read result
00224         c = 0;
00225         size = 0;
00226         while (c != '\n') {
00227                 result = read(m_portHandler, &c, 1);
00228                 if (result < 0) {
00229                         usleep(10000);
00230                         return -5;
00231                 }
00232 
00233                 if (result == 1) {
00234                         m_readBuff[size++] = c;
00235                 }
00236         }
00237         m_readBuff[size] = '\0';
00238         sscanf(m_readBuff, "%d, %f, %*d", &err_code, &range);
00239 
00240         returnCode = 0;
00241         /*CODIGOS DE ERROR QUE PODEMOS RECIBIR:
00242          Errorcode = 0: Indica el estado de la operación de ranging.
00243          Errorcode = 1: success ranging result valid
00244          Errorcode = 2: ranging to own ID
00245          Errorcode = 3: ID out of range, no ACK
00246          Errorcode = 4: ranging unsuccessful, ACK OK, then timeout
00247          */
00248         std::stringstream ss;
00249         switch (err_code) {
00250         case 0: // Success
00251 
00252                 nodeInf.failures = 0;
00253                 pData.beaconId = nodeInf.id;
00254 
00255                 // sscanf(m_beacons.at(m_lastBeacon).c_str(), "%*2x%2x%*2x%*2x%*2x%*2x",pData.beaconId);
00256                 pData.emitterId = m_baseId;
00257                 pData.range = range;
00258 
00259                 if (range < 0) {
00260                         msg = "[WARNING] Negative range received";
00261                 } else {
00262                         returnCode = 1;
00263                 }
00264 
00265                 break;
00266         case 2: // Ranging to own ID. ID out of range, no ACK
00267                 // msg = "[WARNING] " + m_beacons.at(m_lastBeacon) + " is de BASE ID. Invalid ID to range (NO_ACK).";
00268                 //m_b_noack[m_lastBeacon]= m_b_noack[m_lastBeacon]+1;
00269 
00270                 //break;
00271         case 3: // ID out of range, no ACK 
00272                 nodeInf.failures++;
00273 
00274                 //ss << "[WARNING] " << nodeInf.id << " is out of range (NO_ACK).";
00275                 //msg = ss.str();
00276 
00277                 break;
00278         case 4: // Only one ranging operation successful in diversity mode
00279                 msg = "[WARNING] Timeout while ranging with " + nodeInf.id;
00280                 break;
00281         default:
00282                 // Do nothing
00283                 break;
00284         }
00285 
00286         if (nodeInf.failures >= MAX_NO_ACK) {
00287                 nodeInf.penalization = PENALIZACION;
00288                 if (clock_gettime(CLOCK_MONOTONIC_RAW, &nodeInf.penalizationTime)
00289                                 == -1) {
00290                         nodeInf.penalizationTime.tv_sec = 0;
00291                         nodeInf.penalizationTime.tv_nsec = 0;
00292                 }
00293         }
00294 
00295         m_nodes[nodeID] = nodeInf;
00296 
00297         return returnCode;
00298 }
00299 
00300 int CNTronBase::checkPenalization(CNTronNode& nodeInf) {
00301         timespec now;
00302         long delay = -1;
00303 
00304         if (nodeInf.penalization > 0) { 
00305                 if (clock_gettime(CLOCK_MONOTONIC_RAW, &now) != -1) {
00306                         delay = now.tv_sec
00307                                         - nodeInf.penalizationTime.tv_sec;
00308                 }
00309 
00310                 if (delay > 0 && delay > MAX_PENALIZATION_TIME) {
00311                         nodeInf.penalization = 0;
00312                         nodeInf.failures = 0;
00313                 }
00314         }
00315 
00316         return nodeInf.penalization;
00317 }
00318 
00319 // Updates the list of available beacons
00320 int CNTronBase::detectBeacons() {
00321         int result, size, lines, line = 0, age;
00322         char c;
00323         std::string cmd = GETBEACONS(255);
00324         char id[12]; // MAC of a beacon (contains the ID of the beacon).
00325         CNTronNode node;
00326 
00327         result = sendCommand(cmd.c_str(), cmd.size());
00328         if (result < 0)
00329                 return -1;
00330 
00331         // Find the beginning of the stream
00332         c = 0;
00333         while (c != '#') {
00334                 result = read(m_portHandler, &c, 1);
00335                 if (result < 0) {
00336                         usleep(10000);
00337                         return -5;
00338                 }
00339         }
00340 
00341         // Read first line (number of remaining lines)
00342         c = 0;
00343         size = 0;
00344         while (c != '\n') {
00345                 result = read(m_portHandler, &c, 1);
00346                 if (result < 0) {
00347                         usleep(10000);
00348                         return -5;
00349                 }
00350                 if (result == 1) {
00351                         m_readBuff[size++] = c;
00352                 }
00353         }
00354         m_readBuff[size] = '\0';
00355         sscanf(m_readBuff, "%d", &lines);
00356 
00357         // Read list of nodes detected
00358         for (line = 1; line <= lines; line++) {
00359                 // Read new line
00360                 c = 0;
00361                 size = 0;
00362                 while (c != '\n') {
00363                         result = read(m_portHandler, &c, 1);
00364                         if (result < 0) {
00365                                 usleep(10000);
00366                                 return -5;
00367                         }
00368 
00369                         if (result == 1) {
00370                                 m_readBuff[size++] = c;
00371                         }
00372                 }
00373 
00374                 // IDs start at line 3
00375                 if (line >= 3) {
00376                         m_readBuff[size] = '\0';
00377 
00378                         sscanf(m_readBuff, "%d:%s", &age, id);
00379 
00380                         if (age <= MAX_AGE) {
00381 
00382                                 int nodeID = chartohex(id);
00383                                 if (m_nodes.count(nodeID) == 0) { // Add a new beacon
00384                                         node.failures = 0;
00385                                         node.penalization = 0;
00386                                         node.id = nodeID;
00387 
00388                                         strncpy(node.mac, id, 12);
00389                                         node.mac[12] = '\0';
00390 
00391                                         m_nodes[nodeID] = node;
00392                                         m_nodeIDs.push_back(nodeID);
00393                                 } else { // Check penalization
00394                                         if (checkPenalization(m_nodes[nodeID]) > 0) {
00395                                                 m_nodes[nodeID].penalization--;
00396                                         }
00397                                 }
00398                         }
00399                 }
00400         }
00401 
00402 #if DEBUG
00403         printBeacons();
00404 #endif
00405 
00406         return 0;
00407 }
00408 
00409 int CNTronBase::chartohex(char * cnum) {
00410         int result = 0;
00411         int num[2];
00412         int i;
00413 
00414         i = 10; // Penultimate part of MAC address
00415         if ((cnum[i] >= 'A') && (cnum[i] <= 'F'))
00416                 num[1] = (cnum[i] - 'A') + 10;
00417         else
00418                 num[1] = (cnum[i] - '0');
00419 
00420         i = 11; // Last part of MAC address
00421         if ((cnum[i] >= 'A') && (cnum[i] <= 'F'))
00422                 num[0] = (cnum[i] - 'A') + 10;
00423         else
00424                 num[0] = (cnum[i] - '0');
00425 
00426         result = num[1] * 16 + num[0];
00427 
00428         return result;
00429 }


nanotron_swarm
Author(s): Felipe Ramón Fabresse, Alfredo Vázquez Reyes, Fernando Caballero Benitez
autogenerated on Sat Jun 8 2019 20:36:48