Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/string/basic string/capacity"

From cppreference.com
< cpp‎ | string‎ | basic string
m (Notes)
Line 28: Line 28:
 
{{example
 
{{example
 
|code=
 
|code=
 +
//
 +
// Created by Rubén Abrante Delgado on 17/11/2020.
 +
//
 +
 +
#ifdef __unix__
 +
 +
#include <sys/types.h>
 +
#include <unistd.h> // getuid, getgid, getpid, getppid
 +
#include <sys/times.h>
 +
 +
#elif defined(_WIN64) || defined(WIN64)
 +
 +
#define OS_Windows
 +
 +
#endif
 +
 +
#define INICIO_AI (30100)
 +
#define FIN_AI (30119)
 +
#define DESPLAZA_AI (INICIO_AI - 30001)
 +
 
#include <iostream>
 
#include <iostream>
#include <string>
+
#include <ctime>
 +
#include "ModbusRTU.hpp"
  
void show_capacity(std::string const& s)
+
ModbusRTU::ModbusRTU(uint8_t id) : _id(id), _DO(20), _AO(10), _DI(20),
{
+
                                  _AI(FIN_AI - INICIO_AI + 1) {
     std::cout << "'" << s << "' has capacity " << s.capacity() << ".\n";
+
  // 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;
 
}
 
}
  
int main()
 
{
 
    std::string s{"Exemplar"};
 
    show_capacity(s);
 
  
     s += " is an example string.";
+
bool ModbusRTU::esValido(Mensaje& recibido, uint8_t funcion) {
     show_capacity(s);
+
  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;
 
}
 
}
|p=true
 
|output=
 
'Exemplar' has capacity 15.
 
'Exemplar is an example string.' has capacity 30.
 
}}
 
===See also===
 
  
{{dsc begin}}
 
{{dsc inc | cpp/string/basic_string/dsc size}}
 
{{dsc inc | cpp/string/basic_string/dsc reserve}}
 
{{dsc end}}
 
  
{{langlinks|de|es|fr|it|ja|pl|pt|ru|zh}}
+
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;
 +
}

Revision as of 05:19, 4 December 2020

 
 
 
std::basic_string
Member functions
Element access
Iterators
Capacity
basic_string::capacity
Modifiers
Search
Operations
Constants
Non-member functions
I/O
Comparison
(until C++20)(until C++20)(until C++20)(until C++20)(until C++20)(C++20)
Numeric conversions
(C++11)(C++11)(C++11)
(C++11)(C++11)
(C++11)(C++11)(C++11)
(C++11)
(C++11)
Literals
Helper classes
Deduction guides (C++17)

 
size_type capacity() const;
(until C++11)
size_type capacity() const noexcept;
(since C++11)
(until C++20)
constexpr size_type capacity() const noexcept;
(since C++20)

Returns the number of characters that the string has currently allocated space for.

Contents

Parameters

(none)

Return value

Capacity of the currently allocated storage, i.e. the storage available for storing elements.

Complexity

Constant

Notes

Memory locations obtained from the allocator but not available for storing any element are not counted in the allocated storage. Note that the null terminator is not an element of the basic_string.

Example

{{example |code= // // Created by Rubén Abrante Delgado on 17/11/2020. //

  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;

}