UDP Broadcasting
Posted:
Wed Mar 22, 2017 7:36 am
by mscory
Hello,
I'm trying to send NMEA messages to a Wifi network. The messages will be used with application like EasyAIS or SailTracker. Unfortunately it doesn't work: no error messages and nothing seems to be sent. I extract the relevant part of my software.
Any ideas ?
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
//Paramètres
// ==========
char ssid[] = "MyNetwork"; // network SSID (name)
char pass[] = "MyPassword"; // network password
unsigned int udpPort = 2311; // local port to listen for UDP packets
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
void setup() {
Serial.begin(38400);
WiFi.begin(ssid, pass);
while ( WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("[setup] WiFi connected");
Serial.print("[setup] IP address: ");
Serial.println(WiFi.localIP());
udp.begin(udpPort);
}
//**************************************************************************************
void loop() {
IPAddress broadcastIp = WiFi.localIP();
broadcastIp[3] = 255;
Serial.println(broadcastIp);
udp.beginPacket(broadcastIp, udpPort);
udp.print("!AIVDM,1,1,,A,14eG;o@034o8sd<L9i:a;WF>062D,0*7D");
udp.endPacket();
delay(2000);
}
Thanks
Kind regards
Michel
Re: UDP Broadcasting
Posted:
Wed Mar 22, 2017 9:20 am
by Pablo2048
Hi,
there can be more problems
. Please try to:
1. print WiFi.subnetMask() to confirm, that only last octet is used for broadcast address in Your network
2. watch Your network with Wireshark to really check, that nothing left ESP
3. try to use general broadcast address 255.255.255.255 - this will definitively work (I'm using this address), but it's not pure solution...
Re: UDP Broadcasting
Posted:
Wed Mar 22, 2017 11:00 am
by schufti
Re: UDP Broadcasting
Posted:
Thu Mar 23, 2017 8:41 am
by picstart
This working code might help
It gets sentences from a GPS and puts them on a scrolling TFT_ST7735.h
and places them in the air via WiFi other free mapping software like OpenCPN on a separate device
on the same xx.xx.xx.xx network can receive the sentences wrapped in UDP packets.
"Par Hazard un mot de la Floride.....impossible n'est pas francais ....bonne chance"
[code]/// notes working 3/13/2017
//// this code makes the esp8266 a STA on the xx.xx.xx.xx network
//// it needs a 2A power supply the usb port can cause brown out restarts
///// this uses a 6 sentence buffer and sends when buffer is full
//// in the gap between the GPS sending a further group of sentences
//// GPs GP 20U7 sends every second
/// $GP GGA GLL GSA GSV RMC VTG
/// LCD updates with every valid GPS read
/// A Broadcast UDP packet is sent every 1 second controlled via a Ticker
/// raw GPS sentences are
/// Broadcast on xx.xx.xx.255 port 3342 see below
/// It reads a GPS sentence sent over RS232 serial
/// the GPS squawks several sentences one every second
/// the esp8266 acts as a GPS repeater putting the sentences via UDP into the air
/// for other devices to receive the broadcast package
/// the GPS sqwark is asynchronous so the code needs to capture
/// sentences into a bufffer..the esp8266 has a hardware fed buffer of 128 bytes
/// that can be polled to see if there is data available
/// the rest of the work ..writing to UDP and the tft is done when data is not available
///////////////////////////////////////////////// dependencies //////////////////////////////////////////
/// needs TFT_ST7735-1.1b1.zip in libraries for include <TFT_ST7735.h>
///tft.scroll(addr); sends command CMD_VSSTADRS aka scroll start address
/// ST7735S scroll is via circular buffer so the pointer into the buffer needs tracking
/// a routine scroll_line() manages the pointers
// The scrolling area must be a integral multiple of TEXT_HEIGHT eg 17 lines at 9 pixels is 153 160-153 is 7
// the screen is in portrait mode 128 wide by 160 high
#define TEXT_HEIGHT 9 // Height of text to be printed and scrolled default font is mono mid 9 pixels high
#define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
#define TOP_FIXED_AREA 52 // Number of lines in top fixed area (lines counted from top of screen)
// The initial y coordinate of the top of the scrolling area
uint16_t yStart = TOP_FIXED_AREA;
// yArea must be a integral multiple of TEXT_HEIGHT ex 160-52=108 or 12 lines
#define scrollable_lines 12
uint16_t yArea = 160-TOP_FIXED_AREA-BOT_FIXED_AREA;
// The initial y coordinate of the top of the bottom text line
uint16_t yDraw = 160 - BOT_FIXED_AREA - TEXT_HEIGHT;
// Keep track of the drawing x coordinate
uint16_t xPos = 0;
// For the byte we read from the serial port
boolean sendUDP_flag=false;
#include <SPI.h>
#include <TFT_ST7735.h> ///this is fromTFT_ST7735-1.1b1.zip library
//ESP8266-----------------------------------
//Use: GPIO
#define __CS 15
#define __DC 5
#define __RST 4
/// 12 MISO hardware SPI not used for LCD
//// 13 MOSI hardware SPI
/// 14 SCL hardware SPI
//////// ST7735S red pcb
/// Pin
/// 1 3.3v
/// 2 Gnd
//// 3 CS GPIO 15 D8
/// 4 Reset GPIO 4 D2
//// 5 DC aka A0 GPIO 5 D1
/// 6 SDA -->esp MOSI GPIO 13 D7
// 7 SCK esp SCK GPIO 14 D5
// 8 LED -->3.3v
TFT_ST7735 tft = TFT_ST7735(__CS, __DC, __RST); //// uses proportional fonts so fill rect is needed to erase chars
////////////////////////////////////////// UDP broadcast /////////////////////////
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;
///////// a softap is everything a standard AP is except it can't send packets over hard wires
///////// hence soft ap name
///////// define the soft AP
const char* ssid = "ssid"; // SSID (name)
const char* pass = "xxxxx"; // password
// Multicast declarations
IPAddress ipBroadcast(xx, xx, xx, 255);
unsigned int portBroadcast = 3542; // port to broadcast on must be between1024...65000
unsigned int localPort=3542; // port to listen on
//////////////////////////////////////////////////// end of UDP /////////////////////
#define MAX_SENTENCES 12
#define INTERVAL 50
////////////////////////////////////////////// globals ///////////////////////////////
int gled_state=LOW;
int chars[MAX_SENTENCES],tft_line_idx=0,udp_pkt_idx=0;
int sentence_idx_r=0,sentence_idx_w=0;
byte udp_pkt[MAX_SENTENCES][128];
int cksum_idx[MAX_SENTENCES];
boolean started=false,ended=false;
boolean sentence_sent[MAX_SENTENCES];
boolean color_state=true; /// true is white false is yellow
int sentences_xmit=0;
/////////////////////////////////////////////////////////////////////////////////////
void blinkLED(int pin, int duration, int n) {
for(int i=0; i<n; i++) {
digitalWrite(pin, HIGH);
delay(duration);
digitalWrite(pin, LOW);
delay(duration);
}
delay(200);
}
void sendUDP(int idx,int pkt_size)
{
//// received $.......\n sentence
//// idx is the specific sentence one of MAX_SENTENCES
// chars is the number of chars in the sentence
////// put the udp_pkt in the air
Udp.beginPacket(ipBroadcast, portBroadcast);
Udp.write(udp_pkt[idx],pkt_size);
Udp.endPacket();
// Udp.stop();
}
void sendTFT(int idx,int chars)
{
//////// put a few chars of the gps sentence on the tft
//tft.setTextColor(WHITE);
tft.setTextScale(1);
if(tft_line_idx<scrollable_lines) /// (160-TOP_FIXED_AREA)/TEXT_HEIGHT =11 scroll 11 lines
{
///// fill the first 11 lines before starting scroll_line()
tft.setCursor(0, TOP_FIXED_AREA+tft_line_idx*TEXT_HEIGHT);
tft.print(chars);
tft.print(" ");
tft.write(udp_pkt[idx][cksum_idx[idx]+1]);
tft.write(udp_pkt[idx][cksum_idx[idx]+2]);
tft.print(" ");
tft.write(udp_pkt[idx],10);
tft_line_idx++;
}
else
{
//the scroll buffer is circular so ydraw is the pointer into the buffer
yDraw= scroll_line();
tft.setCursor(0,yDraw);
tft.print(chars);
tft.print(" ");
tft.write(udp_pkt[idx][cksum_idx[idx]+1]);
tft.write(udp_pkt[idx][cksum_idx[idx]+2]);
tft.print(" ");
tft.write(udp_pkt[idx],10);
}
}
void setup()
{
unsigned long start = millis();
ESP.wdtEnable(3000); // 3 sec
pinMode(2, OUTPUT); ////// pin 2 is D4 and the board h file will swap D4 for 2
//// the D designation is not used here but is useful if ever the board is switched.
blinkLED(2, 40, 3);
gled_state=LOW;
digitalWrite(2,HIGH); /// blue led is off
//////// init the sentence stack
for( int i=0;i<MAX_SENTENCES;i++)
{
////// start as if all sentences were sent ( no new ones to send)
sentence_sent[i]=true;
cksum_idx[i]=0;
}
Serial.begin(9600); ////// rs232 sentences are at 9600 baud
setupWiFi(); //// establish WiFi for this GPS repeater
tft.begin();
tft.setRotation(0);
tft.setCursor(0,0);
tft.setTextScale(1);
tft.setTextColor(RED);
// print our WiFi AP IP address:
IPAddress ip = WiFi.localIP();
tft.print("IP: ");
tft.println(ip);
tft.println("Broadcast");
tft.print("IP: ");
tft.println(ipBroadcast);
tft.print("Port:");
tft.println(portBroadcast);
///// ////////////////////////////// setup scroll area for the GPS ///////////////////////
tft.defineScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA); //// pixel lines from the top , lines from the bottom
tft.setCursor(0, TOP_FIXED_AREA); //// don't scroll into TOP FIXED AREA
tft.setTextColor(WHITE);
tft.setTextScale(1);
/////// GPS could be in the middle of sqwarking so the code waits for the gap
////// the code waits for the gap defined as at least 0.2 sec
/////// init the controlling values for the sentence buffer
for( int i=0;i<MAX_SENTENCES;i++)
{
////// set the flags to indicate already sent a new GPS sentence will reset to false (ie not yet sent)
sentence_sent[sentence_idx_r]=true;
}
do
{
while (Serial.available() > 0)
{
Serial.read(); //// dump the buffer
start=millis(); //// reset the counter
}
} while (millis() - start < INTERVAL); //// wait for 0.2 sec gap
//// at this point the receive buffer has been empty for 0.2 secs
}// setup
void loop()
{
char c;
while (Serial.available() > 64) ///// esp HARDWARE BUFFER IS 126 CHARS
{
c=Serial.read();
//// wait for $ at start of sentence and fill UDP buffer until /n /r '*" are seen
switch(c)
{
case '$':
digitalWrite(2,LOW); /// blue led is on
udp_pkt_idx=0; /// chars received pointer
started=true;
ended=false;
break;
case '*':
cksum_idx[sentence_idx_r]=udp_pkt_idx; //// save check sum pos of *
break;
case '\n':
ended=true;
digitalWrite(2,HIGH); /// blue led is off
///////// blue light will appear solid even though it is
//////// off briefly between each sentence
//////// net effect is that it flashes once per second
/////// GPS sqwarks 6 sentences every second
break;
} //// switch
if (started==true && ended==false)
{
///// c is $ indicating start of a sentence
/// post a char to the sentence
udp_pkt[sentence_idx_r][udp_pkt_idx]=c;
udp_pkt_idx++;
if (udp_pkt_idx>255) started=false; //// too many
}
if (started==true && ended==true)
{
/// finalize this sentence since
/// there was first a '$' and ending with '\n'
udp_pkt[sentence_idx_r][udp_pkt_idx]='\r';
udp_pkt_idx++;
udp_pkt[sentence_idx_r][udp_pkt_idx]='\n';
//udp_pkt_idx++;
// udp_pkt[sentence_idx_r][udp_pkt_idx]='\0';
chars[sentence_idx_r]=udp_pkt_idx+1; //// finalize size udp_pkt_idx i s zero referenced ex 0 is 1 char
// set the flags to send the sentence
sentence_sent[sentence_idx_r]=false;
Serial.print("r=");
Serial.print(sentence_idx_r);
Serial.print(" chars=");
Serial.print(chars[sentence_idx_r]);
Serial.write(udp_pkt[sentence_idx_r],chars[sentence_idx_r]);
sentence_idx_r++;
if (sentence_idx_r>=MAX_SENTENCES) sentence_idx_r=0; // circular buffer
started=false;
ended=false;
udp_pkt_idx=0;
chars[sentence_idx_r]=0;
}//// end received complete
} /// while gps data available
//// there maybe one or more complete sentences available to send
ESP.wdtFeed(); ////// reset the watch dog
///// we have sometime here between sqwarks to get packets into the air
/// and displayed on the TFT
//// send all received sentences
/// note sentence_idx_r is incremented already
/// so it has reached the maximum
/*
if (sentence_idx_w==MAX_SENTENCES)
{
//// there are sentences 0..MAX_SENTENCES-1 ready to send
//////// toggle the color to indicate a new group of sentences
color_state=!color_state;
if (color_state==true)
{
tft.setTextColor(WHITE);
}
else
{
tft.setTextColor(YELLOW);
}
*/
if(sentence_sent[sentence_idx_w]==false)
{
///// send this sentence
sendTFT(sentence_idx_w,chars[sentence_idx_w]); //// display this sentence via TFT
yield(); //// allow the esp serial or other hardware sometime
/*
Serial.print("w=");
Serial.print(sentence_idx_w);
Serial.print(" chars=");
Serial.print(chars[sentence_idx_w]);
Serial.print(" ");
Serial.write(udp_pkt[sentence_idx_w],chars[sentence_idx_w]);
*/
sendUDP(sentence_idx_w,chars[sentence_idx_w]); //// send this sentence chars is the total size $....\r\n\0
yield(); //// allow the esp serial or other hardware sometime
sentence_sent[sentence_idx_w]=true;
sentences_xmit++;
tft.setCursor(0,36);
tft.fillRect(0,36,127,TEXT_HEIGHT, BLACK); //// black fill the top line
tft.print("Xmitted=");
tft.print(sentences_xmit);
sentence_idx_w++;
if (sentence_idx_w>=MAX_SENTENCES)sentence_idx_w=0;
}
} /// loop
// ##############################################################################################
// Call this function to scroll the display one text line
// ##############################################################################################
int scroll_line() {
int yTemp = yStart; // Store the old yStart, this is where we draw the next line
// Use the record of line lengths to optimise the rectangle size we need to erase the top line
/// tft.fillRect x,y,w,h, color
tft.fillRect(0,yStart,127,TEXT_HEIGHT, BLACK); //// black fill the top line
// Change the top of the scroll area
yStart+=TEXT_HEIGHT;
// The value must wrap around as the screen memory is a circular buffer
if (yStart >= 160 - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA + (yStart - 160 + BOT_FIXED_AREA);
// Now we can scroll the display
tft.scroll(yStart);
return yTemp;
}
void setupWiFi()
{
WiFi.mode(WIFI_STA); ///// explicitly declare the mode to avoid ghost modes from prior sketch
WiFi.disconnect();
WiFi.begin(ssid, pass);
//Udp.begin(localPort);
}
[/code]