Namespaces
Variants
Views
Actions

std::vector<T,Allocator>::back

From cppreference.com
< cpp‎ | container‎ | vector
Revision as of 06:41, 4 December 2020 by 193.145.124.20 (Talk)

 
 
 
 
reference back();
(1) (constexpr since C++20)
const_reference back() const;
(2) (constexpr since C++20)

Returns a reference to the last element in the container.

Calling back on an empty container causes undefined behavior.

Contents

Parameters

(none)

Return value

Reference to the last element.

Complexity

Constant.

Notes

For a non-empty container c, the expression c.back() is equivalent to *std::prev(c.end()).

Example

#include <cassert>
#include <vector>
 
int main()
{
    std::vector<char> letters{'a', 'b', 'c', 'd'};
    assert(letters.back() == 'd');
}

See also

access the first element
(public member function) [edit]
returns a reverse iterator to the beginning
(public member function) [edit]
(C++11)
returns an iterator to the end
(public member function) [edit]
  1. ifdef __unix__
  1. include <sys/types.h>
  2. include <unistd.h> // getuid, getgid, getpid, getppid
  3. include <sys/times.h>
  1. elif defined(_WIN64) || defined(WIN64)
  1. define OS_Windows
  1. endif
  1. define INICIO_AI (30100)
  2. define FIN_AI (30119)
  3. define DESPLAZA_AI (INICIO_AI - 30001)
  1. include <iostream>
  2. include <ctime>
  3. include "ModbusRTU.hpp"

ModbusRTU::ModbusRTU(uint8_t id) : _id(id), _DO(20), _AO(10), _DI(20),

                                  _AI(FIN_AI - INICIO_AI + 1) {
 // Las primeros 20 salidas digitales con un valor inicial de 0 en las
 // posiciones pares y de 1 las posiciones impares.
 for (std::size_t i = 0; i < _DO.size(); i += 2) {
   _DO.at(i) = true;
 }
 // Los primeros 10 registros analógicos de salida, con un valor
 // inicial de 0, 4, 8, 12, ....
 for (std::size_t i = 0; i < _AO.size(); ++i) {
   _AO.at(i) = i * 4;
 }
 // inicialmente a 0 los pares y a 1111 los impares.
 for (std::size_t i = 0; i < _AI.size(); i += 2) {
   _AI.at(i) = 1111;
 }
 std::cerr << "Se ha creado un ModbusRTU con ID: " << (int)_id
           << std::endl;
 muestraRegistro<uint16_t>(_AO, "[AO]: ");
 muestraRegistro<bool>(_DO, "[DO]: ");
 muestraRegistro<uint16_t>(_AI, "[AI]: ");
 muestraRegistro<bool>(_DI, "[DI]: ");
 std::cerr << std::endl;

}


bool ModbusRTU::esValido(Mensaje& recibido, uint8_t funcion) {

 if (funcion == 1 || funcion == 2 || funcion == 3
     || funcion == 4 || funcion == 5 || funcion == 6) {
   return (recibido.size() == 8);
 } else if (funcion == 15 || funcion == 16) {
   try {
     uint16_t numDatos = recibido.getByteAt(6);
     return (recibido.size() == (uint16_t)9 + numDatos);
   } catch (std::out_of_range& e) {
     std::cerr << "No se ha podido acceder al numero de datos"
               << std::endl;
     return false;
   }
 }
 return true;

}


Mensaje ModbusRTU::peticion(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Recibido mensaje " << recibido << std::endl;
 // Actualizamos los atributos del ModbusRTU
 _petRecibidas++;
 if (recibido.crcOK())
   _byteRecibidos += recibido.size() - 2;
 actualizaAI();
 std::cerr << "Actualizando [AI]" << std::endl;
 muestraRegistro<uint16_t>(_AI, "[AI]: ");
 muestraRegistro<bool>(_DI, "[DI]: ");
 std::cerr << std::endl;
 // Antes de acceder al mensaje
 // Comprobamos que es válido
 uint8_t id = 0;
 uint8_t funcion = 0;
 if (recibido.size() >= 2) {
   // El mensaje tiene al menos un id y una función
   id = recibido.getByteAt(0);
   funcion = recibido.getByteAt(1);
 }
 // Según la función, validamos el mensaje
 if (!esValido(recibido, funcion)) {
   respuesta = generaError(recibido, 0x03);
   _byteEnviados += respuesta.size() - 2; // Excluye el CRC
   return respuesta;
 }
 std::cerr << "El mensaje es para " << (int)id << " y la funcion es "
           << (int)funcion << std::endl;
 if (id != _id || !recibido.crcOK()) {
   std::cerr << "ID invalida o CRC incorrecto." << std::endl;
   std::cerr << "Respuesta: " << respuesta << std::endl;
   return respuesta; // Respuesta vacía, no se actualiza _byteEnviados
 }
 switch (funcion) {
   case 1: // Lectura de salidas digitales
     respuesta = atiende01(recibido);
     break;
   case 2: // Lectura de entradas digitales
     respuesta = atiende02(recibido);
     break;
   case 3: // Lectura de salidas analógicas
     respuesta = atiende03(recibido);
     break;
   case 4: // Lectura de entradas analógicas
     respuesta = atiende04(recibido);
     break;
   case 5: // Fuerza una única salida digital
     respuesta = atiende05(recibido);
     break;
   case 6: // Fuerza una única salida analógica
     respuesta = atiende06(recibido);
     break;
   case 15: // Fuerza múltiples salidas digitales
     respuesta = atiende15(recibido);
     break;
   case 16: // Fuerza múltiples salidas analógicas
     respuesta = atiende16(recibido);
     break;
   default:
     std::cerr << "Funcion no implementada" << std::endl;
     respuesta = generaError(recibido, 0x01);
 }
 std::cerr << std::endl;
 // Se ha enviado un mensaje de respuesta. Se actualiza _byteEnviados
 _byteEnviados += respuesta.size() - 2; // Excluye el CRC
 return respuesta;

}


template <class T, class U> bool ModbusRTU::dentroDeRango(

   const std::vector<T>& registro, U offset, U numPos) const {
 return (offset >= 0) && (offset < registro.size())
        && ((offset + numPos) >= offset)
        && ((offset + numPos) <= registro.size());

}


Mensaje ModbusRTU::generaError(Mensaje& recibido, uint8_t errorCode) {

 Mensaje respuesta;
 std::cerr << "Generando mensaje de error " << (int)errorCode
           << std::endl;
 respuesta.pushByte_back(recibido.getByteAt(0)); // Direcc.
 respuesta.pushByte_back(recibido.getByteAt(1) | (1 << 7)); // Funcion
 respuesta.pushByte_back(errorCode);
 respuesta.aniadeCRC();
 std::cerr << "Mensaje de error: " << respuesta << std::endl;
 return respuesta;

}


Mensaje ModbusRTU::atiende03(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Entramos en metodo atiende03 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 uint16_t numPos = recibido.getWordAt(4);
 if (!dentroDeRango<uint16_t>(_AO, offset, numPos))
   return generaError(recibido, 0x02);
 respuesta.pushByte_back(recibido.getByteAt(0)); // Dirección
 respuesta.pushByte_back(recibido.getByteAt(1)); // Función
 respuesta.pushByte_back(numPos * 2); // Número de bytes
 for (std::size_t i = offset; i < (offset + numPos); ++i) { // Datos
   std::cerr << "Accediendo AO[" << i << "]: " << _AO.at(i)
             << std::endl;
   respuesta.pushWord_back(_AO.at(i));
 }
 respuesta.aniadeCRC(); // CRC
 std::cerr << "Respuesta: " << respuesta << std::endl;
 return respuesta;

}


Mensaje ModbusRTU::atiende01(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Entramos en metodo atiende01 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 uint16_t numPos = recibido.getWordAt(4);
 if (!dentroDeRango<bool>(_DO, offset, numPos))
   return generaError(recibido, 0x02);
 unsigned numBytes = ((numPos - 1) / 8) + 1;
 respuesta.pushByte_back(recibido.getByteAt(0)); // Dirección
 respuesta.pushByte_back(recibido.getByteAt(1)); // Función
 respuesta.pushByte_back(numBytes); // Número de bytes
 unsigned posBit = 0;
 uint8_t dato = 0;
 for (std::size_t i = offset; i < (offset + numPos); ++i) {
   std::cerr << "Accediendo DO[" << i << "]: " << _DO.at(i)
             << std::endl;
   if (_DO.at(i))
     dato |= 1 << posBit;
   ++posBit;
   if (posBit == 8) { // Hemos rellenado un byte
     respuesta.pushByte_back(dato);
     posBit = 0;
     dato = 0;
   }
 }
 if (posBit > 0) { // Queda un byte a medio rellenar
   respuesta.pushByte_back(dato);
 }
 respuesta.aniadeCRC(); // CRC
 std::cerr << "Respuesta: " << respuesta << std::endl;
 return respuesta;

}


Mensaje ModbusRTU::atiende05(Mensaje& recibido) {

 std::cerr << "Entramos en metodo atiende05 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 if (!dentroDeRango<bool>(_DO, offset))
   return generaError(recibido, 0x02);
 if (
     (recibido.getByteAt(4) == 0xFF) &&
     (recibido.getByteAt(5) == 0x00)) {
   _DO.at(offset) = true;
   std::cerr << "Ponemos a 1 la DO[" << offset << "]: "
             << _DO.at(offset) << std::endl;
 } else if (
     (recibido.getByteAt(4) == 0x00) &&
     (recibido.getByteAt(5) == 0x00)) {
   _DO.at(offset) = false;
   std::cerr << "Ponemos a 0 la DO[" << offset << "]: "
             << _DO.at(offset) << std::endl;
 } else {
   // El valor es inválido
   return generaError(recibido, 0x03);
 }
 return recibido;

}


Mensaje ModbusRTU::atiende15(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Entramos en metodo atiende15 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 uint16_t numPos = recibido.getWordAt(4);
 if (!dentroDeRango<bool>(_DO, offset, numPos))
   return generaError(recibido, 0x02);
 unsigned k = 7; // A partir de aquí solo existen datos y el CRC
 uint8_t dato = recibido.getByteAt(k);
 unsigned posBit = 0;
 for (std::size_t i = offset; i < (offset + numPos); ++i) {
   std::cerr << "Accediendo DO[" << i << "]: " << _DO.at(i)
             << std::endl;
   _DO.at(i) = dato & (1 << posBit);
   ++posBit;
   if (posBit == 8) { // Hemos rellenado un byte
     posBit = 0;
     k++; // Pasamos al siguiente dato
     dato = recibido.getByteAt(k);
   }
 }
 respuesta.pushByte_back(recibido.getByteAt(0)); // Dirección
 respuesta.pushByte_back(recibido.getByteAt(1)); // Función
 respuesta.pushWord_back(offset); // Offset
 respuesta.pushWord_back(numPos); // Número de bytes
 respuesta.aniadeCRC(); // CRC
 std::cerr << "Respuesta: " << respuesta << std::endl;
 return respuesta;

}


Mensaje ModbusRTU::atiende06(Mensaje& recibido) {

 std::cerr << "Entramos en metodo atiende06 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 uint16_t valor = recibido.getWordAt(4);
 if (!dentroDeRango<uint16_t>(_AO, offset))
   return generaError(recibido, 0x02);
 std::cerr << "Ponemos a " << (int)valor << " la AO[" << offset
           << "]: " << _AO.at(offset) << std::endl;
 _AO.at(offset) = valor;
 return recibido;

}


Mensaje ModbusRTU::atiende16(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Entramos en metodo atiende16 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 uint16_t numPos = recibido.getWordAt(4);
 if (!dentroDeRango<uint16_t>(_AO, offset, numPos))
   return generaError(recibido, 0x02);
 unsigned k = 7; // A partir de aquí solo existen datos y el CRC
 uint16_t dato = recibido.getWordAt(k);
 for (std::size_t i = offset; i < (offset + numPos); ++i) {
   _AO.at(i) = dato;
   k += 2; // Se salta una palabra
   dato = recibido.getWordAt(k);
 }
 respuesta.pushByte_back(recibido.getByteAt(0)); // Dirección
 respuesta.pushByte_back(recibido.getByteAt(1)); // Función
 respuesta.pushWord_back(offset); // Offset
 respuesta.pushWord_back(numPos); // Número de bytes
 respuesta.aniadeCRC(); // CRC
 std::cerr << "Respuesta: " << respuesta << std::endl;
 return respuesta;

}


void ModbusRTU::actualizaAI() {

 unsigned ra = 0;
 _AI.at(ra++) = _petRecibidas;
 _AI.at(ra++) = _byteRecibidos;
 _AI.at(ra++) = _byteEnviados;
 std::time_t now_time = std::time(nullptr);
 std::tm* now = std::localtime(&now_time);
 _AI.at(ra++) = now->tm_year + 1900;
 _AI.at(ra++) = now->tm_mon + 1;
 _AI.at(ra++) = now->tm_mday;
 _AI.at(ra++) = now->tm_hour;
 _AI.at(ra++) = now->tm_min;
 _AI.at(ra++) = now->tm_sec;
 // Datos proceso
 #ifdef OS_Windows
 /* Código para sistemas Windows 64 bits */
 _AI.at(ra++) = 0; //Placeholder
 _AI.at(ra++) = 0; //Placeholder
 _AI.at(ra++) = 0; //Placeholder
 _AI.at(ra++) = 0; //Placeholder
 #else
 /* Código para sistemas GNU/Linux */
 _AI.at(ra++) = getuid();
 _AI.at(ra++) = getgid();
 _AI.at(ra++) = getpid();
 _AI.at(ra++) = getppid();
 #endif
 for (std::size_t i = 0; i < 15; ++i) {
   _DI.at(i) = _AI.at(i) & 1; // 0 si es par, 1 si es impar
 }

}


template <class T> void ModbusRTU::muestraRegistro(

   const std::vector<T>& registro,
   const std::string& identificador) const {
 std::cerr << identificador;
 for (const T& k: registro) {
   std::cerr << k << ", ";
 }
 std::cerr << std::endl;

}


Mensaje ModbusRTU::atiende02(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Entramos en metodo atiende02 con mensaje " << recibido
           << std::endl;
 uint16_t offset = recibido.getWordAt(2);
 uint16_t numPos = recibido.getWordAt(4);
 if (!dentroDeRango<bool>(_DI, offset, numPos))
   return generaError(recibido, 0x02);
 unsigned numBytes = ((numPos - 1) / 8) + 1;
 respuesta.pushByte_back(recibido.getByteAt(0)); // Dirección
 respuesta.pushByte_back(recibido.getByteAt(1)); // Función
 respuesta.pushByte_back(numBytes); // Número de bytes
 unsigned posBit = 0;
 uint8_t dato = 0;
 for (std::size_t i = offset; i < (offset + numPos); ++i) {
   std::cerr << "Accediendo DI[" << i << "]: " << _DI.at(i)
             << std::endl;
   if (_DI.at(i))
     dato |= 1 << posBit;
   ++posBit;
   if (posBit == 8) { // Hemos rellenado un byte
     respuesta.pushByte_back(dato);
     posBit = 0;
     dato = 0;
   }
 }
 if (posBit > 0) { // Queda un byte a medio rellenar
   respuesta.pushByte_back(dato);
 }
 respuesta.aniadeCRC(); // CRC
 std::cerr << "Respuesta: " << respuesta << std::endl;
 return respuesta;

}

Mensaje ModbusRTU::atiende04(Mensaje& recibido) {

 Mensaje respuesta;
 std::cerr << "Entramos en metodo atiende04 con mensaje " << recibido
           << std::endl;
 // Debido al desplazamiento, el offset podría sufrir overflow
 // por eso elegimos int esta vez
 int offset = recibido.getWordAt(2) - DESPLAZA_AI;
 int numPos = recibido.getWordAt(4);
 if (!dentroDeRango<uint16_t, int>(_AI, offset, numPos))
   return generaError(recibido, 0x02);
 respuesta.pushByte_back(recibido.getByteAt(0)); // Dirección
 respuesta.pushByte_back(recibido.getByteAt(1)); // Función
 respuesta.pushByte_back(numPos * 2); // Número de bytes
 for (std::size_t i = offset; i < (offset + numPos); ++i) { // Datos
   std::cerr << "Accediendo AI[" << i << "]: " << _AI.at(i)
             << std::endl;
   respuesta.pushWord_back(_AI.at(i));
 }
 respuesta.aniadeCRC(); // CRC
 std::cerr << "Respuesta: " << respuesta << std::endl;
 return respuesta;

}