- Thu Mar 23, 2017 8:41 am
#64136
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]