Control Remoto para PC


Dicen que de las necesidades surgen las mejores ideas…y estoy convencido de que es así. La cuestión es que tengo unas cuantas películas en cd y las veo en el televisor a través de la salida tv out de la pc, pero me resultaba muy incomodo levantarme del sitio donde estaba viendolas para avanzar o retroceder en cierto momento de las mismas… así fué como me embarque en el proyecto de construirme un control remoto para la pc… no solamente para controlar los videos o la música a distancia sinó para ejecutar cualquier comando…
Éste control remoto también resulta muy útil para un departamento de sistemas, donde los servidores normalmente están en una habitación refrigerada y aislada de la oficina… es muy facil lanzar la ejecución de un script o comando a distancia…
Después de tener mucho tiempo la idea en background en mi cabeza analizando las posibilidades de implementación, llegué a la conclusión de que la manera mas facil de implementarlo sería a través del puerto serie, utilizando la linea DCD (Data Carrier Detect) , Pin 1 en una ficha DB9. Cuando un control remoto emite una señal infraroja, es captada por un receptor infrarojo, que, después de decodificarla, puede envirla como un tren de pulsos altos o bajos (ceros y unos) a la linea DCD. A partir de ahí solo es cuestión de analizar el patron del tren de pulsos a través de un programa y decidir que hacer en caso de que aparezca una secuencia dada.
Éste es el esquema electronico del receptor:
schematics-ir-receiver
La idea es que una vez construído el receptor, se graban los pulsos emitidos por un control remoto cualquiera (ej. de un tv o equipo de audio) y después se utiliza ese control remoto para controlar la pc.
El gran problema con que me encontré fué al programar algoritmo para identificar los patrones de pulsos que ingresan a la linea DCD… es bastante complejo diferenciar la secuencia de un botón Power de la de un botón Volumen, ya que al transformar la señal analogica en digital, puede haber una pequeña variacion en la cantidad de unos y ceros.
La solución a este problema me la dieron los muchachos que hicieron el lirc (Linux Infrared Remote Control) que ya habían pensado en lo mismo y tenían desarrollado el programa para trabajar de la misma manera que yo necesitaba.
La alimentación del circuito la tomamos del pin 7 RTS (request to send), con un diodo para evitar retroalimentación en éste pin.
Respecto del receptor infrarojo, éstos son algunos modelos que se pueden utilizar:
Todos estos modelos ya vienen con el decodificador necesario para obtener la señal esperada para la linea DCD. En caso de no conseguirlos, hay que buscar alguno que trabaje en la frecuencia de 38 kHz, ya que la mayoria de los control remoto, trabajan en ésta frecuencia.
El resto de los componentes se describe en el esquema de arriba.
tie_lirc1
Respecto del programa, aqui tienen una version del winlirc con los fuentes y todo. Pueden abrir el proyecto en Visual C++.

Cómo Conectar el Monitor de Mac a una PC


Resulta que en la empresa donde trabajo, había un monitor de 17″ Mac, de tubo plano…una belleza…y… carísimo. El tema es que no se utilizaba porque la Mac a la que se enchufaba tenía solo 16 Mb de RAM y disco de 8 Gb. Por lo tanto se me ocurrió que debería haber una manera de conectar ese monitor a una pc con una buena placa aceleradora de video para trabajar en diseño… y así es que buscando en internet encontré la equivalencia de pines entre la placa VGA y Mac:

  
Todo lo que hay que hacer es realizar el conexionado según los pines. Ojo con la soldadura en las fichas, y la calidad del cable de video, ya que puede haber interferencias. Tengo entendido que la conexión inversa, es decir, de PC a Mac también es posible, aunque no lo he probado.

script para verificar conexión


Este script verifica la conexión con un determinado servidor. Puede ser utilizado con un router/modem y, eventualmente reiniciarlo a través de un comando expect / spawn.

[root@test scripts]# cat chkconn 
dd=`date +%d`
mm=`date +%m`
YY=`date +%Y`
HH=`date +%H`
MM=`date +%M`
d=0
u=0
HOSTS="www.google.com newton 10.0.1.4 fabrica.dyndns.org"
for HOST in $HOSTS
do
   ping $HOST -c 1|grep " 0% packet loss" > /dev/null
   if [ $? = 0 ] 
   then
      echo "$YY$mm$dd$HH$MM $HOST está levantado"
      let "u=u+1" 
   else
      echo "$YY$mm$dd$HH$MM $HOST no es accesible" >> /var/log/chkconn.log
      let "d=d+1"
   fi
done
echo
#echo "$u sistemas levantados"
#echo "$d sistemas inaccesibles"
#### Si hay mas de tres servidores inaccesibles, reinicia el modem ADSL
#if [[ $d > 3 ]]
#then
#   echo "$YY$mm$dd$HH$MM - Hay $d sistemas off-line" >> /var/log/chkconn.log
#   /usr/bin/expect /root/scripts/reboot.exp
#else
#   echo "Ok."
#fi

 

[root@test scripts]# cat reboot.exp 
spawn telnet 10.0.1.4

expect "NetDSL>"
send "reboot\r"

expect "r"

Control de Acceso del Personal económico


Corría el año 2003 y nos pidieron un sistema de control de acceso. Estas son las ideas que surgen cuando no hay presupuesto:

2013-09-27 18.13.51

2013-09-27 18.16.02Tomamos una vieja pistola lectora de código de barras, la pusimos dentro de una caja con una ranura para pasar la tarjeta y reemplazamos el botón por un sensor de presión.

reloj

Las tarjetas poseen un Code 39 con el legajo del empleado y el programa en la pc se ocupa de guardar la fichada en la base de datos. En esa época casi ningún sistema comercial grababa directamente en una base de datos remota.

Este sistema está funcionando desde el 25/11/2003.

Gracias Carlitos B. por tu ayuda con el sensor.

Probar Fuente de Alimentación


Dado que la pregunta recurrente es: que cable puenteaba para probar la fuente …?
Aquí queda este ayuda memoria:

Para probar la fuente de alimentación de una PC (ATX) sin necesidad de conectarla al mother, lo único que hay que hacer es puentear el único cable verde con algúno de los cables negros.

No hay mejor herramienta para eso que la “herramienta universal para probar fuentes” o simplemente “clip”.

Adicionalmente es buena práctica medir con un tester los voltajes de salida de la fuente cuando la PC está encendida, así verificaremos que estos no caen con la carga del equipo en funcionamiento.

ERRCUIL – Algoritmo de Validacion de CUIL – CUIT


Este algoritmo me lo pasó anotado en un papel, un empleado de una delegación de AFIP Mar del Plata allá por 1997. Con algunas optimizaciones, hoy en día lo sigo utilizando.

Este es el TDA en Pascal.

{ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» 
 º ERRCUIL - Algoritmo de Validacion º 
 º de CUIL - CUIT                    º 
 º Desarrollado por: H. Vivani.      º 
 º 14/07/2001                        º 
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ 
}
program errcuil;
uses 
   crt; 
type 
   tcuil=array[1..11] of char; 
var 
   c:tcuil; 
   i:byte; 
   vc1,vc2,vc3,vc4,vc5:byte; 
   vc6,vc7,vc8,vc9,vc10,vc11:byte; 
   vtotal,vcoci,vres:real; 
   err:integer;
begin 
   clrscr; 
   writeln('**CONTROL DEL CUIL**'); 
   writeln; 
   writeln; 
   i:=0; 
   write('Ingrese el CUIL: '); 
   repeat 
      i:=i+1; 
      read(c[i]); 
   until eoln(input); 
   val(c[1],vc1,err); 
   val(c[2],vc2,err); 
   val(c[3],vc3,err); 
   val(c[4],vc4,err); 
   val(c[5],vc5,err); 
   val(c[6],vc6,err); 
   val(c[7],vc7,err); 
   val(c[8],vc8,err); 
   val(c[9],vc9,err); 
   val(c[10],vc10,err); 
   val(c[11],vc11,err); 
   vtotal:=(vc1*5 + vc2*4 + vc3*3 + vc4*2 + vc5*7 + vc6*6 + vc7*5 + vc8*4 + vc9*3 + vc10*2)*10; 
   vcoci:=vtotal/11; 
   vres:=vtotal-(INT(vcoci)*11); 
   if (vres vc11) or (vcoci = 0) then 
   begin 
        writeln('VTOTAL: ', vtotal:10:2); 
        writeln('VCOCI: ', vcoci:10:2); 
        writeln('Vres: ', vres:10:2); 
        writeln; 
        writeln('CUIT ERRONEO'); 
   end 
   else 
   begin 
        writeln('VTOTAL: ', vtotal:10:2); 
        writeln('VCOCI: ', vcoci:10:2); 
        writeln('Vres: ', vres:10:2); 
        writeln; 
        writeln('CUIT OK'); 
   end; 
   readln; 
   readln; 
end.

TDA LISTA – en memoria dinamica


{ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º TDA LISTA – en memoria dinamica   º
 º Desarrollado por: H. Vivani.      º
 º Universidad CAECE – Mar del Plata º
 º 31/10/2000                        º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
}

unit listad;

INTERFACE

type
   TElemL=integer;
   pnodo=^nodo;
   nodo=record
      dato:TElemL;
      sig:pnodo;
   end;
   tlista=record
      pri,act:pnodo;
   end;

Procedure IniciaL(var l:tlista);
Function VaciaL (l:tlista):boolean;
Procedure PrimeroL (var l:tlista);
Procedure SiguienteL(var l:tlista);
Function FinL(l:tlista):boolean;
Procedure InsertaL(var l:tlista;e:TElemL);      {inserta al medio o al final}
Procedure InsertaPpioL(var l:tlista;e:TElemL);
Procedure InsertaFinL(var l:tlista;e:TElemL);
Procedure InsertaNL(var l:tlista; e:TElemL; n:integer);
Procedure EliminaPpioL(var l:tlista);
Procedure ELiminaL(var l:tlista);

Procedure EliminaNL(var l:tlista;var e:TElemL; n:integer);
Procedure InfoL(l:tlista; var e:TElemL);
Procedure ModificaL(var l:tlista; e:TElemL);

IMPLEMENTATION

procedure IniciaL;
begin
   l.pri:=nil;
   l.act:=nil;
end;

function VaciaL;
begin
   vacial:=l.pri=nil;
end;

procedure PrimeroL;
begin
   l.act:=l.pri;
end;

procedure SiguienteL;
begin
   l.act:=l.act^.sig;
end;

function FinL;
begin
   finl:=l.act=nil;
end;

procedure InsertaL;                     {inserta al medio o al final}
var
   aux,act,ant:pnodo;
begin
   new(aux);
   aux^.dato:=e;
   if vacial(l) or (e <= l.pri^.dato) then {si vacia o < que el primero}
   begin
      aux^.sig:=l.pri;          {insertappio}
      l.pri:=aux;
   end
   else
   begin
      ant:=l.pri;
      act:=ant;
      while (act nil) and (e > act^.dato) do
      begin
         ant:=act;
         act:=act^.sig;
      end;
      ant^.sig:=aux;
      aux^.sig:=act;
   end;
end;

procedure InsertaPpioL;
var
   aux:pnodo;
begin
   new(aux);
   aux^.dato:=e;
   aux^.sig:=l.pri;
   l.pri:=aux;
end;

Procedure InsertaFinL;
var
   ant,act,aux:pnodo;
begin
   new(aux);
   aux^.dato:=e;
   ant:=l.pri;
   act:=ant;
   while act nil do
   begin
      ant:=act;
      act:=act^.sig;
   end;
   ant^.sig:=aux;
   aux^.sig:=act;
end;

procedure InsertaNL;
var
   aux,ant,act:pnodo;
   cont:integer;
begin
   new(aux);
   aux^.dato:=e;
   if n=1 then                          {si es el nodo 1}
   begin
      aux^.sig:=l.pri;
      l.pri:=aux;
   end
   else
   begin
      ant:=l.pri;
      act:=ant;
      cont:=1;
      while (act nil) and (cont < n) do
      begin
         cont:=cont+1;
         ant:=act;
         act:=act^.sig;
      end;
      ant^.sig:=aux;
      aux^.sig:=act;
   end;
end;

Procedure EliminaPpioL;
var
   aux:pnodo;
begin
   if l.prinil then
   begin
      aux:=l.pri;
      l.pri:=l.pri^.sig;
      dispose(aux);
   end;
end;

Procedure EliminaL;
var
   aux,ant:pnodo;
begin
   if l.prinil then
   begin
      if l.act=l.pri then       {si es el primer nodo}
      begin
         aux:=l.pri;
         l.pri:=l.pri^.sig;
         dispose(aux);
      end
      else
      begin
         ant:=l.pri;
         aux:=ant;
         while (aux nil) and (aux l.act) do
         begin
            ant:=aux;
            aux:=aux^.sig;
         end;
         ant^.sig:=aux^.sig;
         dispose(aux);
      end;
   end;
end;

procedure EliminaNL;
var
   aux,ant:pnodo;
   cont:integer;

begin
   if l.prinil then
   begin
      if n=1 then               {si es el primer nodo}
      begin
         e:=l.pri^.dato;
         aux:=l.pri;
         l.pri:=l.pri^.sig;
         dispose(aux);
      end
      else
      begin
         ant:=l.pri;
         aux:=ant;
         cont:=1;
         while (cont < n) and (aux nil) do
         begin
            cont:=cont+1;
            ant:=aux;
            aux:=aux^.sig;
         end;
         if aux nil then
         begin
            e:=aux^.dato;
            ant^.sig:=aux^.sig;
            dispose(aux);
         end;
      end;
   end;
end;

procedure InfoL;
begin
   e:=l.act^.dato;
end;

procedure ModificaL;
begin
   l.act^.dato:=e;
end;

end.

TDA PILA – en memoria dinamica


{ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º TDA PILA – en memoria dinamica    º
 º Desarrollado por: H. Vivani.      º
 º Universidad CAECE – Mar del Plata º
 º 30/10/2000                        º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
}

unit pilad;

INTERFACE

type
   TElemP=string[10];      {o cualquier tipo}
   tpila=^nodo;             {el tipo pila es un puntero a un nodo}
   nodo=record
      item:telemp;
      sig:tpila;
   end;

procedure IniciaP(var p:tpila);
procedure SacaP(var p:tpila;var e:telemp);
procedure PoneP(var p:tpila; e:telemp);
function VaciaP(p:tpila):boolean;
procedure ConsultaP(p:tpila; var e:telemp);

IMPLEMENTATION

procedure IniciaP;
begin
   p:=nil;
end;

procedure SacaP;
var
   aux:tpila;
begin
   if not vaciap(p) then
   begin
      aux:=p;                   {aux apunta a p}
      e:=p^.item;               {obtengo en e el elemento}
      p:=aux^.sig;              {p apunta al siguiente de aux}
      dispose(aux);             {devuelvo la memoria}
   end;
end;

procedure PoneP;
var
   nuevo:tpila;
begin
   new(nuevo);                  {pido memoria}
   nuevo^.item:=e;              {asigno el elemento}
   nuevo^.sig:=p;               {el siguiente del nuevo apunta a p}
   p:=nuevo;                    {p apunta al nuevo}
end;

function VaciaP;
begin
   VaciaP:=p=nil;
end;

procedure ConsultaP;
begin
   e:=p^.item;
end;

end.

TDA COLA – en memoria dinamica


{ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º TDA COLA – en memoria dinamica    º
 º Desarrollado por: H. Vivani.      º
 º Universidad CAECE – Mar del Plata º
 º 30/10/2000                        º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
}

unit colad;

INTERFACE

type
   TElemC=string[10];      {o cualquier tipo}
   pnodo=^nodo;
   nodo=record
      item:telemC;
      sig:pnodo;
   end;
   tcola=record
      pri,ult:pnodo;
   end;

procedure IniciaC(var c:tcola);
procedure SacaC(var c:tcola;var e:telemc);
procedure PoneC(var c:tcola; e:telemc);
function VaciaC(c:tcola):boolean;
procedure ConsultaC(c:tcola; var e:telemc);

IMPLEMENTATION

procedure IniciaC;
begin
   c.pri:=nil;
   c.ult:=nil;
end;

procedure SacaC;
var
   aux:pnodo;
begin
   if not vaciac(c) then
   begin
      e:=c.pri^.item;
      aux:=c.pri;
      if aux^.sig=nil then   {para cuando queda un elemento}
         c.ult:=nil;
      c.pri:=aux^.sig;
      dispose(aux);
   end;
end;

procedure PoneC;
var
   nuevo:pnodo;
begin
   new(nuevo);                  {pido memoria}
   nuevo^.item:=e;
   nuevo^.sig:=nil;
   if vaciac(c) then
      c.pri:=nuevo
   else
      c.ult^.sig:=nuevo;
   c.ult:=nuevo;
end;

function VaciaC;
begin
   VaciaC:=c.pri=nil;
end;

procedure ConsultaC;
begin
   e:=c.pri^.item;
end;

end.