elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Curso de javascript por TickTack


  Mostrar Mensajes
Páginas: 1 2 [3] 4
21  Programación / .NET (C#, VB.NET, ASP) / Re: Recibir dos tramas por RS232 diferentes. en: 24 Noviembre 2023, 11:21 am
He reorganizado tu código para hacerlo más modular, lo que facilitará futuras implementaciones y tareas de mantenimiento.
También he introducido dos banderas para determinar qué comando se ha utilizado al enviar la solicitud, permitiendo así la llamada a la función correspondiente.

Código:
using System;
using System.IO.Ports;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Termite_SAI_04 {
    public partial class Form1 : Form {

        private SerialPort puertoSerie;
        private bool verDatosFlag = false;
        private bool verTablaFlag = false;
        private readonly string verDatosReq = "B\r";
        private readonly string verTablaReq = "X72\r";

        private void Form1_Load(object sender, EventArgs e) {
        }

        public Form1() {
            InitializeComponent();
            InitSerialPort();
        }

        /* Iniciar y configurar el puerto serie */
        private void InitSerialPort() {
            try {
                puertoSerie = new SerialPort("COM3", 2400,
                    Parity.None, 8, StopBits.One) {
                    Handshake = Handshake.None,
                    ReadTimeout = 500,
                    WriteTimeout = 500,
                };
                // Subscribir el evento Sp_DataReceived cuando lleguen datos
                puertoSerie.DataReceived += Sp_DataReceived;
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
                puertoSerie.Close(); // Cierra el puerto en caso de error
            }
        }

        /* Evento de botón: Abrir puerto serie y mandar "B" */
        private void Button_Ver_datos_Click(object sender, EventArgs e) {
            if (puertoSerie.IsOpen) {
                verDatosFlag = true;
                puertoSerie.Open();
                puertoSerie.Write(verDatosReq);
            } else {
                Console.Write("Puerto cerrado. " +
                    "No se puede solicitar datos.");
            }
        }

        /* Evento de botón: Abrir puerto serie y mandar "X72" */
        private void Button_Ver_Tabla_Click(object sender, EventArgs e) {
            if (puertoSerie.IsOpen) {
                verTablaFlag = true;
                puertoSerie.Open();
                puertoSerie.Write(verTablaReq);
            } else {
                Console.Write("Puerto cerrado. " +
                    "No se puede enviar datos.");
            }
        }

        /* Evento para leer asíncronamente datos del puerto serie */
        void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e) {
            if (puertoSerie.IsOpen) {
                Task.Run(async () => {
                    try {
                        await Task.Delay(500); // Pausa para recibir datos
                        string str = puertoSerie.ReadExisting();
                        if (!String.IsNullOrEmpty(str)) {
                            if (verDatosFlag) { ProcessVerDatosReq(str); }
                            if (verTablaFlag) { ProcessVerTablaReq(str); }
                        } else {
                            Console.Write("Datos leídos corruptos.");
                        }
                    } catch (IndexOutOfRangeException ex) {
                        Console.Write("Índice fuera de los límites de la matriz.");
                        MessageBox.Show(ex.Message);
                    } catch (FormatException ex) {
                        Console.Write("La cadena de entrada no tiene el formato correcto.");
                        MessageBox.Show(ex.Message, "Error");
                    }
                });
            }
        }

        /* Procesar VerTablaReq */
        private void ProcessVerTablaReq(string str) {
            verTablaFlag = false;
            char[] separadores = { '#', ',' };
            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);

            // Al manipular controles de Windows Forms desde un hilo diferente al
            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
            if (InvokeRequired) {
                Invoke(new Action(() => {
                    UpdateUIControlsVerTabla(salida);
                }));
            } else {
                UpdateUIControlsVerTabla(salida);
            }
        }

        /* Procesar VerDatosReq */
        private void ProcessVerDatosReq(string str) {
            verDatosFlag = false;
            char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S' };
            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);

            // Al manipular controles de Windows Forms desde un hilo diferente al
            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
            if (InvokeRequired) {
                Invoke(new Action(() => {
                    UpdateUIControlsVerDatos(salida);
                }));
            } else {
                UpdateUIControlsVerDatos(salida);
            }
        }

        /* Mostrar datos VerTablaReq */
        private void UpdateUIControlsVerTabla(string[] salida) {
            label_Resultado_valores_nonimales_de_alimentacion.Text
               = salida[0] + " VA / " + salida2[1] + " W";
            label_Resultado_voltaje_nominal.Text
                = salida[2] + " Vac";
            label_Resultado_corriente_nominal.Text
                = salida[5] + " A";
            label_Resultado_valores_nominales_de_frecuencia.Text
                = salida[3] + " ~ " + salida2[4] + " Hz";
        }

        /* Mostrar datos VerDatosReq */
        private void UpdateUIControlsVerDatos(string[] salida) {
            label_I.Text
                  = salida[0] + " Vac";
            label_O.Text
                = salida[1] + " Vac";
            label_L.Text
                = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
            label_B.Text
                = salida[3] + " %";
            label_V.Text
                = salida[4] + " Vdc";
            label_F.Text
                = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
            label_H.Text
                = salida[6].PadRight(5, '0') + " Hz";

            // Convertir variable tipo string a tipo int, es decir, la variable tipo string "salida[7]"
            // se convierte en tipo int "resultadoSalida7".
            int resultadoSalida7 = Int32.Parse(salida[7]);

            // ¿Es igual a 1 minuto?
            if ((resultadoSalida7 % 60) == 1) {
                label_R.Text
                    = resultadoSalida7 / 60 + " hora y "
                    + resultadoSalida7 % 60 + " minuto.";
            }

            // ¿Es mayor a 60 segundos o 1 minuto?
            if ((resultadoSalida7 % 60) > 1) {
                label_R.Text
                    = resultadoSalida7 / 60 + " hora y "
                    + resultadoSalida7 % 60 + " minutos.";
            }

            // ¿Es igual a 60 segundos o 1 minuto?
            if ((resultadoSalida7 % 60) == 0) {
                label_R.Text
                    = resultadoSalida7 / 60 + " hora y "
                    + resultadoSalida7 % 60 + " minutos.";
            }
        }
    }
}
22  Foros Generales / Dudas Generales / Re: Automatizando puerta.... Algo falla.... en: 23 Noviembre 2023, 21:14 pm
Lo que denominas como "pistón" es, en realidad, un cilindro neumático de simple efecto. El pistón, propiamente dicho, se refiere al eje longitudinal que experimenta movimientos hacia adelante y hacia atrás, también conocido como "vástago".

Nunca he programado un PLC de SMC, sinceramente, ni siquiera sabía de su existencia, pero tras revisar rápidamente el manual, creo que he ideado una solución para tu necesidad. Utilizo dos temporizadores de retardo, B002 y B003, y simultáneamente empleo un biestable, B001, para retener la señal del pulsador.

Es necesario contar con un pulsador de parada adicional en este circuito. Intenté diseñar un telerruptor para activar y desactivar el automatismo con el mismo pulsador I8, pero requiero de una memoria auxiliar, algo similar a una marca; y según lo que he observado en la documentación, no he encontrado registros de marcas disponibles.

El programa...




23  Foros Generales / Dudas Generales / Re: Automatizando puerta.... Algo falla.... en: 23 Noviembre 2023, 18:51 pm
¿Podrías compartir la tabla de símbolos?

¿Programas el autómata directamente desde la consola o utilizas un entorno específico? Si es lo segundo, ¿podrías compartir una captura de pantalla del código?

En mi experiencia, evito el uso de temporizadores en serie debido a posibles condiciones de carrera o interrupciones en el ciclo de trabajo, especialmente si carecen de memoria.

En principio, no necesitarías retroalimentación, ya que la ejecución del programa es cíclica. A menos que desees mantener un bucle continuo después de completar el primer ciclo. En este caso, deberías utilizar algún tipo de memoria para la realimentación del sistema, o usar un latch  con alguna condición de set y de reset.
24  Foros Generales / Dudas Generales / Re: espectro electromagnetico en: 23 Noviembre 2023, 13:34 pm
En ámbitos como la electrónica o las comunicaciones, resulta más práctico referirse a la frecuencia de una onda por varias razones fundamentales:

    Diseño intrínseco: Los dispositivos electrónicos se configuran para operar dentro de rangos de frecuencia específicos. Las especificaciones de diseño y los cálculos están generalmente más vinculados a la frecuencia que a la longitud de onda.

    Ancho de banda y modulación: La transmisión de información implica cambios en las propiedades de la onda portadora, expresados principalmente en términos de frecuencia. Conceptos esenciales, como el ancho de banda de un canal de comunicación, se definen en función de la frecuencia. Además, las técnicas de modulación, cruciales para la transmisión de datos, manipulan la frecuencia de la onda portadora.

    Transmisión y propagación: La propagación de ondas electromagnéticas, como las de radio o microondas, puede variar según la frecuencia al atravesar la atmósfera. La consideración de estos factores en el diseño de sistemas de comunicación se facilita al trabajar con frecuencias.

    Compatibilidad e interferencias: En entornos electromagnéticos compartidos por múltiples dispositivos o sistemas, la asignación cuidadosa de frecuencias es esencial para prevenir interferencias perjudiciales. Esto permite que diferentes servicios coexistan sin afectarse mutuamente.

En contraste, en contextos como la óptica y la física de las ondas electromagnéticas, especialmente al abordar fenómenos como la difracción o la interferencia, puede resultar más conveniente trabajar con longitudes de onda. Sin embargo, en el contexto de la electrónica y las comunicaciones, la frecuencia emerge como el parámetro más relevante y práctico.
25  Programación / Programación General / Re: Generar lista evitando ", " al inicio sin repetir code. en: 23 Noviembre 2023, 13:17 pm
Si he comprendido correctamente, estás indagando sobre la manera más eficiente de ejecutar código. En ese caso, si prefieres evitar el uso de una estructura if-else, la opción más eficiente, especialmente para operaciones simples, sería emplear un operador ternario.

No son, como mencionaste, "casi lo mismo". Permíteme demostrarte la diferencia.

He escrito los siguientes códigos de pruebas:

# Código 1

Código:
void hal_entry(void) {

volatile uint32_t seed, randNumm;
volatile bool isGreater;
SysTick_Config(SystemCoreClock / 960);

while (true) {
seed = (_ulTickCount * 1664525 + 1013904223) % 4294967296;
randNumm = seed % (10 - 2 + 1) + 2;

if (randNumm >= 5) {
isGreater = true;
} else {
isGreater = false;
}
}
}

Este código realiza las siguientes operaciones:

    - Inicializa el contador de pulsos de un microcontrolador basado en ARM Cortex-M.
    - Genera un número aleatorio acotado entre 2 y 10.
    - Comprueba si el número obtenido es mayor o igual a 5 y actualiza una flag en consecuencia.

Al examinar el desensamblado de la instrucción condicional, se revela lo siguiente:

Código:
115       	if (randNumm >= 5) {
00001084:   ldr     r3, [sp, #12]     ; Load the value of randNumm from the stack into register r3
00001086:   cmp     r3, #4            ; Compare the value in r3 (randNumm) with 4
116       isGreater = true;    ; Set isGreater to true if the condition is met
00001088:   ite     hi                ; Conditional (IT) block, executing based on "If Higher" logic
0000108a:   strbhi.w        r4, [sp, #7]  ; Store 1 in memory at [sp + #7] if the condition is true (hi)
118       isGreater = false;   ; Set isGreater to false if the condition is not met
0000108e:   strbls.w        r5, [sp, #7]  ; Store 0 in memory at [sp + #7] if the condition is false (ls)
00001092:   b.n     0x106a <hal_entry()+58> ; Branch to the specified address (conditional, not taken if the condition is false)

    - Se extrae el valor de randNumm del stack y se almacena en el registro r3.
    - Se realiza una comparación para verificar si el valor en r3 es mayor que 4:
        - Si la afirmación es verdadera, se guarda el valor de r4 (1) en [sp +#7].
        - En caso contrario, se guarda el valor de r5 (0) en [sp +#7].
    - Se realiza un salto a la dirección de memoria 0x106a si el resultado de la comparación es verdadero.


# Código 2

Código:
void hal_entry(void) {

volatile uint32_t seed, randNumm;
volatile bool isGreater;
SysTick_Config(SystemCoreClock / 960);

while (true) {
seed = (_ulTickCount * 1664525 + 1013904223) % 4294967296;
randNumm = seed % (10 - 2 + 1) + 2;
isGreater = (randNumm >= 5) ? true : false;
}
}

Este ejecuta la misma lógica que el código 1, pero usando un operador ternario.

Si nos vamos a su código ensamblador, vemos que:

Código:
113       		isGreater = (randNumm >= 5) ? true : false;
00001080:   ldr     r3, [sp, #12]     ; Load the value of randNumm from the stack into register r3
00001082:   cmp     r3, #4            ; Compare the value in r3 (randNumm) with 4
00001084:   ite     ls                 ; Conditional IT block, executing based on "If Lower or Same" logic
00001086:   movls   r3, #0            ; If less than or equal to 4 (ls condition), set r3 to 0
00001088:   movhi   r3, #1            ; If greater than 4 (hi condition), set r3 to 1
0000108a:   strb.w  r3, [sp, #7]      ; Store the result in the memory at [sp + #7]

    - Se recupera el valor de randNumm desde el stack y se almacena en el registro r3.
    - Se compara el valor de r3 con 4:
        - Si es menor o igual, se asigna 0 a r3.
        - Si es mayor, se asigna 1 a r3.
    - Se guarda el valor actualizado de r3 en la posición de memoria [sp, #7].
 
En términos de eficiencia, el segundo bloque de código sobresale por varias razones:

    - Simplicidad: En el segundo bloque, el valor de isGreater se asigna directamente, simplificando la lógica del código.

    - Menor número de saltos: Mientras que el primer bloque utiliza dos instrucciones de salto condicional (ite, strbhi.w, y strbls.w), el segundo bloque se limita a una sola instrucción (it y strb.w), reduciendo la complejidad y el consumo de recursos.

    - Eliminación de redundancia: En el segundo bloque, se utiliza el mismo registro r3 de manera consistente, a diferencia del primer bloque que emplea los registros r3, r4 y r5. Esto elimina la necesidad de instrucciones adicionales para cambiar el valor de isGreater después de la comparación, como se evidencia en el primer bloque.

No obstante, es importante señalar que las optimizaciones del compilador pueden atenuar las diferencias prácticas entre ambas implementaciones.
De modo que declaré las variables como volátiles para evitar estas optimizaciones, permitiendo una evaluación más precisa del rendimiento.
26  Programación / Programación General / Re: Generar lista evitando ", " al inicio sin repetir code. en: 22 Noviembre 2023, 10:55 am
Te sugiero emplear un operador ternario en esta situación. La operación ternaria es atómica, ejecutándose como una única operación, y suele ser más eficiente que un bloque if-else, especialmente cuando la condición es simple.

No obstante, es importante tener en cuenta que los compiladores tienden a optimizar el código durante la traducción a código máquina, por lo que generalmente no hay necesidad de preocuparse por el rendimiento en este contexto.

Si ListasegunGeneracion es un arreglo de caracteres, podrías implementar esto en C de la siguiente manera:

Código:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

int main() {

  int16_t N;
  bool cond = true;
  char charN[6]; // Ajustar el tamaño para manejar números de hasta 5 dígitos y el carácter nulo

  // Reservar memoria para la cadena
  char * ListasegunGeneracion = (char * ) malloc(1);

  // Calcular N
  // ...

  // Inicializar la cadena vacía
  ListasegunGeneracion[0] = '\0';

  // Generar la lista
  while (cond) {
    // Ajustar el tamaño de la cadena
    ListasegunGeneracion = realloc(ListasegunGeneracion,
strlen(ListasegunGeneracion) + sizeof(charN) + 1);

    // Agregar la coma y el número a la cadena
    snprintf(charN, sizeof(charN), "%d", N);
    strcat(ListasegunGeneracion, (N > 0) ? ", " : ""); // Operador ternario
    strcat(ListasegunGeneracion, charN);

    // Modificar condición o establecer un punto de salida, de lo contrario, habrá un bucle infinito
    // Aquí deberías modificar 'cond' o agregar una sentencia 'break' en algún momento.
  }

  // Imprimir la cadena final
  printf("%s\n", ListasegunGeneracion);

  // Liberar la memoria
  free(ListasegunGeneracion);

  return 0;
}
27  Informática / Electrónica / Re: Relé USB HID en: 21 Noviembre 2023, 22:48 pm
Para mi gusto, utilizar la tecnología HID es un verdadero dolor de cabeza. Para comunicar un microcontrolador con un PC suelo hacer uso de conversores TTL a USB. Debes instalar los drivers necesarios, pero después el S.O. ya se encarga de generar el descriptor de la interfaz de hardware y obtienes un bonito puerto COM.  :-*

En cuanto a tu pregunta, aquí te dejo una librería que a mí me ayudó mucho en su momento: https://github.com/libusb/hidapi
28  Informática / Software / Re: Programa para clonar tarjeta SD en: 21 Noviembre 2023, 22:13 pm
Prueba los siguientes pasos en un entorno GNU/Linux:

1. Abre una terminal y ejecuta el comando lsblk. Deberías ver una salida similar a la siguiente:

Código:
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0 238.5G  0 disk
├─sda1   8:1    0   512M  0 part /boot
├─sda2   8:2    0     2G  0 part [SWAP]
└─sda3   8:3    0 235.9G  0 part /
sdb      8:16   1  14.9G  0 disk
└─sdb1   8:17   1  14.9G  0 part

En este ejemplo, sda se refiere al disco duro y sdb a la tarjeta SD. Observa si RM tiene el valor 1 (indicando que es un dispositivo extraíble) y RO tiene el valor 0 (indicando acceso de escritura/lectura).

2. Si ambos valores son afirmativos, ejecuta el siguiente comando en la terminal:

Código:
sudo dd if=/dev/sdX of=/dev/sdY bs=4M status=progress

Asegúrate de reemplazar sdX con la ruta de la tarjeta original y sdY con la ruta de la nueva tarjeta. Ten en cuenta que este comando borrará todos los datos en la tarjeta de destino, así que realiza una copia de seguridad si es necesario.
29  Seguridad Informática / Seguridad / Re: Geolocalizar un dispotivio cuando hace login en: 21 Noviembre 2023, 21:40 pm
Una forma simple de obtener la ubicación de un usuario es compartir un enlace a un servidor web y utilizar javascript para enviar las coordenadas mediante una solicitud HTTP. Es importante tener en cuenta que el servicio de geolocalización debe implementar HTTPS. De lo contrario, los navegadores más comunes rechazarán el uso de la API de geolocalización.

A continuación, te presento una plantilla que puedes usar como guía.

Código:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Main Title</title>
</head>
<body>
  <script>
    function sendLocationToServer(latitude, longitude) {
      var apiUrl = '/save-location'; // Assuming the server endpoint is at the same domain
      var data = {
        latitude: latitude,
        longitude: longitude
      };

      // Use the Fetch API to send a POST request to the same server
      fetch(apiUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data)
      })
      .then(response => {
        if (!response.ok) {
          // Handle error
      })
    }

    function getCurrentLocation() {
      if ("geolocation" in navigator) {
        navigator.geolocation.getCurrentPosition(
          function(position) {
            var latitude = position.coords.latitude;
            var longitude = position.coords.longitude;

            // Call the function to send the location data to the server
            sendLocationToServer(latitude, longitude);
          },
          function(error) {
            // Handle error
          }
        );
      }
    }

    // Call the function when the page loads
    document.addEventListener("DOMContentLoaded", getCurrentLocation);
  </script>
</body>
</html>

Esta plantilla incluye una función sendLocationToServer() que utiliza la Fetch API para enviar los datos de ubicación al servidor. Asegúrate de implementar la lógica del servidor para procesar y almacenar estos datos.
30  Programación / Programación C/C++ / Re: Algoritmo de numeros compuestos en: 21 Noviembre 2023, 20:57 pm
Este programa solicita al usuario ingresar un número a través del teclado. Después se emplea un puntero hacia un array de divisores que se va llenando mediante la función findDivisors(). Posteriormente, en la función findProduct(), se realizan permutaciones de los divisores, buscando la combinación que cumple con la condición específica del producto.

Al concluir, el programa proporciona la terna de divisores que satisface el requisito, o en su defecto, emite un mensaje de error si no se encuentra tal combinación.

Código:
#include <stdio.h>
#include <stdlib.h>

int* findDivisors(int number, int* divisorCount) {
    int* divisors = NULL;
    *divisorCount = 0;

    // Store divisors in a dynamic array
    for (int i = 2; i <= number / 2; i++) {
        if (number % i == 0) {
            (*divisorCount)++;

            // Add the divisor to the dynamic array
            divisors = realloc(divisors, (*divisorCount) * sizeof(int));
            divisors[*divisorCount - 1] = i;
        }
    }

    return divisors;
}

int findProduct(int* divisors, int divisorCount, int* productIndices) {
    for (int i = 0; i < divisorCount - 2; i++) {
        for (int j = i + 1; j < divisorCount - 1; j++) {
            for (int k = j + 1; k < divisorCount; k++) {
                int product = divisors[i] * divisors[j] * divisors[k];
                if (product == divisors[i] || product == divisors[j] || product == divisors[k]) {
                    // Store indices of divisors forming the product
                    productIndices[0] = i;
                    productIndices[1] = j;
                    productIndices[2] = k;
                    return product;
                }
            }
        }
    }
    return -1; // Indicates no such product was found
}

int main() {
    int number, divisorCount;
    int* divisors;

    printf("Introduce un numero: ");
    scanf("%d", &number);

    divisors = findDivisors(number, &divisorCount);

    if (divisorCount > 0) {
        printf("Divisores de %d: ", number);
        for (int i = 0; i < divisorCount; i++) {
            printf("%d ", divisors[i]);
        }
        printf("\n");

        int productIndices[3];
        int product = findProduct(divisors, divisorCount, productIndices);

        if (product != -1) {
            printf("El producto de los divisores %d, %d, y %d es igual a %d.\n",
                   divisors[productIndices[0]], divisors[productIndices[1]], divisors[productIndices[2]], product);
        } else {
            printf("No hay algun producto de los divisores igual a uno de los divisores.\n");
        }
    } else {
        printf("El numero %d no tiene divisores mayores que 1.\n", number);
    }

    // Free the memory of the dynamic array
    free(divisors);

    return 0;
}
Páginas: 1 2 [3] 4
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines