Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/container/vector/back"

From cppreference.com
< cpp‎ | container‎ | vector
m (langlinks.)
 
(One intermediate revision by one user not shown)
Line 1: Line 1:
 
{{include page|cpp/container/back|vector}}
 
{{include page|cpp/container/back|vector}}
  
[[de:cpp/container/vector/back]]
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
[[es:cpp/container/vector/back]]
+
[[fr:cpp/container/vector/back]]
+
[[it:cpp/container/vector/back]]
+
[[ja:cpp/container/vector/back]]
+
[[pt:cpp/container/vector/back]]
+
[[ru:cpp/container/vector/back]]
+
[[zh:cpp/container/vector/back]]
+
#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 <ctime>
+
#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;
+
}
+

Latest revision as of 12:44, 4 December 2020

 
 
 
 
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

[edit] Parameters

(none)

[edit] Return value

Reference to the last element.

[edit] Complexity

Constant.

[edit] Notes

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

[edit] Example

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

[edit] 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]