Sto facendo le prime prove con lo shield ethernet W5100 su ArduinoUNO.
Ho scritto un programma Python per inviare pacchetti UDP di prova, che crea un'interfaccia grafica con tre pulsanti: 'accendi' 'spegni' 'spam':
# Python 3.x
import socket
import random
import tkinter as tk
ARDU_ADDR = '192.168.1.30', 9000
#---------------------------------------------------------------------
def create_gui():
gui = tk.Tk()
gui.title('Ardu-UDP test')
gui.resizable(False, False)
button_on = tk.Button(gui, text='ACCENDI', width=12)
button_on.grid(row=0, column=0)
button_off = tk.Button(gui, text='SPEGNI', width=12)
button_off.grid(row=0, column=1)
button_spam = tk.Button(gui, text='SPAM', width=12)
button_spam.grid(row=0, column=3)
return gui, button_on, button_off, button_spam
#---------------------------------------------------------------------
def send_packet(n):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
if n == 2:
for h in range(random.randint(1, 101)):
len_data = random.randint(2, 1001)
data = [random.randrange(256) for n in range(len_data)]
sock.sendto(bytes(data), ARDU_ADDR)
else:
sock.sendto(bytes([n]), ARDU_ADDR)
sock.close()
#---------------------------------------------------------------------
def main():
gui, button_on, button_off, button_spam = create_gui()
button_on.bind('<Button-1>', lambda evt, n=1: send_packet(n))
button_off.bind('<Button-1>', lambda evt, n=0: send_packet(n))
button_spam.bind('<Button-1>', lambda evt, n=2: send_packet(n))
gui.mainloop()
#---------------------------------------------------------------------
main()
I pulsanti 'accendi' e 'spegni' inviano un pacchetto con un solo byte (rispettivamente di valore 1 e 0), mentre il pulsante 'spam' invia casualmente a raffica da 1 a 100 pacchetti, lunghi da 2 a 1000 byte, composti da byte casuali 0..255
Il programma ricevente su Arduino è il seguente:
#include <Ethernet.h>
#include <EthernetUdp.h>
//------------------------------------------------------------------
byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress IP(192, 168, 1, 30);
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // 24 bytes
EthernetUDP Udp;
//------------------------------------------------------------------
void setup()
{
pinMode(2, OUTPUT); // LED debug
digitalWrite(2, LOW); // spento
Ethernet.init(10);
Ethernet.begin(MAC, IP);
Udp.begin(9000);
}
//------------------------------------------------------------------
void loop()
{
int packetSize = Udp.parsePacket();
if (1 == packetSize)
{
Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
if (1 == packetBuffer[0]) { digitalWrite(2, HIGH); }
else if (0 == packetBuffer[0]) { digitalWrite(2, LOW); }
else { }
}
else if (packetSize > 1) // scartare intero pacchetto
{
while (Udp.available()) { Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); }
}
else
{
}
delay(10);
}
Lo scopo della prova era di verificare se la funzione 'Udp.parsePacket' riusciva a distinguere chiaramente tutti i pacchetti l'uno dall'altro e le loro esatte dimensioni.
I pulsanti 'accendi' e 'spegni' funzionano perfettamente, il LED collegato al pin 2 si comporta come previsto.
Cliccando su 'spam' invece di tanto in tanto il LED commuta, segno che qualche pacchetto o viene frammentato e diventa lungo un solo byte (ma strano su rete interna con solo uno switch di mezzo), o il buffer di ricezione del W5100 viene letto in un modo che non corrisponde a quanto penso, ovvero 'Udp.parsePacket' e/o 'Udp.available' e/o 'Udp.read' non si comportano come credevo.
Anche cambiando la strategia per scartare un pacchetto le cose non variano:
else if (packetSize > 1) // scartare intero pacchetto
{
for (uint16_t n=0; n<packetSize; n++) { Udp.read(); }
}
In sostanza pensavo che controllando il valore riportato da parsePacket potessi distinguere esattamente i pacchetti lunghi 1 da tutti gli altri, ma non è così.
In realtà potrebbe non essere un problema, perché nell'uso reale non invierei singoli byte ma messaggi completi, e non ci sarebbero dati spam serrati in circolo, però mi piacerebbe capire.
Come non detto... solito errore di if con = al posto di == Ho corretto, ma lascio i codici se a qualcuno servono come spunto.