Skip to content

Instantly share code, notes, and snippets.

@D3f0
Last active August 29, 2015 14:09
Show Gist options
  • Save D3f0/294caf0860231e8b17f8 to your computer and use it in GitHub Desktop.
Save D3f0/294caf0860231e8b17f8 to your computer and use it in GitHub Desktop.
Mara para Arduino
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"author": "Nahuel Defoss\u00e9",
"name": "",
"signature": "sha256:0e596bf855e85768efc0a387d0d9b12a21899d5a0bf935acbc171174cff0d802"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"%load_ext hierarchymagic"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Protocolo de Mara\n",
"\n",
"<img src=\"http://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Gro%C3%9Fer_Mara_0505273.jpg/250px-Gro%C3%9Fer_Mara_0505273.jpg\">\n",
"\n",
"# Estructura de una trama Mara\n",
"<table class=\"protocol\" style=\"text-align: center\">\n",
" <tr>\n",
" <td>Nombre</td>\n",
" <th>SOF</th><th>QTY</th><th>DST</th><th>SRC</th><th>SEQ</th><th>CMD</th><th>[PAYLOAD]</th><th>BCC H</th><th>BCC L</th>\n",
" </tr>\n",
" <tr>\n",
" <td>Significado</td>\n",
" <td>Inicio de trama</td>\n",
" <td>Longitud del trama</td>\n",
" <td>Direcci\u00f3n de destino</td>\n",
" <td>Direcci\u00f3n de origen</td>\n",
" <td>N\u00famero de secuencia</td>\n",
" <td>Comando</td>\n",
" <td>Carga \u00fatil</td>\n",
" <td>Suma de coprobaci\u00f3n byte alto</td>\n",
" <td>Suma de comprobaci\u00f3n byte bajo</td>\n",
" </tr>\n",
" <tr>\n",
" <td>Ejemplo</td>\n",
" <td>FE</td><td>08</td><td>01</td><td>40</td><td>80</td><td>10</td><td></td><td>80</td><td>A7</td>\n",
" </tr>\n",
"</table>\n",
"\n",
"## SOF\n",
"Comienzo de trama\n",
"\n",
"## QTY\n",
"Longitud total de la trama, en bytes, incluyendo el BCC H y L\n",
"\n",
"## DST\n",
"Direcci\u00f3n destino, en general `0xFF` es una direcci\u00f3 de broadcast.\n",
"\n",
"## SRC\n",
"Direcci\u00f3n de origen, generalmente no cambia y es la del ``master`` en la comunicaci\u00f3n.\n",
"\n",
"## SEQ\n",
"N\u00famero de secuencia, comienza en ``0x00`` y llega hasta ``0xAA``\n",
"\n",
"## CMD\n",
"N\u00famero de comando. Los comandos pueden ser con o sin respuesta. Los comandos que sean enviados con ``DST == 0xFF`` nunca tienen respuesta.\n",
"\n",
"### Nota\n",
"\n",
"Cuando hablemos de n\u00fameros hexadecimales utilizaremos la notaci\u00f3n de C/C++, que consiste en anteponer un ``0x`` al n\u00famero, adem\u00e1s se rellenar\u00e1 con un 0 si el nibble alto es 0. Por ejemplo, el n\u00famero 10 se escribe ``0x0A``."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%dot -f svg\n",
"digraph G {\n",
" WAIT_SOF -> WAIT_QTY [label=\"Rx byte == SOF\"];\n",
" WAIT_SOF -> WAIT_SOF [label=\"Rx byte != SOF\"];\n",
" WAIT_QTY -> WAIT_SOF [label=\"Rx byte < 5\"];\n",
" WAIT_QTY -> WAIT_FRAME_QTY [label=\"*\"];\n",
" WAIT_FRAME_QTY -> WAIT_SOF [label=\"received == QTY\"];\n",
" WAIT_FRAME_QTY -> WAIT_FRAME_QTY [label=\"received < QTY\"];\n",
"\n",
"\n",
"}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"396pt\" height=\"218pt\"\n",
" viewBox=\"0.00 0.00 396.10 218.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 214)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-214 392.105,-214 392.105,4 -4,4\"/>\n",
"<!-- WAIT_SOF -->\n",
"<g id=\"node1\" class=\"node\"><title>WAIT_SOF</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"123.913\" cy=\"-192\" rx=\"56.59\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"123.913\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">WAIT_SOF</text>\n",
"</g>\n",
"<!-- WAIT_SOF&#45;&gt;WAIT_SOF -->\n",
"<g id=\"edge2\" class=\"edge\"><title>WAIT_SOF&#45;&gt;WAIT_SOF</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M175.13,-199.794C188.43,-199.315 198.458,-196.717 198.458,-192 198.458,-188.573 193.164,-186.264 185.168,-185.074\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"185.394,-181.581 175.13,-184.206 184.791,-188.555 185.394,-181.581\"/>\n",
"<text text-anchor=\"middle\" x=\"245.458\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">Rx byte != SOF</text>\n",
"</g>\n",
"<!-- WAIT_QTY -->\n",
"<g id=\"node2\" class=\"node\"><title>WAIT_QTY</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"114.913\" cy=\"-105\" rx=\"58.4896\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"114.913\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">WAIT_QTY</text>\n",
"</g>\n",
"<!-- WAIT_SOF&#45;&gt;WAIT_QTY -->\n",
"<g id=\"edge1\" class=\"edge\"><title>WAIT_SOF&#45;&gt;WAIT_QTY</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M68.2661,-188.784C44.8276,-184.747 19.6209,-175.656 4.91329,-156 -11.6582,-133.853 18.0248,-121.255 50.7096,-114.246\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"51.7629,-117.606 60.9016,-112.245 50.4147,-110.737 51.7629,-117.606\"/>\n",
"<text text-anchor=\"middle\" x=\"53.4133\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">Rx byte == SOF</text>\n",
"</g>\n",
"<!-- WAIT_QTY&#45;&gt;WAIT_SOF -->\n",
"<g id=\"edge3\" class=\"edge\"><title>WAIT_QTY&#45;&gt;WAIT_SOF</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M116.732,-123.175C117.963,-134.806 119.617,-150.419 121.026,-163.734\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"117.558,-164.223 122.092,-173.799 124.52,-163.486 117.558,-164.223\"/>\n",
"<text text-anchor=\"middle\" x=\"154.913\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">Rx byte &lt; 5</text>\n",
"</g>\n",
"<!-- WAIT_FRAME_QTY -->\n",
"<g id=\"node3\" class=\"node\"><title>WAIT_FRAME_QTY</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"179.913\" cy=\"-18\" rx=\"96.3833\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"179.913\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">WAIT_FRAME_QTY</text>\n",
"</g>\n",
"<!-- WAIT_QTY&#45;&gt;WAIT_FRAME_QTY -->\n",
"<g id=\"edge4\" class=\"edge\"><title>WAIT_QTY&#45;&gt;WAIT_FRAME_QTY</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M127.755,-87.2067C137.131,-74.9464 150.002,-58.1143 160.613,-44.2391\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"163.581,-46.119 166.876,-36.0493 158.021,-41.8668 163.581,-46.119\"/>\n",
"<text text-anchor=\"middle\" x=\"154.913\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">*</text>\n",
"</g>\n",
"<!-- WAIT_FRAME_QTY&#45;&gt;WAIT_SOF -->\n",
"<g id=\"edge5\" class=\"edge\"><title>WAIT_FRAME_QTY&#45;&gt;WAIT_SOF</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M187.913,-36.0863C199.5,-63.5841 217.167,-118.375 193.913,-156 189.035,-163.894 181.777,-170.067 173.757,-174.875\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"172.049,-171.819 164.831,-179.574 175.31,-178.013 172.049,-171.819\"/>\n",
"<text text-anchor=\"middle\" x=\"255.913\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">received == QTY</text>\n",
"</g>\n",
"<!-- WAIT_FRAME_QTY&#45;&gt;WAIT_FRAME_QTY -->\n",
"<g id=\"edge6\" class=\"edge\"><title>WAIT_FRAME_QTY&#45;&gt;WAIT_FRAME_QTY</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M268.01,-25.3828C283.399,-24.3984 294.105,-21.9375 294.105,-18 294.105,-14.9854 287.829,-12.8362 277.981,-11.5527\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"278.293,-8.06666 268.01,-10.6172 277.64,-15.0361 278.293,-8.06666\"/>\n",
"<text text-anchor=\"middle\" x=\"341.105\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">received &lt; QTY</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
]
}
],
"prompt_number": 11
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Esto conforma un aut\u00f3mata finito con transiciones lambda, por lo tanto no determinista.\n",
"A\u00fan as\u00ed es implementable. \n",
"Cabe aclarar que lo que se recive entre el estado WAIT_QTY y las iteraciones en WAIT_FRAME_QTY es el [PDU](http://es.wikipedia.org/wiki/Unidad_de_datos_de_protocolo) con el checksum (BCC)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A partir de este aut\u00f3mata y vali\u00e9ndonos de que Arduino utiliza un compilador de C++, podemos generar una clase que se encarge de recibir los paquetes del protocolo."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"! mkdir -p src"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file src/mara.cpp\n",
"// Algunas definiciones\n",
"\n",
"#ifndef __AVR_ATmega328P__\n",
"// Para emular un puerto serial de arduino compilando sobre x86\n",
"// creamos la siguente clase\n",
"class Serial {\n",
" public:\n",
" static int write(int) {\n",
"\n",
" }\n",
" static int \n",
"\n",
"}\n",
"#endif\n",
"\n",
"#define SOF 0xF0\n",
"#define MIN_QTY 8\n",
"#define MAX_PKG_LEN 256\n",
"#define MAX_CMD_OP 128\n",
"\n",
"#define GET_CMD( arr ) (arr[5])\n",
"\n",
"class MaraServer {\n",
" private:\n",
" char _buffer[MAX_PKG_LEN];\n",
" char _index; // Indice en el buffer\n",
" bool (*_cmdCallbacks[MAX_CMD_OP])(char, char*);\n",
" char _remainingQty; // Longitud que queda de lectura de trama luego de encontrar QTY\n",
" public:\n",
" /**\n",
" * Estado del aut\u00f3mata de entrada\n",
" */\n",
" enum MaraInputState {\n",
" WAIT_SOF,\n",
" WAIT_QTY,\n",
" WAIT_FRAME_QTY\n",
" } _state;\n",
" // Constructor \n",
" MaraServer() {\n",
" _state = WAIT_SOF;\n",
" _index = 0;\n",
" _remainingQty = 0;\n",
" // Inicializaci\u00f3n en 0 del arreglo\n",
" for (int i=0; i<MAX_CMD_OP; i++) {\n",
" _cmdCallbacks[i] = (bool (*)(char, char*))0;\n",
" }\n",
" }\n",
" // Acepta un byte\n",
" void receiveByte(char byte) {\n",
" switch (_state) {\n",
" case WAIT_SOF:\n",
" if (byte == SOF) {\n",
" _state = WAIT_QTY;\n",
" _buffer[_index++] = byte;\n",
" }\n",
" break;\n",
" case WAIT_QTY:\n",
" if (byte >= MIN_QTY && byte <= MAX_PKG_LEN) {\n",
" _state = WAIT_FRAME_QTY;\n",
" _buffer[_index++] = byte;\n",
" _remainingQty = byte - 2; // Para control m\u00e1s tarde\n",
" }\n",
" break;\n",
" case WAIT_FRAME_QTY:\n",
" _buffer[_index++] = byte;\n",
" _remainingQty--;\n",
" if (_remainingQty == 0) {\n",
" executeCommand();\n",
" _state = WAIT_SOF;\n",
" }\n",
" break;\n",
" \n",
" }\n",
" \n",
" }\n",
" // Realiza la operaci\u00f3n registrada para el comando\n",
" void executeCommand(void) {\n",
" // Hay handler registrado?\n",
"\n",
" }\n",
" // Registra una funci\u00f3n que atiende un comando\n",
" void onCommand(char command, bool (*funptr)(char, char *)) {\n",
" _cmdCallbacks[command] = funptr;\n",
" }\n",
" \n",
"};\n",
"\n",
"int main(void) {\n",
" MaraServer server;\n",
" //server.receiveByte();\n",
"}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting src/mara.cpp\n"
]
}
],
"prompt_number": 62
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!gcc src/mara.cpp -o mara"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 63
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!gist -d \"Mara para Arduino\" \"Mara para Arduino.ipynb\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"https://gist.github.com/294caf0860231e8b17f8\r\n"
]
}
],
"prompt_number": 67
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!gist -u https://gist.github.com/294caf0860231e8b17f8 \"Mara para Arduino.ipynb\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"https://gist.github.com/294caf0860231e8b17f8\r\n"
]
}
],
"prompt_number": 69
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment