Archivo

Entradas Etiquetadas ‘caracteres’

Dialogando con HardwareSerial y SoftwareSerial más fácil

Lunes, 29 de Agosto de 2011 Gaspar Fernández Sin comentarios

A la hora de dialogar con los Serials en Arduino, durante estos días he desarrollado funciones para leer cadenas completas de texto desde el Serial y para escribir con la sintaxis de printf(), ya que esto es mucho más fácil cuando se trata de formatear texto.

Bien, ahora se trata de unirlo todo y de dar soporte a cualquier Serial, ya sea HardwareSerial o SoftwareSerial sin complicarnos mucho la vida, con la posibilidad de cambiar esta entrada/salida en cualquier momento y así hacer nuestro programa más flexible.

Para ello he creado la biblioteca SerialExt:
SerialExt.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef SERIALEXT_H
#define SERIALEXT_H

/* Quitar comentario si no vamos a usar SoftwareSerial, así
 reducimos un poco el tamaño del ejecutable. */

/* #define SEXT_NOSOFTWARESERIAL */

#include <WProgram.h>
#include <stdio.h>
#include <stdarg.h>

/* Si no vamos a usar el Software Serial, no creamos soporte para el */
#ifndef SEXT_NOSOFTWARESERIAL
#include <dynmem.h>
#include <SoftwareSerial.h>
#endif

class SerialExt
{
public:
  ~SerialExt();
  SerialExt(const HardwareSerial &serial, long bps=19200);
  #ifndef SEXT_NOSOFTWARESERIAL
  SerialExt(uint8_t rxp=2, uint8_t txp=3, long bps=19200);
  #endif
  int readString (char *str, unsigned size, const char *stop="\0");
  void printf(const char *fmt,...);
  // A veces, podemos necesitar esto desde fuera
  void serialPrint(const char *txt);
private:
  bool serialAvailable();
  int serialRead();
  HardwareSerial *hs;
  #ifndef SEXT_NOSOFTWARESERIAL
  SoftwareSerial *ss;
  #endif
  int timeout;
};

#endif

SerialExt.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "SerialExt.h"

void SerialExt::serialPrint(const char *txt)
{
  if (hs)
    hs->print(txt);
  #ifndef SEXT_NOSOFTWARESERIAL
  else
    ss->print(txt);
  #endif
}

void SerialExt::printf(const char *fmt,...)
{
  char tmp[128]; // resulting string limited to 128 chars
  va_list args;
  va_start (args, fmt );
  vsnprintf(tmp, 128, fmt, args);
  va_end (args);
  serialPrint(tmp);
}

SerialExt::SerialExt(const HardwareSerial &serial, long bps)
{
  hs=(HardwareSerial*)&serial;

  #ifndef SEXT_NOSOFTWARESERIAL
  ss=NULL;
  #endif
  timeout=3000000/(bps/8);  // ( 1000/(bps/8) ) * 1000 * 3.0 (milisegundos por signo por 1.5)
  // Initialize serial
  hs->begin(bps);
}

#ifndef SEXT_NOSOFTWARESERIAL
SerialExt::SerialExt(uint8_t rxp, uint8_t txp, long bps)
{
  ss=new SoftwareSerial(rxp, txp);
  hs=NULL;
  // Initialize serial
  ss->begin(bps);
}
#endif

SerialExt::~SerialExt()
{
  #ifndef SEXT_NOSOFTWARESERIAL
  if (ss)
    delete ss;
  #endif
}

// Sólo aplicable con HardwareSerial
bool SerialExt::serialAvailable()
{
  if (hs)
    return hs->available();
  else
    return true;
}

int SerialExt::serialRead()
{
  if (hs)
    hs->read();
  #ifndef SEXT_NOSOFTWARESERIAL
  else
    ss->read();
  #endif
}

int SerialExt::readString(char *str, unsigned size, const char *stop)
{
  unsigned i=0;
  char sIn;
  unsigned long m;
  // Queremos que la cadena se rellene hasta size-2 para que en el carácter
  // size-1 (el último) podamos meter el terminador \0
  --size;      
  while (serialAvailable() && i<size)
    {
      sIn=serialRead();
      if (strchr(stop, sIn))
    break;
      str[i++]=sIn;
      m=micros();
      while (!serialAvailable() && micros()<m+timeout);
    }
  str[i++]='\0';
  return i;
}

Esta biblioteca, hace uso de dynmem, para poder utilizar new y delete y crear el objeto SoftwareSerial. Aunque si no vamos a utilizar el Serial por Software, hay una directiva de pre-procesador (#define SEXT_NOSOFTWARESERIAL) que si quitamos el comentario no compilará nada del soporte, con lo que ahorraremos unos 600 bytes en el binario (que a veces, pueden salvarnos la vida).

Para probar la biblioteca, cargamos el siguiente programa de ejemplo:
serial1.h

1
2
3
4
5
6
7
/* En este archivo veremos la configuración de nuestro proyecto */

#define SERIAL_SPEED 19200
/* Led que queremos que parpadee mientras se ejecuta el programa */
#define STATUS_LED   11
/* Led que indica transferencia de datos */
#define BLINK_DELAY  500

serial1.pde:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// serial1
// Hace un eco con el puerto serie del Arduino
// Dialogamos con el Serial a través de la clase SerialExt. Desde aquí podremos dialogar
// con cualquier HardwareSerial o SoftwareSerial

#include "serial1.h"
#include <dynmem.h>
#include <SerialExt.h>
#include <SoftwareSerial.h>

#define MAX_BUFFER 100

// Almacenamos el estado como variable global
int estado=LOW;
// Almacenamos también el número de milisegundos anterior
unsigned long momento_anterior=0;
unsigned long bytes_recibidos=0;
// SerialExt SExt(Serial);

SerialExt *SExt;

void setup()
{
  // Queremos que un led parpadee mientras trabajamos
  pinMode(STATUS_LED, OUTPUT);
  digitalWrite(STATUS_LED, HIGH);
  delay(1000);
  digitalWrite(STATUS_LED, LOW);
  delay(1000);
  SExt = new SerialExt(Serial);
  digitalWrite(STATUS_LED, HIGH);
}

void loop ()
{  
  int recibe;
  unsigned long momento_actual=millis();
  char buf[MAX_BUFFER];
// No bloqueante, si hay algo para leer entramos, si no, no.
  if(Serial.available())
    {
      SExt->readString(buf, MAX_BUFFER);
      // Escribimos el buffer completo
      SExt->printf("Texto recibido: %s\n", buf);
    }
  // No usamos delay para el parpadeo porque nos entorpece la comunicación con el serial
  if (momento_actual-momento_anterior>=BLINK_DELAY)
    {
      // Cambiamos el estado siguiente. Si era HIGH (1) ahora será
      // LOW (0). He leído en algún lado que el valor de HIGH no
      // siempre es 1; pero en este caso sí es así.
      estado=!estado;
      // Escribimos el estado actual del led
      digitalWrite(STATUS_LED, estado);
      // Establecemos el momento anterior como actual.
      momento_anterior=momento_actual;
    }
}

Como vemos, SerialExt se encarga de hacer Serial.begin() y todo (tampoco es que sea gran cosa, pero nos ahorra una línea); en este ejemplo podemos ver cómo podemos intercambiar líneas completas de texto con Arduino a través del puerto serie.

Recopilación de soluciones para los retos de #tuentiContest . Challenge #18

Jueves, 30 de Junio de 2011 Gaspar Fernández Sin comentarios

Últimamente he hablado acerca del I concurso de programación de Tuenti. Un concurso de programación Online que se llevó acabo durante la semana pasada (del 13 al 20 de Junio, muy mala fecha).

Podéis ver los enunciados de todos los problemas, con ejemplos sobre la entrada y salida (aunque a veces no hay que hacerles mucho caso) en la web oficial del concurso, pero en Vidas Concurrentes lo encontramos todo en español.

Challenge #18 : The Riddle

Nos mandan una imagen en base64 por la stdin (ya lo toman como costumbre) y nos dan además, una adivinanza. Se trataba de extraer texto de la imagen, pero sólo de ciertas partes, es decir, teníamos que extraer la información por columnas, siempre que éstas no fueran verdes.
Soluciones:

Si no estás en la lista y quieres plantear tu solución, deja un comentario con tu link !

Actualización 2011/07/03 01:49 : Añadida solución de @frisco82
Actualización 2011/07/03 13:52 : Añadida solución de @Rosapolis

Separar palabras de una cadena de caracteres en un array [ C ]

Jueves, 2 de Diciembre de 2010 Gaspar Fernández Sin comentarios

Si conocéis PHP, habréis visto la función explode(). Tiene una utilidad curiosa, separa cadenas de caracteres en elementos de un array. Es como hacer un corte a la cadena cada vez que encontremos un carácter delimitador. Por ejemplo:

“Bienvenido al blog Poesía Binaria”, si usamos como delimitador ” ” (un espacio), los elementos del array quedarían así:

[0] = “Bienvenido”
[1] = “al”
[2] =”blog”
[3] =”Poesía”
[4] = “Binaria”

Pero en C, no encontramos ninguna función que haga esto, tenemos que currar un poco; aunque tenemos una función de string.h que hace algo que se parece en cierto modo: strtok(), esta función, va a separar una cadena en fragmentos modificando la propia cadena, es decir, introduciremos caracteres terminadores al final de cada palabra.

La solución intuitiva, sería hacer una copia en una variable de la original, y utilizar la copia para strtok() aunque el acceso a cada palabra no es tan flexible, es decir, strtok() nos devolverá un puntero a donde empieza la palabra, pero en cuanto queramos conocer la siguiente palabra que encontremos no podremos volver fácilmente a la anterior.

Por ello, planteo la siguiente solución:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#define MAX_CADENA 100

/**
 ******************************************************************
 * @brief Extrae palabras de una cadena y las coloca en un array
 *
 * @param orig     Cadena inicial
 * @param delim    Las palabras vendrán delimitadas por uno de los
 *                 caracteres de esta cadena            
 * @param args     Array donde separaremos cada palabra
 * @param max_args Número de palabras como máximo a extraer (tamaño
 *                 del array)
 *
 * @return Número de palabras extraídas. (max_args+1) si en la
 *         cadena hay más de max_args palabras.
 *
 ******************************************************************/

int extrae_argumentos(char *orig, char *delim, char args[][MAX_CADENA], int max_args)
{
  char *tmp;
  int num=0;
  /* Reservamos memoria para copiar la candena ... pero la memoria justa */
  char *str = malloc(strlen(orig)+1);
  strcpy(str, orig);

  /* Extraemos la primera palabra */
  tmp=strtok(str, delim);
  do
    {
      if (num==max_args)
    return max_args+1;  /* Si hemos extraído más cadenas que palabras devolvemos */
                /* El número de palabras máximo y salimos */

      strcpy(args[num], tmp);   /* Copiamos la palabra actual en el array */
      num++;

      /* Extraemos la siguiente palabra */
      tmp=strtok(NULL, delim);
    } while (tmp!=NULL);

  return num;
}

Con esta función ejecutaremos strtok para extraer palabras de una cadena, como máximo (max_args+1) veces. El objetivo es rellenar el Array, debido a las limitaciones de los Arrays tenemos que decir el número máximo de elementos que vamos a extraer, la cadena podrá tener 1000 palabras, pero si nuestro array sólo tiene capacidad para 10 no podremos extraer todo; y la función debe estar preparada para eso; por tanto cuando no hayamos podido extraer todo, devolveremos max_args+1, si todo va bien, devolveremos el número de palabras extraídas.

Lo curioso es que cambiando sólo una línea podemos hacer que admita en lugar de un array de cadenas de caracteres (char args[][MAX_CADENA]) un array de punteros de cadenas de caracteres (char *args[]) por lo que en cierto modo, depende del uso que vayamos a darle es algo más flexible, en este caso repartiremos en el array anterior los valores de las posiciones de memoria donde empieza cada palabra en la cadena copiada de la original:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int extrae_argumentos_d(char *orig, char *delim, char *args[], int max_args)
{
  char *tmp;
  int num=0;
  /* Reservamos memoria para copiar la candena ... pero la memoria justa */
  char *str = malloc(strlen(orig)+1);
  strcpy(str, orig);

  /* Extraemos la primera palabra */
  tmp=strtok(str, delim);
  do
    {
      if (num==max_args)
    return max_args+1;  /* Si hemos extraído más cadenas que palabras devolvemos */
                /* El número de palabras máximo y salimos */

      args[num]=tmp;            /* Copiamos la dirección de memoria tmp en args[num] */
      num++;

      /* Extraemos la siguiente palabra */
      tmp=strtok(NULL, delim);
    } while (tmp!=NULL);

  return num;
}

Ahora acompaño un programa para probar esto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_ARGS 90
#define MAX_CADENA 100

// Aquí copiamos extrae_argumentos o extrae_argumentos_d
int main()
{
  char cadena[]="Una ristra de palabras separadas por espacios";

  char args[MAX_ARGS][MAX_CADENA]; // Para extrae_argumentos
//  char *args2[MAX_ARGS];                  // Para extrae_argumentos_d

  int nargs = extrae_argumentos(cadena, " ", args, MAX_ARGS);
  int i;

  if (nargs>MAX_ARGS)
    {
      printf ("Se han devuelto más palabras del máximo\n");
      nargs=MAX_ARGS;
    }

  printf("CADENA: %s\n", cadena);
  for (i=0; i<nargs; i++)
    printf("Palabra %d: \"%s\"\n", i, args[i]);

  return 0;
}

Intercalar 2 ó más cadenas en PHP

Lunes, 9 de Agosto de 2010 Gaspar Fernández Sin comentarios

A la hora de crear un hash para una contraseña, es conveniente no incluir sólo la contraseña, sino concatenar una cadena o un número más; lo mismo cuando generamos claves para que interaccionen aplicaciones en varios servidores; aunque hay veces en que, dados los pocos datos de que disponemos a la hora de generar la clave, no tenemos mucho donde elegir a la hora de crear el hash.

Por ese motivo se me ocurrió esta función en PHP, lo que hace es intercalar cadenas, es decir, tenemos dos cadenas, y queremos generar una cadena a partir de las dos anteriores, podemos coger un carácter de una, otro de otra, y así sucesivamente (como si estuviéramos barajando) hasta formar una cadena cuya longitud es la suma de las dos. Por ejemplo si tenemos las palabras “poesia” y “binaria“, resultaría la cadena: pboiensairaia .

Aunque, ya que vamos a hacer algo así, ¿ por qué limitarlo ? Hagamos una función que soporte una cantidad indeterminada de cadenas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function intercalar($cadenas)
{
  $n_cadenas = count ($cadenas);

  if ($n_cadenas==1)        /* Si sólo hay una cadena, la devolvemos */
    return $cadenas[0];

  /* Contamos los caracteres de cada cadena y los almacenamos en un array */
  $chars_cadena=array();
  for ($i=0; $i<$n_cadenas; $i++)
    $chars_cadena[$i]=strlen($cadenas[$i]);

  $max_cadena = max ($chars_cadena); /* La cadena más larga determina cuándo paramos */
  $res='';
  /* Recorremos la longitud de cadena más larga */
  for ($j=0; $j<$max_cadena; $j++)
    {
      /* Recorremos todas las cadenas */
      for ($i=0; $i<$n_cadenas; $i++)
    {
      /* Si la cadena no está terminada añadiremos el carácter a la cadena */
      if ($j<$chars_cadena[$i])
        $res.=$cadenas[$i][$j];
    }
    }

  return $res;
}

echo intercalar (array("Poesia", "Binaria", "Blog", "Gaspar", "Programacion", "Software", "Libre"));

La cadena resultante de este ejemplo será: PBBGPSLoilaroienosofbsagpgtrirarweairaaamraecion.

Contar letras (caracteres) en EMACS

Miércoles, 14 de Abril de 2010 Gaspar Fernández Sin comentarios

letrasHay ocasiones en las que, cuando estamos escribiendo en nuestro editor de texto, necesitamos saber cuántas letras tiene un texto seleccionado.

Podemos hacerlo a la antigua usanza (la mayoría de los editores nos dicen el número de línea y carácter donde está el cursor, pues miramos al final del texto y al comienzo y restamos. Aunque emacs tiene un comando específico que nos hará esa tarea más fácil.

M-x count-lines-region

Nos devolverá el número de líneas y caracteres que tiene un texto seleccionado, como carácter se cuenta también el retorno de carro.

Por cierto, también dispone de tecla rápida: M-=

Foto: Laineys Repertoire (Flickr)

Categories: Emacs Tags: , , , ,

Funciones con nombres raros, y cortos (PHP, Javascript ,C)

Viernes, 12 de Marzo de 2010 Gaspar Fernández Sin comentarios

El objetivo de la programación, además de escribir poco (ya sabemos que todos los que programamos no queremos dejarnos las manos escribiendo), es hacer nuestro código mantenible, y para eso es necesario que nuestras funciones y métodos tengan nombres descriptivos.
Es decir, podemos definir 20 funciones: a(), b(), c(),… y mientras hacemos el programa tener un mapa mental de todas ellas, y utilizarlas, pero dentro de 6 meses, cuando vayamos a hacer la versión 2.0 de nuestro programa, ¿nos acordaremos de para qué valía cada función? Seguramente no; pero siempre que hacemos un for, lo más normal es escribir: “for (i=0;….”, “for (j=0;……)”, etc, eso sí que sale automático :)

Podemos, por ejemplo, tener nombres descriptivos, pero tal vez sean demasiado largos y muchos de ellos empezarán por las mismas letras, lo cual podemos considerarlo improductivo.

Si habéis curioseado prototype o JQuery, veréis cómo hay una llamada que se repite: $() y ella sola, con lo corta que es, hace maravillas para obtener objetos en Javascript. Los que hayan curioseado gettext recordarán la función _(), que sirve para traducir un mensaje. Estas funciones tienen en común que no vamos a parar de llamarlas en nuestros programas, sabemos lo que hacen y necesitamos una forma corta de llamarlas, ya que si desde nuestro programa llamamos a la función gettext() unas 2000 veces, estaríamos escribiendo 12000 caracteres de más, y en Javascript, si por ejemplo queremos llamar a document.getElementById(), con $() (no es lo único que hace) unas 60 veces, estaremos escribiendo unas 1320letras de más (y en Javascript eso se traduce en más transferencia por nuestra parte).

Pero cuando vamos a hacer una aplicación, todo se utiliza más o menos a un ritmo similar, aunque encontraremos tal vez funciones de formateo que llamemos constantemente, y esas funciones podrán tener un nombre raro que puede ser un símbolo. Pero con lo caprichosos que son los lenguajes de programación, ¿qué símbolos podemos utilizar? Deben ser caracteres con los que podamos empezar una función.
Aquí van algunos ejemplos para funciones PHP:

  • €();
  • ¡();
  • ç();
  • º();
  • ½();
  • _(); Pertenece a gettext
  • ł();
  • ¶();
  • ŧ();
  • ←();

C sólo permite el uso de _()

En Javascript, tenemos por ejemplo los siguientes:

  • $() Ojo con jquery y prototype
  • _()
  • º()
  • ª()
  • ß()
  • ð()
  • ŋ()
  • ħ()
  • ł()

Hay algunos más, pero no es plan de abusar, y no quiere decir que tenemos que usarlos, sólo que tenemos esa posibilidad; también muchos caracteres dependen de la codificación que utilicemos, por lo tanto pueden darnos ciertos problemas en el futuro (sobre todo en Javascript).

Visita otras webs de la red