3. Código fuente

Anuncio
Titulació:
Enginyeria Industrial (pla 2003)
Alumne (nom i cognoms):
Marcelo Germán López Pérez
Títol PFC:
Proyecto de diseño de una red inalámbrica de sensores de bajo coste
Director del PFC:
David González Diez
Convocatòria de lliurament del PFC:
2014/15 Q1
Contingut d’aquest volum:
-CÓDIGO FUENTE-
Índice de contenido
1.
Nodo sensor .......................................................................................... 3
2.
Programa de volcado de datos ................................................................ 8
2
1. Nodo sensor
A continuación se muestra el código programado en Arduino para el nodo sensor.
Este programa sirve de base para que los usuarios puedan realizar sus propias
aplicaciones.
/*
Programa del nodo sensor desarrollado para la Wireless Sensor
Network
Proyecto de diseño de una red inalámbrica de sensores de bajo
coste
PFC - ETSIAT - UPC
Desarrollado por: Marcelo Germán López Pérez
Septiembre 2014
*/
#include <avr/sleep.h>
#include <avr/power.h>
uint8_t
addr[10]={0x00,0x13,0xA2,0x00,0x40,0xBA,0xBC,0x78,0x00,0x00};//64b
its+16bits addresses
bool COM=false;//SI EL NODO SE TRABA SE PUEDE REINICIAR EL XBee de
forma remota con el comando FR
bool sent=false;
uint8_t value[5]={0,0,0,0,0};
uint32_t time;
uint16_t frecuencia=5000;
void pin2Interrupt(void)
{
/*Función ejecutar al despertarse el nodo
La primera acción es desactivar la interrupción
Para evitar que salte continuamente.*/
detachInterrupt(0);
}
void enterSleep(void)
{
/* setear la interrupción en el pin2*/
attachInterrupt(0, pin2Interrupt, LOW);
delay(100);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
/* El nodo se irá a dormer aquí */
3
/*tras despertarse y quitar la interrupción
Lo siguiende es deshabilitar el sleep mode*/
sleep_disable();
}
void setup() {
Serial.begin(9600);
pinMode(2,INPUT);
}
void loop() {
//SI EL XBEE SE ENCUENTRA ENCENDIDO, CONECTADO A LA RED Y NO SE
HAN ENVIADO DATOS TODAVIA
if(digitalRead(2)==LOW && COM==true && sent==false){
//forma alternativa si el nodo no duerme
//if(COM==true && (millis()-time)>frecuencia){
//incluir aquí las funciones para realizar mediciones en los
sensores y enviar los datos a través de la red
time=millis();
sent=true;//CONFIRMAR CON TX_STATUS
}
//SI la radio se ha apagado, sent y entrar en modo sleep
else if(digitalRead(2)==HIGH){
sent=false;
enterSleep();
}
}
void serialEvent(){
uint8_t frame_type;
int packet_length;
if(Serial.available()>4){//si se reciben más de cuatro
bytes:delimiter, length y frame type
if(Serial.read()==0x7E){
packet_length=Serial.read();
packet_length=packet_length*256+Serial.read();
frame_type=Serial.read();
//modificar el número de bytes de Serial_wait se acuerdo a
la longitud recibida
switch(frame_type){
case 0x8B:
if(serial_wait(packet_length)==true)tx_status();
break;
case 0x90:
if(serial_wait(packet_length)==true)rx_packet(packet_length);
break;
case 0x8A:
if(serial_wait(packet_length)==true)modem_status();
break;
default:break;
}
}
}
}
4
//funcion necesaria para evitar leer más rapido de lo que el
buffer se llena
//se podría eliminar aumentadno la velocidad del UART
bool serial_wait (uint8_t data_size){//cuidado con la declaracion
de variable porque packet_length es int
uint32_t timeout;
timeout=millis();
while(Serial.available()<data_size && (millis()-timeout)<1000){}
if(Serial.available()>=data_size)return true;
else return false;
}
void rx_packet(int packet_size){
uint8_t payload[packet_size-12];
uint8_t check=0x90;
for(uint8_t i=0;i<11;i++)check+=Serial.read();//no importa de
quien viene la instruccion ni otras caracteristicas sólo se leen
los 11 bytes para el checksum
for(uint8_t i=0;i<sizeof(payload);i++){
payload[i]=Serial.read();
check+=payload[i];
}
check+=Serial.read();//sumar checksum
if(check==0xFF){
switch (payload[0]){
case 0x01: //incluir sensores sucseptibles de enviar
mediciones por solicitud
break;
case 0x02: //incluir actuadores susceptibles de ser
comandados de forma remota
break;
case 0x03: //incluir parámetros suceptibles de ser
modificados de forma remota
break;
default: break;
}
}
}
void tx_status(){
uint8_t tx_status[7];
uint8_t check=0x8B;
for(uint8_t i=0;i<sizeof(tx_status);i++){
tx_status[i]=Serial.read();
check+=tx_status[i];
}
if(check==0xFF){
if(tx_status[4]==0x00);//éxito al enviar mensaje posible
acción a tomar
}
}
void modem_status(){
uint8_t modem_status[2];
uint8_t check=0x8A;
for(uint8_t i=0;i<sizeof(modem_status);i++){
modem_status[i]=Serial.read();
5
check+=modem_status[i];
}
if(check==0xFF){ //checksum incorrecta desde el modem: 0xFF
if(modem_status[0]==0x02) COM=true;//radio confirma que está
conectada a la red
else if(modem_status[0]==0x03)COM=false;//radio confirma que s
eha desconectado de la red
}
}
void tx_request(uint8_t *rfdata, int datasize){
uint8_t frame_type=0x10;
uint8_t frame_ID=0x01;
uint8_t broad_radius=0x00;
uint8_t options=0x00;
uint8_t checksum=0xFF;
//1xframetype, 1xframeid, 8x64bitaddr, 2x16bitaddr,
1xbroadcastradio, 1xoptions
int packet_lenght=14+datasize;
//cálculo del checksum
int sum=frame_type+frame_ID+broad_radius+options;
for(uint8_t i=0; i<10; i++){sum+=addr[i];}
for(uint8_t i=0; i<datasize;i++){sum+=rfdata[i];}
checksum-=lowByte(sum);
//transmisión del marco
Serial.write(0x7E);
Serial.write(highByte(packet_lenght));
Serial.write(lowByte(packet_lenght));
Serial.write(frame_type);
Serial.write(frame_ID);
for(uint8_t i=0; i<10;i++)Serial.write(addr[i]);
Serial.write(broad_radius);
Serial.write(options);
for(uint8_t i=0; i<datasize;i++)Serial.write(rfdata[i]);
Serial.write(checksum);
}
void ftohex (float number, uint8_t result [5]){
uint16_t aux;
if(number<0){
result[0]=0x01;
number=abs(number);//eliminar el signo
}
else result[0]=0x00;
aux=number;//extraemos parte entera
result[1]=highByte(aux);
result[2]=lowByte(aux);
//extraer la parte decimal
number=number-aux;
//A será inferior al número máximo para 16 bits 2^16=65536
//tambien el decimal debe ser mayor a 0, sino se quedaria en el
bucle tener en cuenta los bits!!!
while(number<6553.6 && number>0)number=number*10;
aux=number;
result[3]=highByte(aux);
result[4]=lowByte(aux);
}
6
float hextof(uint8_t data [5]){
int entero=data[1] <<8 +data[2];
float decimal=data[3] <<8 +data[4];
while (decimal>1) decimal=decimal/10;
float val=(data[0]*(-2)+1)*(entero+decimal);
return val;
}
7
2. Programa de volcado de datos
A continuación se muestra el código del programa desarrollado en Processing
para la recogida y el almacenamiento de los datos provenientes de la red,
generación de gráficos y comandos de actuación.
/*
Programa de procesado de datos para Wireless Sensor Network
Proyecto de diseño de una red inalámbrica de sensores de bajo
coste
PFC - ETSIAT - UPC
Desarrollado por: Marcelo Germán López Pérez
Septiembre 2014
*/
import processing.serial.*;
Serial port;
PFont font;
Table table;
Table rxdata;
Table gdata;
//variables del sistema
int active_menu=0;
//SON STRINGS porque las rutas van en string pero representan
numeros hex porque es lo que se recibe el Xbee
String active_node="";
String active_device="";
String active_parameter="";
String title;
String title2;
int dia=day();
String fecha=Date();
MenuButtons [] botones=new MenuButtons[5];
Parameter list=new Parameter(100, 500);
Graphic show;
MenuButtons [] points=new MenuButtons[3];//botones del gráfico
//variables para actuación
MenuButtons send;
DragButton command;
boolean cmd=false;
byte [] value=new byte[5];
// variables para tratamiento de datos rx
boolean header=false;
int frame_type;
8
int packet_length;
byte check=0;
//variables para la edicion de la red
boolean updated=false;
boolean prop=false;
int active_ID=0;
int active_prop=1;
MenuButtons [] edit=new MenuButtons[3];//botones del edit chart
TextLine edit_ID=new TextLine("ID", 30, 50, 72);
TextLine edit_name=new TextLine("Name", 120, 50, 72);
Options edit_role=new Options("","", 42,85);
//variables auxiliares para edicion
ElementButton auxiliar=new ElementButton("", "", 0, 0, 0);
String [] aux={"","","","","","",""};
void setup() {
size(1024, 700);
port=new Serial(this,Serial.list()[0], 9600);
port.buffer(4);//ejecutar serialevent() si se reciben más de
cuatro bytes:delimiter, length y frame type
//new_node();//si los archivos existen no hace falta crearlos
//se puede disminuir el frameRate para disminuir el trabajo del
procesador
frameRate(15);
smooth();
font = loadFont("Tahoma-36.vlw");
textFont(font);
//cargar los nodos de la red
table= new Table();
rxdata=new Table();
gdata=new Table();
table=loadTable("data/Network.csv","header");//se necesita como
minimo el coordinador en la lista para que el programa funcione.
//crear los archivos de volcado de datos para todos los
dispositivos de la red
Filesgen();
//iniciar botones del menu
botones[0]=new MenuButtons(width*9/10, height*19/20, 0);
botones[1]=new MenuButtons(width*8/10, height*19/20, 1);
botones[2]=new MenuButtons(width/20, height/20, 2);
botones[3]=new MenuButtons(width/20, height*2/20, 3);
botones[4]=new MenuButtons(width*9/10, height/20, 4);
//iniciar botones del edit chart
edit[0]=new MenuButtons(60,110, 5);
edit[1]=new MenuButtons(32,140, 5);
edit[2]=new MenuButtons(120,140, 5);
edit[0].name="<- Place label";
edit[1].name="OK";
edit[2].name="Cancel";
9
//inciar el gráfico
show=new Graphic(width/2, height*2/5, 600, 320);
points[0]=new MenuButtons(width/20, height/2, 5);
points[1]=new MenuButtons(width/20, height/2+30, 5);
points[2]=new MenuButtons(width/20, height/2+60, 5);
points[0].name="Show all";
points[1].name="+50";
points[2].name="-50";
//variables para enviar comando
send=new MenuButtons(width*2/3, 550, 5);
send.name="Send command";
command=new DragButton(1, width*2/3, 500, 0, 1, 0, "default",
"none" );
}
void draw(){
ElementButton device=new ElementButton("", "", 0, 0, 0);
background(204);
fill(0);
textSize(24);
textAlign(CENTER,CENTER);
//network nemu
if(active_menu==0){
text("XBee Network", width/2, 24);
for(int i=0;i<table.getRowCount();i++){
device.get_device(i);//recupera la información del nodo en
la fila i
device.draw_label();
}
for(int
i=0;i<botones.length;i++)if(i!=1)botones[i].draw_label();
}
//node menu
else if(active_menu==1){
text("Active node:"+title, width/2, 24);
for(int i=0;i<table.getRowCount();i++){
device.get_device(i);
device.draw_label();
}
for(int i=1;i<botones.length;i++)botones[i].draw_label();
}
//device menu
else if(active_menu==2){
text("Active device:"+title, width/2, 24);
text("Active parameter:"+title2, width/2, 48);
textSize(14);
if(show.fix==true)text("showing: "+show.N+" points", width/2,
96);
else text("showing all points ("+gdata.getRowCount()+")",
width/2, 96);
if(botones[2].state==false && botones[3].state==false &&
gdata.getRowCount()>0)show.draw_graph();//dibujar si no estamos en
modo edicion
10
list.draw_header();
for(int i=0; i< table.getRowCount(); i++){
list.get_line(i);
list.draw_line();
}
for(int i=1;i<botones.length;i++)botones[i].draw_label();
for(int i=0;i<points.length;i++)points[i].draw_label();
if(cmd==true){
command.draw_drag();
send.draw_label();
}
}
else active_menu=0;
//edit mode
if(botones[2].state==true || botones[3].state==true) {
if(active_menu==0 || active_menu==1){
if(edit[0].state==true) {
auxiliar.pos_x=mouseX;
auxiliar.pos_y=mouseY;
}
auxiliar.draw_label();
}
else{
if (botones[2].state==true){
int h=list.position[1]+20*(1+table.getRowCount());
fill(0);
textAlign(CENTER, CENTER);
text(aux[0],list.position[0],h);//ID
text(aux[1],list.position[0]+40,h);//name
text(int(aux[2]),list.position[0]+80,h);//type
text(aux[3],list.position[0]+120,h);//unit
text(int(aux[4]),list.position[0]+160,h);//min
text(int(aux[5]),list.position[0]+200,h);//max
text(int(aux[6]),list.position[0]+240,h);//default
fill(255);
ellipse(list.position[0]-20,h,10,10);
fill(0);
ellipse(list.position[0]-20,h,5,5);
textAlign(LEFT);
}
list.edit_header();
}
edit_chart();
}
}
//Funciones para las comunicaciones
//Recepcion de datos por el puerto USB
void serialEvent (Serial port){
if(header==false && port.read()==0x7E){
header=true;
packet_length=port.read();
packet_length=packet_length*256+port.read();
frame_type=port.read();
check=byte(frame_type);
}
11
else if(header==true && port.available()>=packet_length){
byte[] inBuffer = new byte[packet_length];
port.readBytes(inBuffer);
for(int i=0;i<packet_length;i++)check+=inBuffer[i];
if(check==-1){
switch(frame_type){
case 0x8B: //if(inBuffer[4]==0)println("success");
//else println("fail");
break;
case 0x90: rx_packet(inBuffer);
break;
case 0x8A: modem_status(inBuffer[0]);
break;
default:
break;
}
}
else println("rx_ERROR");
header=false;
//while(port.available()>0)println(port.readBytes());
}
}
//procesado de datos recibidos
void rx_packet(byte rfdata[]){
String hora=Time();
//dirección de origen
String
node=hex(rfdata[4])+hex(rfdata[5])+hex(rfdata[6])+hex(rfdata[7]);
//tipo de mensaje
int type=int(rfdata[11]);
//dispositivo de origen
int device=int(rfdata[12]);
if (dia!=day()){
dia=day();
fecha=Date();
Filesgen();
}
//si es un mensaje de medicion
if (type==0x01){
//al paquete recibido le restamos la dirección, las opciones,
el checksum, el dispositivo y el tipo de dato y nos quedan las
mediciones
int messurements=(packet_length-14)/5;
float [] values=new float[messurements];
for(int i=0; i<messurements; i++){
int position=13+5*i;
int sign=int(rfdata[position])*(-2)+1;
int
entero=int(rfdata[position+1])*256+int(rfdata[position+2]);
float
decimal=float(rfdata[position+3])*256+int(rfdata[position+4]);
while (decimal>1) decimal=decimal/10;
values[i]=sign*(entero+decimal);
}
//guardar las mediciones
12
rxdata=loadTable("data/"+fecha+"/"+node+"/"+hex(device,2)+".csv",
"header");
TableRow newRow = rxdata.addRow();
newRow.setString(0, hora);
for (int i=0; i<messurements; i++){
newRow.setFloat(i+1, values[i]);
}
saveTable(rxdata,
"data/"+fecha+"/"+node+"/"+hex(device,2)+".csv");
//cargar el nuevo punto en la tabla del grafico requiere
enviar todos los parámetros de un sensor en un mismo mensaje
if(active_menu==2){
if(unhex(active_node)==unhex(node) &&
unhex(active_device)==device){
//cargar la medida para el parámetro en gráfico
show.new_point(hora, values[int(active_parameter)-1],
int(active_parameter));
/*esta estructura obliga a enviar las medidas en el
mismo orden en que se han creado
los parametros y en que estarán las columnas de las
tablas de datos*/
//mostrar últimas medidas
for(int i=0; i<messurements; i++) table.setString(i, 7,
hora+" --> "+values[i]);
}
}
}
}
void tx_request(byte []command, int
commandsize){//http://stackoverflow.com/questions/12020344/passing
-an-array-to-a-function-and-using-sizeof-in-arduino
byte frame_type=byte(0x10);
int lowint=unhex(active_node);
byte [] addr={byte(0), byte(19), byte(162), byte(0), 0, 0, 0, 0,
byte(255), byte(254)};//0013A200+ low part+ 16 bit unknown
//pasar el string para formar la direccion
for(int i=0; i<4; i++)addr[7-i]=byte(lowint >>8*i);
byte frame_ID=byte(0x01);
byte broad_radius=byte(0x00);
byte options=byte(0x00);
byte checksum=byte(0xFF);
byte [] payload=new byte[2+commandsize+2];//getrowcount()
payload[0]=byte(0x02);
payload[1]=byte(int(active_device));
int position=2;
for(int i=0; i<table.getRowCount(); i++){
if(i!=int(active_parameter)-1){
payload[position]=-1;//byte(0xFF)
position++;
}
13
else{
for(int j=0; j<commandsize;
j++)payload[position+j]=command[j];
position+=5;
}
}
//1xframetype, 1xframeid, 8x64bitaddr, 2x16bitaddr,
1xbroadcastradio, 1xoptions
int packet_lenght=14+payload.length;
int sum=frame_type+frame_ID+broad_radius+options;
for(int i=0; i<10; i++){sum+=int(addr[i]);}
for(int i=0; i<payload.length;i++)sum+=int(payload[i]);
checksum-=byte(sum);
/*println(hex(0x7E, 2));
println(hex(packet_lenght >> 8, 2));
println(hex(packet_lenght, 2));
println(hex(frame_type));
println(hex(frame_ID));
for(int i=0; i<10;i++)println(hex(addr[i]));
println(hex(broad_radius));
println(hex(options));
for(int i=0; i<payload.length;i++)println(hex(payload[i]));
println(hex(checksum));*/
port.write(byte(0x7E));
port.write(byte(packet_lenght >> 8));
port.write(byte(packet_lenght));
port.write(frame_type);
port.write(frame_ID);
for(int i=0; i<10;i++)port.write(addr[i]);
port.write(broad_radius);
port.write(options);
for(int i=0; i<payload.length;i++)port.write(payload[i]);
port.write(checksum);
}
void modem_status(byte status){
if (int(status)==0x00)println("dispositivo reiniciado");
else if(int(status)==0x06)println("coordinador iniciado");
}
// Funciones relacionadas con el teclado y el ratón
void mouseReleased(){
int i=0;
boolean pressed=false;
ElementButton device=new ElementButton("", "", 0, 0,
0);//inciado necesario
if(mouseButton==LEFT){
//network menu
if(active_menu==0){
//comprobar dispositivos en pantalla
while(i<table.getRowCount() && pressed==false){
device.get_device(i);
pressed=device.over();
14
if(pressed==true && (botones[2].state==false &&
botones[3].state==false))device.action();
else if(pressed==true && botones[3].state==true){
active_node=device.ID;//seleccionar nodo a editar
active_ID=i;//dispositivo activo correspondiente al que
se encuentra en la fila i de la tabla
updated=false;
}
else i++;
}
if(pressed==false){
i=0;
//comprobar botones del menu en pantalla
while(i<botones.length && pressed==false){
pressed=botones[i].over();
if(pressed==true && (botones[2].state==false &&
botones[3].state==false))botones[i].action();
else i++;
}
}
}
//node menu
else if(active_menu==1){
//comprobar dispositivos en pantalla
i=1; //ignorar la radio
while(i<table.getRowCount() && pressed==false){
device.get_device(i);
pressed=device.over();
if(pressed==true && (botones[2].state==false &&
botones[3].state==false))device.action();
else if(pressed==true && botones[3].state==true){
active_device=device.ID;//seleccionar dispositivo a
editar
active_ID=i;//dispositivo activo correspondiente al que
se encuentra en la fila i de la tabla
updated=false;
}
else i++;
}
if(pressed==false){
i=0;
//comprobar botones en pantalla
while(i<botones.length && pressed==false){
pressed=botones[i].over();
if(pressed==true && (botones[2].state==false &&
botones[3].state==false))botones[i].action();
else i++;
}
}
}
//device menu
else {
while (i<table.getRowCount() && pressed==false &&
botones[2].state==false){
pressed=list.over(i);
if(pressed==true && (botones[2].state==false &&
botones[3].state==false))list.action(i);
else if(pressed==true && botones[3].state==true){
15
active_parameter=table.getString(i,0);//seleccionar
dispositivo a editar
active_ID=i;//dispositivo activo correspondiente al que
se encuentra en la fila i de la tabla
updated=false;
}
else i++;
}
if(pressed==false){
i=0;
//comprobar botones en pantalla
while(i<botones.length && pressed==false){
pressed=botones[i].over();
if(pressed==true && (botones[2].state==false &&
botones[3].state==false))botones[i].action();
else i++;
}
}
//comprobar botones graph
if(pressed==false){
i=0;
//comprobar botones en pantalla
while(i<points.length && pressed==false){
pressed=points[i].over();
if(pressed==true && i==0)show.fix=!show.fix;
//se limita a 500 el número de puntos en pantalla
else if(pressed==true && i==1 &&
show.N<500)show.N=show.N+50;
else if(pressed==true && i==2 &&
show.N>50)show.N=show.N-50;
else i++;
}
if(pressed==true){
gdata=loadTable("data/"+fecha+"/"+active_node+"/"+active_device+".
csv", "header");
//eliminar línea por defecto
String [] m1=match(gdata.getString(0, 0),"del");
if(m1!=null)gdata.removeRow(0);
gdata.addColumn("Y");
show.column=int(active_parameter);
if (gdata.getRowCount()>0)show.prepare_data();
}
}
if(pressed==false && cmd==true){
pressed=send.over();
if(pressed==true){
ftohex(command.value, value);
tx_request(value, value.length);
}
}
}
//edit mode active
if (botones[2].state==true || botones[3].state==true){
if(active_menu==0 || active_menu==1){
if(edit[0].over()==true)edit[0].state= !edit[0].state;//activar
place device
16
else if (edit[0].state==true &&
edit[1].over()==false)edit[0].state=false;//situar nodo
}
else {
i=1;
while(i<7 && pressed==false){//se puden modificar 7
propiedades
pressed=list.over_prop(i);
if(pressed==true){
active_prop=i;
prop=false;
}
else i++;
}
}
//over ID TextLine
if(edit_ID.over()==true) edit_ID.active=true;
else edit_ID.active=false;
//over Name TextLine
if(edit_name.over()==true) edit_name.active=true;
else edit_name.active=false;
//option selected
edit_role.over();
if (edit[1].over()==true && edit[0].state==false) {//guardar
cambios
close_edit();
botones[2].state=false;
botones[3].state=false;
edit_ID.word="";
}
else if (edit[2].over()==true) {//cancelar cambios
botones[2].state=false;
botones[3].state=false;
edit_ID.word="";
}
}
}
}
void mouseDragged(){
if(command.over()==true)command.action();
}
void keyTyped() {
if(edit_ID.active==true)edit_ID.type();
else if(edit_name.active==true)edit_name.type();
}
//Funciónes relacionadas con el modo de edición
//función del cuadro de edición
void edit_chart(){
ElementButton device=new ElementButton("", "", 0, 0, 0);
rectMode(CORNER);
fill(204);
rect(10,10,200,150);
fill(0);
17
textSize(14);
text("Edition chart", 75,30);
//dibujar botones del chart
for (int i=0; i<edit.length; i++)edit[i].draw_label();
//menus de la red o del nodo
if(active_menu==0 || active_menu==1){
if(botones[3].state==true && updated==false){//actualizar el
chart si seleccionamos un nodo diferente del actual
device.get_device(active_ID);
updated=true;
//obtener propiedades del dispositivo seleccionado
auxiliar.ID=device.ID;
auxiliar.name=device.name;
auxiliar.role=device.role;
auxiliar.pos_x=device.pos_x;
auxiliar.pos_y=device.pos_y;
//pasarlas para que sean dibujadas en el chart
edit_ID.word=auxiliar.ID;
edit_name.word=auxiliar.name;
edit_role.current=boolean(auxiliar.role-1-2*active_menu);
}
if(active_menu==0){//dibujar edit_role
edit_role.names[0]="Router";
edit_role.names[1]="End. dev";
auxiliar.role=int(edit_role.current)+1;
}
else if(active_menu==1){
edit_role.names[0]="Sensor";
edit_role.names[1]="Actuator";
auxiliar.role=int(edit_role.current)+3;
}
edit_ID.draw_text();//dibujar lineas de texto
edit_name.draw_text();
edit_role.draw_options();
auxiliar.ID=edit_ID.word;
auxiliar.name=edit_name.word;
}
//menu del dispositivo
else{
if(botones[3].state==true && updated==false){// si se cambia
se parámetro
//cargar el parámetro a modificar
aux[0]=table.getString(active_ID, 0);//ID
aux[1]=table.getString(active_ID, 1);//name
aux[2]=str(table.getInt(active_ID, 2));//type
aux[3]=table.getString(active_ID, 3);//units
aux[4]=str(table.getInt(active_ID, 4));//min
aux[5]=str(table.getInt(active_ID, 5));//max
aux[6]=str(table.getInt(active_ID, 6));//default
//actualizar propiedad actual
edit_ID.word=aux[0];
edit_name.word=aux[active_prop];
updated=true;
}//si se cambia de propiedad del parámetro
else if(prop==false){
edit_name.word=aux[active_prop];
prop=true;
}
18
edit_ID.draw_text();
edit_name.draw_text();
aux[0]=edit_ID.word;
aux[active_prop]=edit_name.word;
}
}
//Función encargada de guardar los cambios del modo de edición
void close_edit(){
ElementButton device=new ElementButton("", "", 0, 0, 0);
//modificar nodo
if(active_menu==0){
if(botones[2].state==true){//if add node
if(edit_ID.word!=""){//si nuevo nodo, agregar linea en la
tabla y crear archivo de dispositivos del nodo
TableRow newRow = table.addRow();
newRow.setString(0, auxiliar.ID);//ID
newRow.setString(1, auxiliar.name);
newRow.setInt(2, auxiliar.pos_x);//X
newRow.setInt(3, auxiliar.pos_y);//Y
newRow.setInt(4, auxiliar.role); //ROLE
saveTable (table,"data/Network.csv");
//crear archivo de devices del nuevo nodo
String [] new_node={"ID,name,X,Y,role",
auxiliar.ID+","+auxiliar.name+","+str(width/2)+","+str(height/2)+"
,"+str(auxiliar.role) };
saveStrings("data/nodes/"+auxiliar.ID+"/devices.csv",
new_node);
//crear archivo de estado de comandos de la nueva radio en
el nodo
String [] new_radio={"command,value,,,,,,",
"SH,0013A200,,,,,,",
"SL,"+auxiliar.ID+",,,,,,",
"ID,2014,,,,,,",
"AP,1,,,,,,",
"SM,0,,,,,,",
"SP,3E8,,,,,,",
"ST,1388,,,,,,",
"SN,1,,,,,,",
"SO,00,,,,,,"};
saveStrings("data/nodes/"+auxiliar.ID+"/"+auxiliar.ID+".csv",
new_radio);
}
}//if edit node
else{
if(edit_ID.word=="" && active_ID!=0 ){//delete node
table.removeRow(active_ID);
saveTable (table,"data/Network.csv");
active_ID=0;//para reiniciar
}
else if (edit_ID.word!=""){//condicion para poder modificar
el nodo coordinador
//modificar tabla de nodos
table.setString(active_ID, 0, auxiliar.ID);//ID
table.setString(active_ID, 1, auxiliar.name);
table.setInt(active_ID, 2, auxiliar.pos_x);//X
table.setInt(active_ID, 3, auxiliar.pos_y);//Y
19
if(active_ID!=0) table.setInt(active_ID, 4,
auxiliar.role); //ROLE
saveTable (table,"data/Network.csv");
//cargar y modificar la tabla de dispositivos del nodo
//primera linea corespondiente a la radio del nodo
//si se cambia el nombre no podrá cargar el archivo del
nodo, por eso cargamos el String active_node
table.clearRows();
table=loadTable("data/nodes/"+active_node+"/devices.csv","header")
;
table.setString(0,0, auxiliar.ID);//ID
table.setString(0,1, auxiliar.name);//name
//no se modifica la posición del nodo en el menu del nodo
//table.setInt(0,"X", auxiliar.pos_x);
//table.setInt(0,"Y", auxiliar.pos_y);
if(active_ID!=0) table.setInt(0,"role", auxiliar.role);
saveTable
(table,"data/nodes/"+auxiliar.ID+"/devices.csv");
//volver a cargar los nodos de la red, se podrían utilizar
dos tablas
table.clearRows();
table=loadTable("data/Network.csv","header");
}
}
}
//modificar dispositivo
else if(active_menu==1){
if(botones[2].state==true){//if add device
if(edit_ID.word!=""){
//modificar la tabla del nodo activo
TableRow newRow = table.addRow();
newRow.setString(0, auxiliar.ID);//ID
newRow.setString(1, auxiliar.name);//name
newRow.setInt(2, auxiliar.pos_x);//X
newRow.setInt(3, auxiliar.pos_y);//Y
newRow.setInt(4, auxiliar.role);//ROLE
saveTable
(table,"data/nodes/"+active_node+"/devices.csv");
//crear archivo del device S o A y el primer parametro
//columna last no imprescindible
String []
new_node={"ID,name,type,unit,min,max,default,last",
"01,default,0,0,0,0,0,0"};
saveStrings("data/nodes/"+active_node+"/"+auxiliar.ID+".csv",
new_node);
//crear el archivo de datos para el parámetro por defecto
que se crea con el dispositivo
String [] header={"time,01", "del,0"};
saveStrings("data/"+fecha+"/"+active_node+"/"+auxiliar.ID+".csv",
header);
}
}//if edit node
else{
20
//delete node
if(edit_ID.word=="" && active_ID!=0 ){
table.removeRow(active_ID);
saveTable
(table,"data/nodes/"+active_node+"/devices.csv");
active_ID=0;
}
else if(edit_ID.word!="") {
//modificar tabla del nodo
table.setString(active_ID, 0, auxiliar.ID);//ID
table.setString(active_ID, 1, auxiliar.name);//name
table.setInt(active_ID, 2, auxiliar.pos_x);//X
table.setInt(active_ID, 3, auxiliar.pos_y);//Y
if(active_ID!=0) table.setInt(active_ID, 4,
auxiliar.role); //ROLE
saveTable
(table,"data/nodes/"+active_node+"/devices.csv");
//cargar y modificar la tabla de dispositivos del nodo
//primera linea corespondiente a la radio del nodo
//si se cambia el nombre no podrá cargar el archivo del
dispositivo, por eso cargamos el String active_device
table.clearRows();
table=loadTable("data/nodes/"+active_node+"/"+active_device+".csv"
,"header");
table.setString(0, 0, auxiliar.ID);//ID
table.setString(0, 1, auxiliar.name);//name
//no se modifica la posición del nodo en para el menu 1
//table.setInt(0,"X", auxiliar.pos_x);//no se modifica la
posición del nodo en para el menu 1
//table.setInt(0,"Y", auxiliar.pos_y);
saveTable
(table,"data/nodes/"+active_node+"/"+auxiliar.ID+"/devices.csv");
//volver a cargar los nodos de la red, se podrían utilizar
dos tablas
table.clearRows();
table=loadTable("data/nodes/"+active_node+"/devices.csv","header")
;
}
}
}
//modificar parametro
else{
if(botones[2].state==true){
//modificar la tabla del nodo activo
TableRow newRow = table.addRow();
newRow.setString(0, hex(table.getRowCount(), 2));//ID de
la fila a la que corresponde
newRow.setString(1, aux[1]);//name
newRow.setInt(2, int(aux[2]));//type
newRow.setString(3, aux[3]);//unit
newRow.setInt(4, int(aux[4]));//min
newRow.setInt(5, int(aux[5]));//max
newRow.setInt(6, int(aux[6]));//default
newRow.setString(7, "");//last
21
saveTable
(table,"data/nodes/"+active_node+"/"+active_device+".csv");
//crear columna en la tabla graph y guardar la nueva tabla
/*puede tardar dependiendo del numero de puntos que haya,
aunque en general se hará al momento de configurar el dispositivo
por lo que no habrá que considerar muchos puntos,
posiblemente*/
String []
head=loadStrings("data/"+fecha+"/"+active_node+"/"+active_device+"
.csv");
head[0]="time";
head[1]="del";
for(int i=0; i<table.getRowCount(); i++){
head[0]+=","+table.getString(i, 0);
head[1]+=",0";
}
saveStrings("data/"+fecha+"/"+active_node+"/"+active_device+".csv",
head);
}
else {
//delete parametro
/*if(edit_ID.word=="" && active_ID!=0 ){
table.removeRow(active_ID);
saveTable
(table,"data/nodes/"+active_node+"/"+active_device+".csv");
active_ID=0;
//no se borraran los datos captados, al ser borrado de la
tabla no se creará la columna en los siguientes archivos
}
un parametro no se podrá eliminar,´sólo editar su definicion.
porque esto está relacionado por como se reciben los datos desde
el Arduino.
Para eliminar el parámetro habrá que modificar la
programación del MCU y eliminar la fila directamente desde el
archivo devices, si procede
Esto es como medida de seguridad
*/
//else if(edit_ID.word!="") {
//modificar tabla del nodo
//table.setString(active_ID, 0, aux[0]);//ID del
dispositivo definida por su posicion en la tabla
table.setString(active_ID, 1, aux[1]);//name
table.setInt(active_ID, 2, int(aux[2]));//type
table.setString(active_ID, 3, aux[3]);//unit
table.setInt(active_ID, 4, int(aux[4]));//min
table.setInt(active_ID, 5, int(aux[5]));//max
table.setInt(active_ID, 6, int(aux[6]));//default
saveTable
(table,"data/nodes/"+active_node+"/"+active_device+".csv");
//si la ID editada es diferente de la existente, habrá que
modificar la tabla de datos
/*String [] m1=match(active_parameter, aux[0]);
if(m1==null);{
String []
head=loadStrings("data/"+fecha+"/"+active_node+"/"+active_device+"
.csv");
head[0]="time";
22
for(int i=0; i<table.getRowCount(); i++){
head[0]+=","+table.getString(i, 0);
}
saveStrings("data/"+fecha+"/"+active_node+"/"+active_device+".csv",
head);
}*/
/*si se modifica la ID de un parámetro, habrá que cargar
la tabla de datos actual, guardarla con otra nombre y
crear un nuevo archivo de datos con los nuevos nombres a
aplicar en que se almacenarán los datos a partir de ahora.
*/
/*editar la ID de los prametros de un sensor se realizará
al realizar la configuracion del dispositivo
esto significa que todavía no se encontrará activo o
estará en proceso de activarse y comenzar a funcionar.
Por ello, se puede abrir el archivo de datos en un String
para modificar la cabecera*/
//}
}
}
}
//A continuación se definen todos las clases diseñadas
específicamente para el programa
//Linea de texto
class TextLine{
String name;
String word="";
int [] position=new int[2];
boolean active=false;
int h=20;
int size;
TextLine (String tempname, int X, int Y, int tempW){
name=tempname;
position[0]=X;
position[1]=Y;
size=tempW;
}
void type(){
if(key==8){
word="";
}
else if(key==10)active=false;
else {
if(textWidth(word)<(size-textWidth(key))){
word+=char(key);
//word=word.toUpperCase();
}
}
}
void draw_text(){
stroke(0);
23
rectMode(CORNER);
strokeWeight(1);
fill(255);
rect(position[0],position[1],size,h);
fill(0);
textSize(h*3/5);
textAlign(LEFT, CENTER);
text(word, (position[0]+h/4),(position[1]+h/2));
textSize(h*3/5);
text(name, position[0], position[1]-h/4);
}
boolean over(){
if(mouseX>position[0] && mouseX<(position[0]+size) &&
mouseY>position[1] && mouseY<(position[1]+h))return true;
else return false;
}
}
//Opciones disyuntivas
class Options{
String[] names=new String[2];
int [] position= new int[2];
boolean current=false;
int size=12;
int distance=size*6;
Options(String op1, String op2, int X, int Y){
names[0]=op1;
names[1]=op2;
position[0]=X;
position[1]=Y;
}
void draw_options(){
stroke(0);
fill(255);
ellipse(position[0], position[1], size,size);
ellipse(position[0]+distance, position[1], size,size);
fill(0);
if(current==false)ellipse(position[0], position[1],
size/2,size/2);
else ellipse(position[0]+distance, position[1],
size/2,size/2);
textSize(size);
textAlign(LEFT, CENTER);
text(names[0], position[0]+size, position[1]);
text(names[1], position[0]+size+distance, position[1]);
}
void over(){
if (dist(mouseX, mouseY, position[0], position[1]) <
size*0.5){
current=false;
}
else if (dist(mouseX, mouseY, position[0]+distance,
position[1]) < size*0.5){
24
current=true;
}
}
}
//Botón de nivel de parámetro para comandos de actuación
class DragButton{
int ID;
int[] position= new int[2];
float[] range= new float[2];
float current;
float value;//adaptar a cada sensor
String name;
String unit;
int size=20;
DragButton(int tempID, int tempX, int tempY, int min, int max,
int tempC, String tempName, String tempU){
ID=tempID;
position[0]=tempX;
position[1]=tempY;
range[0]=min;
range[1]=max;
value=tempC;
current=int(map(value,range[0],range[1],position[0],position[0]+si
ze*10));//adaptar a cada sensor
name=tempName;
unit=tempU;
}
void action(){
if(mouseX<position[0])current=position[0];
else
if(mouseX>(position[0]+size*10))current=position[0]+size*10;
else current=mouseX;
if(range[1]-range[0]==1){
if(mouseX>(position[0]+size*5))value=range[1];
else value=range[0];
}
else
value=map(current,position[0],position[0]+size*10,range[0],range[1
]);
}
void draw_drag(){
ellipseMode(CENTER);
strokeWeight(4);
stroke(0);
line(position[0],position[1],position[0]+size*10,position[1]);
strokeWeight(1);
fill(150);
ellipse(current,position[1], size,size);
fill(0);
textSize(size*3/5);
text(name+": "+str(int(value))+" "+unit, position[0],
position[1]-size);
25
}
boolean over(){
float d = dist(mouseX, mouseY, current,
position[1]);//análisis de posición del raton
if (d < size*0.5) return true;//size es el diametro del
circulo
else return false;
}
}
//Gráficos de datos
class Graphic{
int[] position=new int[2];
int[] size=new int[2];
float[] limits_y=new float[2];
String[] limits_x=new String[2];
boolean fix=true;
int N=50;
int column;
Graphic(int tempX, int tempY, int tempW, int tempH){
position[0]=tempX;
position[1]=tempY;
size[0]=tempW;
size[1]=tempH;
}
void prepare_data(){//cada vez que cambie fix se ejecutará esta
función
float y;
//si hay mas filas al numero indicado eliminar las sobrantes
if (fix==true && gdata.getRowCount()>N)
while(gdata.getRowCount()>N)gdata.removeRow(0);
//determinar un maximo y minimo para empezar
limits_y[0]=gdata.getFloat(0, column);
limits_y[1]=gdata.getFloat(0, column);
//determinar limites en y
for(int i=1; i<gdata.getRowCount(); i++){
if(gdata.getFloat(i,
column)<limits_y[0])limits_y[0]=gdata.getFloat(i, column);
else if(gdata.getFloat(i,
column)>limits_y[1])limits_y[1]=gdata.getFloat(i, column);
}
//determinar limites en X
limits_x[0]=gdata.getString(0,0);
limits_x[1]=gdata.getString(gdata.getRowCount()-1,0);
for(int i=0; i<gdata.getRowCount(); i++){
y=map(gdata.getFloat(i, column), limits_y[0], limits_y[1],
size[1]*0.025, size[1]*0.975);
gdata.setFloat(i, "Y", y);
}
}
void new_point(String time, float val, int col){
float y;
//agregar nueva fila
TableRow newRow = gdata.addRow();
26
newRow.setString(0, time);
newRow.setFloat(1, val);
//si se supera el máximo de filas permitido
if(fix=true && gdata.getRowCount()>N){
y=gdata.getFloat(0, col);
gdata.removeRow(0);
//determinar los extremos de la nueva tabla
//la longitud de la tabla no será considerable, por lo que
el tiempo no será excesivo (200 puntos max) pero se ha limitado
igualmente
if(int(y)==limits_y[0] || int(y)==limits_y[1] ||
val<limits_y[0] || val>limits_y[1]){
float min=gdata.getFloat(0, col);
float max=gdata.getFloat(0, col);
for(int i=1; i<gdata.getRowCount(); i++){
if(gdata.getFloat(i, col)<min)min=gdata.getFloat(i,
col);
else if(gdata.getFloat(i, col)>max)max=gdata.getFloat(i,
col);
}
//si los extremos son diferentes a los existentes,
establecer los nuevos y recalcular las "Y" de los otros puntos
if(min!=limits_y[0] || max!=limits_y[1]){
limits_y[0]=min;
limits_y[1]=max;
for(int i=0; i<gdata.getRowCount()-1; i++){
y=map(gdata.getFloat(i, col), limits_y[0], limits_y[1],
size[1]*0.025, size[1]*0.975);
gdata.setFloat(i, "Y", y);
}
}
}
limits_x[0]=gdata.getString(0,0);
}
// si no hay un máximo de filas definido
else{
//si el nuevo punto supera los extremos
if(val<limits_y[0] || val>limits_y[1]){
//establecer los nuevos limites
if (val<limits_y[0]) limits_y[0]=val;
else limits_y[1]=val;
//recalcular las "Y" de los otros puntos
for(int i=0; i<gdata.getRowCount()-1; i++){// la última
fila corresponde al punto nuevo que se realiza debajo
y=map(gdata.getFloat(i, col), limits_y[0], limits_y[1],
size[1]*0.025, size[1]*0.975);
gdata.setFloat(i,"Y",y);
}
}
}
//calcular la Y del nuevo punto, tanto si han variado los
extremos o no
y=map(val, limits_y[0], limits_y[1], size[1]*0.025,
size[1]*0.975);
gdata.setFloat(gdata.getRowCount()-1, "Y", y);
//nuevo límite en x
if(gdata.getRowCount()==1)limits_x[0]=time;//si es el primer
punto de la tabla porque el punto del fue eliminado
27
limits_x[1]=time;
}
void draw_graph(){
float origin=0;
//dibujar los ejes y lineas
rectMode(CENTER);
fill(0);
stroke(255);
strokeWeight(2);
rect(position[0],position[1],size[0],size[1]);
translate(position[0]-size[0]/2,position[1]+size[1]/2);
strokeWeight(1);
stroke(128);
line(0, -size[1]*0.025, size[0], -size[1]*0.025);
line(0, -size[1]*0.25, size[0], -size[1]*0.25);
line(0, -size[1]*0.5, size[0], -size[1]*0.5);
line(0, -size[1]*0.75, size[0], -size[1]*0.75);
line(0, -size[1]*0.975, size[0], -size[1]*0.975);
//si hay valores positivos y negativos, dibujar el eje x para
referencia
if(limits_y[0]*limits_y[1]<0){
origin=-map(0, limits_y[0], limits_y[1], size[1]*0.025,
size[1]*0.975);
line(0, origin,size[0], origin);
}
//color y tamaño de los puntos
stroke(204,102,0);
strokeWeight(4);
//calculo de posicion y dibujo de los puntos
for(int i=0; i<gdata.getRowCount(); i++){
float x=size[0]*(i+1)/(gdata.getRowCount()+1);
point(x, -gdata.getFloat(i,"Y"));
}
if(limits_y[0]==limits_y[1])line(0, -size[1]*0.5, size[0], size[1]*0.5);
strokeWeight(1);//reset strokeWeight
textSize(12);
fill(0);
textAlign(RIGHT, CENTER);
text(str(limits_y[0]), -5, -size[1]*0.025);
text(str(limits_y[1]), -5, -size[1]*0.975);
text(str((limits_y[1]+limits_y[0])*0.5), -5, -size[1]*0.5);
if(limits_y[0]*limits_y[1]<0) text("0", -5, origin);
textAlign(CENTER, CENTER);
text(limits_x[0],0,20);
text(limits_x[1],size[0],20);
//retornar origen
translate(-position[0]+size[0]/2,-position[1]-size[1]/2);
}
}
28
//Elemento para operar las listas de parametros de los
dispositivos
class Parameter{
int[] position=new int[2];//posición base para dibujar la tabla
int row=0;
String ID="00";
String name="name";
int type=0;
String unit="[]";
int min=0;
int max=0;
int def=0;
String last;
Parameter (int temp_X, int temp_Y){
position[0]=temp_X;
position[1]=temp_Y;
}
void action (int i){
active_parameter=table.getString(i,0);//set fila i de la tabla
como parámetro activo
title2=table.getString(i,1)+" ["+table.getString(i,3)+"]";
//cargar columna de datos del sensor en el archivo de medidas
que se cargo cuando se entró el menu 2 para dibujar el gráfico
gdata=loadTable("data/"+fecha+"/"+active_node+"/"+active_device+".
csv", "header");
//eliminar línea por defecto
String [] m1=match(gdata.getString(0, 0),"del");
if(m1!=null)gdata.removeRow(0);
gdata.addColumn("Y");
show.column=i+1;//time=columna 0
if (gdata.getRowCount()>0)show.prepare_data();
if(cmd==true){
get_line(i);
command.range[0]=min;
command.range[1]=max;
command.value=def;
command.name=name;
command.unit=unit;
command.action();
}
}
void get_line(int i){
row=i;
ID=table.getString(i,0);//ID
name=table.getString(i,1);//name
type=table.getInt(i,2);//type
unit=table.getString(i,3);//unit
min=table.getInt(i,4);//min
max=table.getInt(i,5);//max
def=table.getInt(i,6);//default
last=table.getString(i,7);//last
}
void draw_header(){
29
stroke(0);
textAlign(CENTER);
textSize(12);
text("ID", position[0], position[1]);
//ID
text("Name", position[0]+40, position[1]); //name
text("Type", position[0]+80, position[1]); //type
text("Unit", position[0]+120, position[1]);//unit
text("MIN", position[0]+160, position[1]);//min
text("MAX", position[0]+200, position[1]);//max
text("Default", position[0]+240, position[1]);//default
textAlign(LEFT);
text("Last", position[0]+280, position[1]);//last
line(position[0]30,position[1]+5,position[0]+410,position[1]+5);
}
void edit_header(){
stroke(0);
fill(255);
for (int i=1; i<7; i++){//se modificara´n sólo 7 propiedades
ellipse(position[0]+40*i, position[1]-20, 10, 10);
if(i==active_prop){
fill(0);
ellipse(position[0]+40*i, position[1]-20,5,5);
fill(255);
}
}
}
void draw_line(){//dibujar la linea correspondiente de la tabla
int h=position[1]+20*(1+row);
fill(0);
textAlign(CENTER, CENTER);
text(ID,position[0],h);//ID
text(name,position[0]+40,h);//name
text(type,position[0]+80,h);//type
text(unit,position[0]+120,h);//unit
text(min,position[0]+160,h);//min
text(max,position[0]+200,h);//max
text(def,position[0]+240,h);//default
textAlign(LEFT, CENTER);
text(last,position[0]+280,h);//last
fill(255);
stroke(0);
ellipse(position[0]-20,h,10,10);
if(table.getString(row,0)==active_parameter){
fill(0);
ellipse(position[0]-20,h,5,5);
}
}
boolean over(int i){
float d = dist(mouseX, mouseY, position[0]-20,
position[1]+20*(1+i));//análisis de posición del raton
if (d < 10*0.5) return true;//size es el diametro del circulo
else return false;
}
30
boolean over_prop(int i){
float d = dist(mouseX, mouseY, position[0]+40*i, position[1]20);//análisis de posición del raton
if (d < 10*0.5) return true;//size es el diametro del circulo
else return false;
}
}
//Elemento para operar las etiquetas y botones de los nodos y los
dispositivos
class ElementButton{
String ID;
//ID del dispositivo
String name;
//descripción del dispositivo
int size=48;
//tamaño del boton
int pos_x;
//posicion en x del boton
int pos_y;
//posicion en y del boton
int role;
//rol del dispositivo E,R,C (comunicacion), S,A
(sensor y actuador)
color aspecto=color(100,100,100);;
ElementButton(String tempID, String tempname, int tempX, int
tempY, int tempR){
ID=tempID;
name=tempname;
pos_x=tempX;
pos_y=tempY;
role=tempR;
}
void get_device(int i){
ID=table.getString(i,0); //columna ID
name=table.getString(i,1); //columna name
pos_x=table.getInt(i,2);
//columna X
pos_y=table.getInt(i,3);
//columna Y
//coumna role
role=table.getInt(i,4);
}
void action(){
active_menu++;
if(active_menu==1){//cargar dispositivos en el nodo
active_node=ID;
title=name;
table=loadTable("data/nodes/"+ID+"/devices.csv","header");
}
else if (active_menu==2){
active_device=ID;
if(role==4)cmd=true;//activar el command mode para actuadores
title=name;
//cargar tabla de parámetros
table=loadTable("data/nodes/"+active_node+"/"+ID+".csv","header");
active_parameter=table.getString(0,0);//indicación para
marcar el primer parámetro de la lista
list.action(0);
/* //cargar tabla de datos para el parámetro por defecto 1
31
gdata=loadTable("data/"+fecha+"/"+active_node+"/"+ID+".csv",
"header");
//eliminar línea por defecto
String [] m1=match(gdata.getString(0, 0),"del");
if(m1!=null)gdata.removeRow(0);
gdata.addColumn("Y");
show.column=1;
if (gdata.getRowCount()>0)show.prepare_data();*/
}
}
void draw_label(){// no hacen falta parametros
rectMode(CENTER);
int text_size=size/4;
int over=int(over());
float L=1.25*size;
String symbol;
switch (role){
case 0: aspecto=color(182,83,83);
symbol="C"; //Coordinator
break;
case 1: aspecto=color(63,121,60);
symbol="R"; //Router
break;
case 2: aspecto=color(80,80,120);
symbol="E"; //End device
break;
case 3: aspecto=color(0,112,192);
symbol="S"; //Sensor
break;
case 4: aspecto=color(255,192,0);
symbol="A"; //Actuator
break;
default:symbol="0";
//otro
break;
}
stroke(0);
fill(255);
rect(pos_x-(0.5*size), pos_y, 2*L, L);
stroke(255);
fill(aspecto,255-(80*over));
ellipse(pos_x,pos_y,size, size);
fill(255);
textSize(text_size*3);
textAlign(CENTER, CENTER);
text(symbol,pos_x,pos_y);
fill(0);
textAlign(LEFT, CENTER);
textSize(text_size);
text(ID, pos_x-(1.3*L), pos_y-(0.3*L));
text (name,pos_x-(1.3*L),pos_y);
}
boolean over(){
float d = dist(mouseX, mouseY, pos_x, pos_y);//análisis de
posición del raton
32
if (d < size*0.5) return true;//size es el diametro del
circulo
else return false;
}
}
//Botones generales de la aplicación
class MenuButtons{
String name;
//descripción del dispositivo
int size=24;
//tamaño del boton
int pos_x;
//posicion en x del boton
int pos_y;
//posicion en y del boton
int role;
boolean state=false;
color aspecto=color(15,36,62);
MenuButtons(int tempX, int tempY, int tempR){
role=tempR;
pos_x=tempX;
pos_y=tempY;
switch (tempR){
case 0: name="Exit";
//salir
break;
case 1: name="Back";
//volver
break;
case 2: name="Add new"; //add device
break;
case 3: name="Edit selected"; //Edit
break;
case 4: name="Help";
//help
break;
default: name="";
break;
}
}
void action(){
switch (role){
case 0: exit();
break;
case 1: active_menu--;
if(active_menu==0){
table.clearRows();
table=loadTable("data/Network.csv","header");
}
else if(active_menu==1){
cmd=false;
table.clearRows();
table=loadTable("data/nodes/"+active_node+"/devices.csv","header")
;
}
break;
case 2: state=true;
break;
case 3: state=true;
33
break;
case 4:
open("C:/Users/marcelo/Documents/Processing/sketch_140821b/data/he
lp.txt");
break;
default: //active_menu=0;
break;
}
}
void draw_label(){// no hacen falta parametros
int text_size=size/4;
int over=int(over());
float L=1.25*size;
String symbol;
switch (role){
case 0: symbol="X";
break;
case 1: symbol="<";
break;
case 2: symbol="+";
break;
case 3: symbol=">";
break;
case 4: symbol="?";
break;
default: symbol="";
break;
}
stroke(255);
fill(aspecto,255-(80*over));
ellipse(pos_x,pos_y,size, size);
//Salir
//volver
fill(255);
textSize(text_size*3);
textAlign(CENTER, CENTER);
text(symbol,pos_x, pos_y);
fill(0);
textAlign(LEFT, CENTER);
textSize(text_size*2);
text(name,pos_x+size, pos_y);
}
boolean over(){
float d = dist(mouseX, mouseY, pos_x, pos_y);//análisis de
posición del raton
if (d < size*0.5) return true;//size es el diametro del
circulo
else return false;
}
}
//A continuacion aparecen las funciones auxiliares que utiliza la
aplicación
//función para generar los archivos de datos de los dispositivos
34
void Filesgen(){
for(int i=0; i<table.getRowCount(); i++){
active_node=table.getString(i, 0);
gdata=loadTable("data/nodes/"+active_node+"/devices.csv","header")
;
for(int j=1; j<gdata.getRowCount(); j++){//ignorar la radio
active_device=gdata.getString(j, 0);
rxdata=loadTable("data/nodes/"+active_node+"/"+active_device+".csv
","header");
/*aparte de la cabecer se requiere de una primera línea, de
lo contrario la tabla no se abre
igualmente esta primera línea se eliminará al cargar la
tabla*/
String [] header={"time", "del"};
for(int k=0; k<rxdata.getRowCount(); k++){
header[0]+=","+rxdata.getString(k, 0);
header[1]+=",0";
}
saveStrings("data/"+fecha+"/"+active_node+"/"+active_device+".csv",
header);
rxdata.clearRows();
}
}
gdata.clearRows();
}
//función para convertir datos floats a formato de 5 bytes
void ftohex (float number, byte [] result){
int aux;
if(number<0){
result[0]=1;
number=abs(number);//eliminar el signo
}
else result[0]=0;
aux=int(number);//extraemos parte entera
result[2]=byte(aux);
result[1]=byte(aux >>8);
//extraer la parte decimal
number=number-aux;
//A será inferior al número máximo para 16 bits 2^16=65536
//tambien el decimal debe ser mayor a 0, sino se quedaria en el
bucle tener en cuenta los bits!!!
while(number<6553.6 && number>0)number=number*10;
aux=int(number);
result[4]=byte(aux);
result[3]=byte(aux >>8);
}
//funciones para obtener del sistema la fecha y la hora.
String Date(){
String[] Date=new String[3];
Date[2] =nf(day(), 2);
Date[1] =nf(month(), 2);
Date[0]= nf(year(), 4);
35
return(Date[0]+ '_'+Date[1]+ '_'+Date[2]);
}
String Time(){
String[] Time=new String[3];
Time[0] =nf(second(), 2);
Time[1] =nf(minute(), 2);
Time[2]= nf(hour(), 2);
return(Time[2]+ ':'+Time[1]+ ':'+Time[0]);
}
36
Descargar