Como se comentó en el post anterior, una forma muy sencilla de obtener la fecha y hora GPS locales de un mensaje TAIP es con un método como sigue, el cual recibe como argumentos los 3 campos de tiempo que el mensaje TAIP tiene, además de que se debe importar el paquete System.Globalization:
private String GetDate(string seconds, string day, string week){
//Se crea una instancia del objeto DateTime Inicializado el 6 de Enero de 1980 a las 00:00:00 hrs UTC.
DateTime dT = new DateTime(1980, 1, 6, new GregorianCalendar());
//A la instancia de la fecha anterior se le suman las semanas, el día y los segundos dados por el mensaje TAIP.
dT = new CultureInfo("es-MX").Calendar.AddWeeks(dT,Convert.ToInt32(week)).AddDays(Convert.ToDouble(day)).AddSeconds(Convert.ToDouble(seconds));
//Se convierte esta fecha a UTC-6 y se regresa como string en formato YYYY-MM-DD HH:mm:ss.
return dT.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", new CultureInfo("es-MX"));
}
Tecnologías de la información
lunes, 10 de febrero de 2014
Parseo de una sentencia TAIP.
Otro de los formatos en los cuales algunos dispositivos GPS transmiten sus localizaciones es en el formato TAIP (Trimble ASCII Interface Protocol).
Los mensajes TAIP tienen en general la siguiente estructura:
>REVAABBBBCDDDDDEEEEEEEEFFFFFFFFFGGGHHHJK<
Donde:
>: Inicio del Mensaje.
REV: Tipo de Mensaje.
AA: Tipo de Evento.
BBBB: Número de Semana (Desde el 6 de Enero de 1980 a las 00:00:00 hrs. UTC).
C: Día de la Semana (0 domingo).
DDDDD: Número de Segundos transcurridos en el día(UTC).
EEEEEEEE: Latitud (Grados decimales WGS-84).
FFFFFFFFF: Longitud (Grados decimales WGS-84)
GGG: Velocidad (MPH).
HHH: Rumbo (Grados sexagesimales).
J: Fuente de la última posición (0: 2D, 1: 3D, 9: No Fix).
K: Antigüedad del Mensaje (0: No disponible, 1: Mayor a 10 segundos, 2: Menor a 10 segundos).
<: Fin del Mensaje.
Un ejemplo de un mensaje TAIP es el siguiente:
>REV011779180540+1931046-0991095500000012<
Siguiendo la descripción anterior para este mensaje tenemos lo siguiente:
>: Inicio del Mensaje.
REV: Mensaje de Posición.
01: Evento 01.
1779: Semana 1,779 desde el 6 de Enero de 1980 a las 00:00:00 hrs. UTC.
1 : Lunes.
80540 : 80,540 segundos.
+1931046: Se divide entre 100,000 para obtener la latitud (19.31046).
-09910955: Se divide entre 100,000 para obtener la longitud (-99.10955).
000: 0 MPH.
000: Norte.
1: 3D.
2: Mensaje con menos de 10 segundos de antigüedad.
<: Fin del Mensaje.
Para obtener Hora GPS se propone seguir el siguiente procedimiento (se tomará el mensaje de ejemplo):
1) Dividir entre 60 el número de segundos para obtener los minutos:
80,540 seg = 1,342.3333 min
2) Separar la parte entera y la parte decimal:
Parte Entera = 1,342 min.
Parte Decimal = 0.33333333 min.
3) Multiplicar por 60 la parte decimal para obtener este dato en segundos:
0.33333333 min * 60 = 20 seg.
Con esto tenemos que: 80,540 seg = 1,342 min 20 seg.
4) Dividimos el número de minutos entre 60:
1,342 min = 22.366666666 hrs.
5) Separar la parte entera y la parte decimal:
Parte Entera = 22 hrs.
Parte Decimal = 0.36666666 hrs.
6) Multiplicar por 60 la parte decimal para obtener este dato en minutos:
0.36666666 hrs. * 60 = 22 min.
Con esto tenemos que: 80,540 seg = 1,342 min 20 seg = 22 hrs 22 min 20 seg, por lo que la hora UTC es 22:22:20 hrs. En el caso de México, la zona horaria es UTC -6, por lo que para obtener la hora local se deben restar 6 horas a esta hora, quedando como 16:22:20 hrs.
Computacionalmente el proceso de obtener la fecha resulta complicado, por lo que en el post siguiente daré una alternativa de cómo obtener las fechas y horas GPS de un Mensaje TAIP con C# de una forma rápida y sencilla.
Los mensajes TAIP tienen en general la siguiente estructura:
>REVAABBBBCDDDDDEEEEEEEEFFFFFFFFFGGGHHHJK<
Donde:
>: Inicio del Mensaje.
REV: Tipo de Mensaje.
AA: Tipo de Evento.
BBBB: Número de Semana (Desde el 6 de Enero de 1980 a las 00:00:00 hrs. UTC).
C: Día de la Semana (0 domingo).
DDDDD: Número de Segundos transcurridos en el día(UTC).
EEEEEEEE: Latitud (Grados decimales WGS-84).
FFFFFFFFF: Longitud (Grados decimales WGS-84)
GGG: Velocidad (MPH).
HHH: Rumbo (Grados sexagesimales).
J: Fuente de la última posición (0: 2D, 1: 3D, 9: No Fix).
K: Antigüedad del Mensaje (0: No disponible, 1: Mayor a 10 segundos, 2: Menor a 10 segundos).
<: Fin del Mensaje.
Un ejemplo de un mensaje TAIP es el siguiente:
>REV011779180540+1931046-0991095500000012<
Siguiendo la descripción anterior para este mensaje tenemos lo siguiente:
>: Inicio del Mensaje.
REV: Mensaje de Posición.
01: Evento 01.
1779: Semana 1,779 desde el 6 de Enero de 1980 a las 00:00:00 hrs. UTC.
1 : Lunes.
80540 : 80,540 segundos.
+1931046: Se divide entre 100,000 para obtener la latitud (19.31046).
-09910955: Se divide entre 100,000 para obtener la longitud (-99.10955).
000: 0 MPH.
000: Norte.
1: 3D.
2: Mensaje con menos de 10 segundos de antigüedad.
<: Fin del Mensaje.
Para obtener Hora GPS se propone seguir el siguiente procedimiento (se tomará el mensaje de ejemplo):
1) Dividir entre 60 el número de segundos para obtener los minutos:
80,540 seg = 1,342.3333 min
2) Separar la parte entera y la parte decimal:
Parte Entera = 1,342 min.
Parte Decimal = 0.33333333 min.
3) Multiplicar por 60 la parte decimal para obtener este dato en segundos:
0.33333333 min * 60 = 20 seg.
Con esto tenemos que: 80,540 seg = 1,342 min 20 seg.
4) Dividimos el número de minutos entre 60:
1,342 min = 22.366666666 hrs.
5) Separar la parte entera y la parte decimal:
Parte Entera = 22 hrs.
Parte Decimal = 0.36666666 hrs.
6) Multiplicar por 60 la parte decimal para obtener este dato en minutos:
0.36666666 hrs. * 60 = 22 min.
Con esto tenemos que: 80,540 seg = 1,342 min 20 seg = 22 hrs 22 min 20 seg, por lo que la hora UTC es 22:22:20 hrs. En el caso de México, la zona horaria es UTC -6, por lo que para obtener la hora local se deben restar 6 horas a esta hora, quedando como 16:22:20 hrs.
Computacionalmente el proceso de obtener la fecha resulta complicado, por lo que en el post siguiente daré una alternativa de cómo obtener las fechas y horas GPS de un Mensaje TAIP con C# de una forma rápida y sencilla.
miércoles, 15 de enero de 2014
Convertir tablas de InnoDB a MyISAM de una Forma rápida.
En ocasiones resulta de suma utilidad el convertir el engine de una tabla, ya sea por performance o por algún otro objetivo que se tenga en mente. Esta tarea no resulta sencilla cuando tenemos un gran número de tablas con engine InnoDB, puesto que existen dependencias con llaves de otras tablas, por lo que el proceso se vuelve largo y tedioso, pues se deben eliminar las llaves foráneas antes y posteriormente cambiar a MyISAM.
Una forma sencilla de hacer este cambio a gran escala es escribir una sentencia SQL que a su vez construya todas las consultas que nos permitirán hacer estos cambios.
La siguiente consulta nos da como resultado las consultas que se deberán ejecutar para eliminar todas las llaves foráneas de una Base de Datos específica, en este caso se deberán seleccionar sólo aquellas consultas que eliminen las llaves que se desean eliminar:
SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' drop foreign key ', CONSTRAINT_NAME,';') FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY' AND table_schema = 'NOMBRE_BD';
Después de eliminar las llaves foráneas, es posible hacer el cambio de engine de InnoDB a MyISAM, si se trata de muchas tablas podemos ejecutar una consulta que nos de como resultado las consultas necesarias para transformar cada tabla InnoDB a MyISAM y seleccionar las que sean útiles para ejecutarlas, para el caso esta es la consulta:
SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' engine=MyISAM;') FROM information_schema.tables WHERE engine = 'InnoDB' and table_schema = 'NOMBRE_BD';
lunes, 11 de noviembre de 2013
Convertir latlong GPRMC a grados decimales (WGS84).
Continuando con el post anterior resulta muy útil saber la forma de convertir las coordenadas GPRMC a un formato conocido como el que utilizan mapas como Here de Nokia o Google Maps. Retomando la trama GPRMC del post anterior ($GPRMC,055956.00,A,2029.49050,N,10316.32055,W,000.00,000.0,111113,08.0,E,D*27), tenemos la siguiente información para latitud: 2029.49050,N y para longitud tenemos: 10316.32055,W.
El proceso para obtener la latitud en grados decimales es el siguiente:
1.- Se divide la latitud entre 100, quedando como resultado 20.294905.
2.- Se obtiene la parte entera del resultado del punto anterior, en este caso sería 20.
3.- A la latitud original (2029.49050) se le resta la parte entera que se obtuvo en el punto anterior multiplicada por 100, dando como resultado 29.4905.
4.- El resultado del punto anterior se divide entre 60, quedando 0.4915083333333333.
5.- Se suman los resultados obtenidos del punto 2 (20) y del punto 4 (0.4915083333333333), resultando 20.49150833333333.
6.- Si el hemisferio es sur (S), el resultado del punto anterior se debe multiplicar por -1 para obtener la latitud, si el hemisferio es norte (N), la latitud es el valor obtenido en el punto 5.
El proceso para obtener la longitud en grados decimales es el siguiente:
1.- Se divide la longitud entre 100, quedando como resultado 103.1632055.
2.- Se obtiene la parte entera del resultado del punto anterior, en este caso sería 103.
3.- A la longitud original (10316.32055) se le resta la parte entera que se obtuvo en el punto anterior multiplicada por 100, dando como resultado 16.32055.
4.- El resultado del punto anterior se divide entre 60, quedando 0.2720091666666667.
5.- Se suman los resultados obtenidos del punto 2 (103) y del punto 4 (0.2720091666666667), resultando 103.2720091666667.
6.- Si el hemisferio es oeste (W), el resultado del punto anterior se debe multiplicar por -1 para obtener la longitud (-103.2720091666667), si el hemisferio es este(E), la longitud es el valor obtenido en el punto 5.
De acuerdo a lo anterior tenemos que latlong en grados decimales WGS84 es 20.49150833333333,-103.2720091666667.
El proceso para obtener la latitud en grados decimales es el siguiente:
1.- Se divide la latitud entre 100, quedando como resultado 20.294905.
2.- Se obtiene la parte entera del resultado del punto anterior, en este caso sería 20.
3.- A la latitud original (2029.49050) se le resta la parte entera que se obtuvo en el punto anterior multiplicada por 100, dando como resultado 29.4905.
4.- El resultado del punto anterior se divide entre 60, quedando 0.4915083333333333.
5.- Se suman los resultados obtenidos del punto 2 (20) y del punto 4 (0.4915083333333333), resultando 20.49150833333333.
6.- Si el hemisferio es sur (S), el resultado del punto anterior se debe multiplicar por -1 para obtener la latitud, si el hemisferio es norte (N), la latitud es el valor obtenido en el punto 5.
El proceso para obtener la longitud en grados decimales es el siguiente:
1.- Se divide la longitud entre 100, quedando como resultado 103.1632055.
2.- Se obtiene la parte entera del resultado del punto anterior, en este caso sería 103.
3.- A la longitud original (10316.32055) se le resta la parte entera que se obtuvo en el punto anterior multiplicada por 100, dando como resultado 16.32055.
4.- El resultado del punto anterior se divide entre 60, quedando 0.2720091666666667.
5.- Se suman los resultados obtenidos del punto 2 (103) y del punto 4 (0.2720091666666667), resultando 103.2720091666667.
6.- Si el hemisferio es oeste (W), el resultado del punto anterior se debe multiplicar por -1 para obtener la longitud (-103.2720091666667), si el hemisferio es este(E), la longitud es el valor obtenido en el punto 5.
De acuerdo a lo anterior tenemos que latlong en grados decimales WGS84 es 20.49150833333333,-103.2720091666667.
Parseo de una trama GPRMC.
Muchos dispositivos GPS transmiten tramas en el formato GPRMC, que es un formato creado por NMEA (National Marine electronics Association). La trama GPRMC contiene información acerca de la ubicación del dispositivo GPS y ciertas variables calculadas por los satélites GPS. Aunque puede variar un poco, la siguiente es una muestra de una trama GPRMC:
$GPRMC,055956.00,A,2029.49050,N,10316.32055,W,000.00,000.0,111113,08.0,E,D*27
Como se aprecia, la trama GPRMC separa la información por medio de comas, por lo que cada dato que se encuentra entre comas representa una variable calculada por los satélites GPS. A continuación desglosaré la trama anterior y diré el significado de cada parte de la trama:
$GPRMC - Esta variable indica el formato de la trama, en este caso es GPRMC.
055956.00 - Hora UTC en la que se obtuvo la posición del GPS (hhmmss).
A - Estatus de la trama A significa que es una trama válida, 9 que es una trama de caché y V significa que es una trama inválida.
2029.49050 - Latitud.
N - Hemisferio (N: Norte, S: Sur).
10316.32055 - Longitud.
W - Hemisferio (E: Este, W: Oeste).
000.00 - Velocidad en nudos.
000.0 - Rumbo en grados (0° a 360°).
111113 - Fecha UTC en la que se obtuvo la posición del GPS (DDMMAA).
08.0,E - Variación magnética.
D*27 - Checksum.
$GPRMC,055956.00,A,2029.49050,N,10316.32055,W,000.00,000.0,111113,08.0,E,D*27
Como se aprecia, la trama GPRMC separa la información por medio de comas, por lo que cada dato que se encuentra entre comas representa una variable calculada por los satélites GPS. A continuación desglosaré la trama anterior y diré el significado de cada parte de la trama:
$GPRMC - Esta variable indica el formato de la trama, en este caso es GPRMC.
055956.00 - Hora UTC en la que se obtuvo la posición del GPS (hhmmss).
A - Estatus de la trama A significa que es una trama válida, 9 que es una trama de caché y V significa que es una trama inválida.
2029.49050 - Latitud.
N - Hemisferio (N: Norte, S: Sur).
10316.32055 - Longitud.
W - Hemisferio (E: Este, W: Oeste).
000.00 - Velocidad en nudos.
000.0 - Rumbo en grados (0° a 360°).
111113 - Fecha UTC en la que se obtuvo la posición del GPS (DDMMAA).
08.0,E - Variación magnética.
D*27 - Checksum.
viernes, 8 de febrero de 2013
Como obtener el resultado de una consulta en MySQL como Cadena.
Hace un par de semanas me enfrenté con un pequeño problema que resolví de buena manera. Dicho problema fue el siguiente: Necesitaba obtener un reporte de todos los usuarios de un sistema, además de ello necesitaba obtener las fechas de inicio de sesión de cada usuario de los últimos 30 días. En pocas palabras, requería algo como lo siguiente:
-----------------------------------------------------------------
| Nombre de Usuario | Fechas de Inicio de sesión |
-----------------------------------------------------------------
| correo1@mail.com | 2012-15-24,2012-15-25,2012-15-26 |
| correo2@mail.com | 2012-15-20,2012-15-25,2012-15-27 |
| correo3@mail.com | 2012-15-24,2012-15-25,2012-15-26 |
| correo4@mail.com | 2012-15-24,2012-15-25 |
-----------------------------------------------------------------
Esto es un problema sencillo de resolver, bastaría con ejecutar 2 consultas y algo de programación. Pero es más rápido y eficiente ejecutar una sola consulta. Esto se podría hacer gracias a la función de MySQL GROUP_CONCAT, la cual permite obtener los resultados de una consulta como una cadena.
Para el caso de este problema supongamos que se tienen 2 tablas, una llamada Usuario con idUsuario(Pk) y nombreUsuario y la otra llamada AccessLog con idUsuario(Fk) y FechaInicio (Se que esta tabla debería llevar una llave primaria , pero para el ejemplo la omití). La tabla AccessLog almacena las fechas de inicio de sesión de los usuarios de los últimos 30 días.
La consulta para obtener la talba de arriba sería la siguiente:
SELECT Usuario.nombreUsuario AS Usuario,
GROUP_CONCAT(AccessLog.FechaInicio) AS Fechas
FROM Usuario, AccessLog
WHERE Usuario.idUsuario = AccessLog.idUsuario
Con esta consulta nos ahorramos hacer una consulta que traiga a todos los usuarios y otra que además por cada usuario traiga las fechas de inicio de sesión, aunado a los ciclos necesarios para construir la tabla de arriba.
viernes, 2 de noviembre de 2012
Correr Netcat en segundo plano y redirigir la salida a un archivo
Hace unos días me enfrenté con un problema que me dió verdaderos dolores de cabeza. Resulta que necesitaba escribir un socket TCP para conectarme a un servidor que envía información a todos los clientes que se conectan a el. Este cliente TCP debía estar siempre conectado y recibiendo información del Servidor. Yo por su parte debía redirigir la salida de dicho socket a un archivo para que después otro programa leyera dicho archivo y lo procesara. Para hacer el trabajo más ligero, decidí probar con telnet, pero se me presentaron algunos inconvenientes, así que decidí utilizar netcat.
Sentí una gran alegría al ver que netcat trabajaba muy bien. El problema era que tenía que mantener mí sesión SSH abierta para que mí socket siguiera funcionando, cosa que supuse era sencilla con el uso de nohup. Pero que sorpresa me llevé al ver que nohup no lograba poner a mí socket en segundo plano. Me la pase googleando y probando alternativas todo el día hasta que después de toda una jornada laboral de trabajo encontré la solución que es bastante sencilla:
Lo único que se debe hacer para correr netcat en segundo plano es añadir la opción -d, que le indica a netcat que no lea de la salida estándar (el teclado). Mí comando para correr netcat en segundo plano quedó como sigue:
nohup nc -d <IP Servidor> <Puerto Remoto> & >> archivo.log
Es importante señalar que esta solución funciona en un Ubuntu 11.10, no lo he probado en otras distribuciones de Linux ni en otras versiones de Ubuntu, pero me imagino que no debe haber mucha variación. Espero este texto sea de utilidad, ya que existe poca información acerca de como resolver este problema y la información que existe se encunetra en inglés.
Suscribirse a:
Entradas (Atom)