Mostrando las entradas con la etiqueta linux. Mostrar todas las entradas
Mostrando las entradas con la etiqueta linux. Mostrar todas las entradas

sábado, 15 de octubre de 2016

Emacs Lisp - Función/comando para reemplazar coincidencias de texto.

Una de las grandes ventajas de la utilización del editor Gnu Emacs es su capacidad para extender las funciones del mismo editor a través de elisp.

 Para empezar a adentrarme en el lenguaje, decidí escribir una pequeña función que me ayudara a rápidamente cambiar todas las coincidencias de una cadena de texto en un buffer.  A continuación, explico como lograr esto de manera sencilla.

Funciones y sus argumentos.
Para definir una función en elisp, usamos la siguiente palabra (o símbolo, para ser más correcto según lisp):

defun 

Simplemente una abreviación de "define function". Este símbolo le dice a lisp, que el consecuente código dentro de la lista definida sea enlazado a otro símbolo: el nombre de nuestra función. Por ejemplo:

(defun suma (x y)
      (+ x y)
) 

¿Qué hace esta función? Es simple. Toma dos argumentos recibidos y los suma. En otras palabras, enlaza el símbolo "suma" con el código consecuente dentro de la función, el de la suma.
Ahora bien, observemos que después de la definición del nombre de la función viene otra lista. Esta es la lista de los parametros a usar en nuestro función y que deben ser pasados al momento de llamarla. Por ejemplo, evaluemos la siguiente función:

(suma 3 4)

Deberá imprimirse en nuestro mini-buffer el número 7.

La función interactive.

La función interactive hace que nuestra función pueda volverse un comando (pueda ser llamada con M-x/alt-x). Distintos argumentos dados a nuestra función, le dan distintos comportamientos a la llamada de nuestro comando/función.
Para nuestro caso, usaremos el argumento "s", como argumento de interactive. Este argumento, leerá del minibuffer y lo guardará en nuestra lista de argumentos dados a la función.

La función save-excursion.
Esta función nos permitirá guardar la posición actual del cursor (su punto, de acuerdo a la terminología de emacs). Esto debido a que mientras cuando se haga la búsqueda y reemplazo, el punto/point/cursor estará moviendose a través de todo el texto. Para evitar que, al usar la función, nos deje en donde no estabamos colocados usamos save-excursion.

La función beginning-of-buffer.
Retorna el cursor al principio del buffer.

re-search-forward, regexp-quote y replace-match.
Estas tres funciones son las que harán el trabajo fuerte de nuestro comando. 
re-search-forward nos moverá a través de las coincidencias del texto, como un puntero. Al ser llamada, regresará la ubicación de la coincidencia, en la siguiente iteración nos dará la siguiente coincidencia.
regexp-quote: Le daremos un string de argumento y nos retornará la forma de evaluar el string como si fuera una expresión regular.
replace-match: La llamamos para reemplazar la coincidencia que teníamos con re-search-forward dandole el string a reemplazar.

 Nuestra función: replace-all-ins-of.


(defun replace-all-inst-of (x y)
  ;; pregunta por los argumentos
  (interactive "sSearch (with regexp): \nsReplace: ")
  (save-excursion ;; guardar el actual punto
    (beginning-of-buffer) ;; moverse al principio del buffer 
    ;; Empezar la busqueda hacia adelante
    (while (re-search-forward (regexp-quote x) nil t)
      (replace-match y))
    )
  )

Evaluamos la función al ponernos al final de la misma y haciendo Ctrl-x CTRL-e. Esto también agregará nuestra función a los comandos de emacs.
Finalmente para probar la función, hacemos M-x replace-all-inst-of o ALT-x replace-all-inst-of.
Cabe destacar que para "instalar" de forma permanente nuestra función como un comando necesitamos guardarlo en nuestro archivo de inicio .emacs. De esta manera, siempre estará disponible en las siguientes sesiones de nuestro editor.

lunes, 24 de agosto de 2015

Encender y apagar un led con Android y Raspberry Pi

Hace poco pude hacerme con un dispositivo Android y decidí empezar a sacarle un poco de jugo. A continuación, les muestro y explico, lo más claro posible, el resultado.

Objetivo:
Comunicar un dispositivo Android y una Raspberry Pi por medio de sockets para encender y apagar un led a través de la red local usando.

Materiales:
- 1 LED
- Raspberry Pi [Cualquier modelo]
- Resistor 330 Ohms
- Protoboard
- Jumper Hembra Macho [para la conexión Raspberry Pi a protoboard]

Breve explicación:
El método usado para la comunicación entre los dispositivos esta vez fueron los sockets.
La Raspberry Pi corre un pequeño script en python que está a la espera de una conexión entrante, que en nuestro caso sería el dispositivo Android. Cuando recibe una conexión, la RPi crea un nuevo socket, un canal de comunicación, donde recibe un caracter enviado por el dispotivo Android. Hay dos posibles caracteres que pueden ser enviados, 'A' o 'B'. Si se recibe A, el LED enciende; con B, éste se apaga.

En la aplicación en Android, tenemos tres elementos sencillos: dos campos de texto y un botón. El primero para la IP de la RPi, el segundo para el puerto (Nota: El número de puerto debe ser el mismo que el declarado en el script de la RPi, y se recomienda uno que sea distinto a los reservados para otras conexiones. En este caso, yo opté por el puerto 1000) y, finalmente, el botón de On/Of. Este botón es el encargado de llamar a la función que tratará de conectarse a la RPi y enviar los datos. El socket se destruye al finalizar la comunicación, así que cada vez que presionamos el botón se crea uno nuevo.

Ejemplo de uso:


Esquemático y conexiones:
No he podido crear un esquemático por falta de tiempo, en cuánto pueda lo haré.

El LED se conecta al resistor de 330 Ohms y ésta está conectada al GPIO 17 de la RPi, el número de pin puede ser cambiado por cualquier otro disponible. El cátodo del LED se conecta a algún pin GND de la RPi.

Esquemático de GPIO:
http://www.peatonet.com/wp/wp-content/uploads/2014/08/PinoutRaspberry-1.jpeg 

Proyecto en Android Studio:
1. Crea una nuevo proyecto en Android Studio que tenga una actividad en blanco. Elige el SDK al que quieras compilar la aplicación.

2. Modifica el AndroidManifest.xml agregando los siguientes permisos:

<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>

3. Modifica el archivo xml de tu actividad prinicipal de la siguiente forma:
<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"  android:layout_width="match_parent" android:layout_height="match_parent"  android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"  tools:context=".Main" android:id="@+id/relativeLayout"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Introduzca la ip" android:inputType="numberDecimal" android:digits="0123456789." android:id="@+id/editText1" /> <EditText android:id="@+id/editText2" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Introduzca el puerto" android:inputType="number" android:layout_below="@+id/editText1" android:layout_alignParentStart="true" /> <Button style="?android:attr/buttonStyleSmall" android:layout_width="200dp" android:layout_height="wrap_content" android:text="On/Off" android:id="@+id/buttonLed" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="201dp" android:onClick="togLed" /> </RelativeLayout>


4.  Modifica tu actividad principal con el siguiente código:
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Main extends ActionBarActivity {
    private LedToggle ledToggle;
    private boolean ledState = true;
    private Button button;
    private EditText ipText;
    private EditText portText;
    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.buttonLed);
        ipText = (EditText) findViewById(R.id.editText1);
        portText = (EditText) findViewById(R.id.editText2);
        }

    @Override    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void togLed(View view) {
        try {
            String ipAddr = ipText.getText().toString();
            int nPuerto = Integer.parseInt(portText.getText().toString());
            if (ledState == false) ledState = true;
            else ledState = false;
            ledToggle = new LedToggle(ipAddr, nPuerto);
            ledToggle.execute(ledState);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

5. Crea una nueva clase que será el controlador encargado de enviar los datos y pedir conexión a la RPi, llamada LedToggle. Esta clase extiende de AsyncTask, para poder manejar la petición en un hilo distinto al principal.

import android.os.AsyncTask;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/** * */public class LedToggle extends AsyncTask<Boolean, Void, Void>{
    private Socket socket = null;
    private OutputStream outputStream = null;
    private String sockeAdd = null;
    private int portNum;

    public LedToggle(String s, int p) {
        sockeAdd = s;
        portNum = p;
    }

    @Override    protected Void doInBackground(Boolean... params) {
        try {
            socket = new Socket(sockeAdd, portNum);
            outputStream = socket.getOutputStream();

            if(params[0] == true)
                outputStream.write('A');
            else                outputStream.write('B');
            outputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}

6. El siguiente script de python debe estar corriendo en la Raspberry Pi.




Más adelante escribiré un post explicando más a detalle los temas. Cualquier duda, sugerencia o comentario son bienvenidos :-D

Interviewbit Question - Solución al problema de la potencia de dos enteros.

Este es un problema de tipo entrevista, encontrado en interviewbit.com. El problema nos menciona que debemos encontrar si dada una entr...