I am using a GPS sensor based on the MTK3339 which is generally working correctly, however when I try to upload the EPO file to the GPS, it always fails (at packet 10 which is the last in a satellite set). Is there anyone who has in depth knowledge of what I am trying to acheive, or can read both C# & Python to see where I am going wrong.
I have posed the full GPS driver to [url]https://gist.github.com/networkfusion/a3b3fbc415bb88a06ec2[/url] but this is my EPO part (excusing the code quality as I am just trying to get it to work first):
byte[] epoPacket = new byte[191];
int epoCount = 0;
bool finalEpoPacketRequired = false;
bool flagStop = false;
//int totEPOcnt = 0;
byte[] epoFileData;
int failCount = 0;
int SatSetSize = 60;
int currentFileDataIndex = 0;
enum CommsProtocol
{
Binary,
ASCII
}
CommsProtocol currentProtocol = CommsProtocol.ASCII;
public void UpdateEpoData(byte[] fileData) //TODO: try and use https://github.com/f5eng/mt3339-utils/blob/gps/epoloader as this fails.
{
this.failCount = 0;
this.epoCount = 0;
this.epoFileData = fileData;
//this.flagAGPS = false;
this.finalEpoPacketRequired = false;
this.flagStop = false;
//this.totEPOcnt = epoFileData.Length / SatSetSize; // = 32
if (this.epoFileData.Length % 1920 != 0)
{
if (Debugger.IsAttached) { Debug.Print("EPO File is corrupt"); }
}
else
{
var b = UTF8Encoding.UTF8.GetBytes(ENTER_BINARY_MODE);
serialPort.Write(b, 0, b.Length); // GPS chipset from nmea- to bin-mode at 57600bps
Thread.Sleep(500);
serialPort.Close();
currentProtocol = CommsProtocol.Binary;
serialPort.BaudRate = 57600;
serialPort.Open();
if (Debugger.IsAttached) { Debug.Print("Starting to send epo packets"); }
this.SendEpoPacket();
}
}
int satSet = 0;
int packetInSatSet = 0;
private void SendEpoPacket()
{
if (this.flagStop)
{
if (Debugger.IsAttached) { Debug.Print("finished EPO file setup, going back to nema mode"); }
this.finalEpoPacketRequired = false;
this.flagStop = false;
this.SetModeNMEA(9600);
Thread.Sleep(1000);
this.serialPort.Write("$PMTK607*33\r\n");
return;
}
if (this.finalEpoPacketRequired)
{
if (Debugger.IsAttached) { Debug.Print("sending the final epo packet"); }
this.flagStop = true;
this.epoCount = 65535; //0xffff
this.GenerateEpoPacket(0, true);
this.serialPort.Write(this.epoPacket, 0, 191);
return;
}
if (packetInSatSet != 10)
{
Debug.Print("Sending 3 sats");
if (Debugger.IsAttached) { Debug.Print("sending an epo packet"); }
this.GenerateEpoPacket(180);
this.serialPort.Write(this.epoPacket, 0, 191);
this.epoCount++;
packetInSatSet++;
}
else
{
Debug.Print("Sending 2 sats");
int num = epoFileData.Length - currentFileDataIndex; //should be 120?!
if (num < 121)
{
this.finalEpoPacketRequired = true;
if (Debugger.IsAttached)
{
Debug.Print("current file index is: " + currentFileDataIndex);
Debug.Print("file size is: " + epoFileData.Length);
Debug.Print("got " + num + ". It should be 120... but is it?");
}
}
this.GenerateEpoPacket(120);
this.serialPort.Write(this.epoPacket, 0, 191);
this.epoCount++;
packetInSatSet = 0;
satSet++;
}
}
private void GenerateEpoPacket(int epoMaxCount, bool isFinalPacket = false)
{
epoPacket = new byte[191];
this.epoPacket[0] = 0x04; this.epoPacket[1] = 0X24; //Preamble
this.epoPacket[2] = 0xBF; this.epoPacket[3] = 0x00; //Length
this.epoPacket[4] = 0xD2; this.epoPacket[5] = 0x02; //Command: EPO Packet
this.epoPacket[6] = (byte)(this.epoCount & 0xFF); //Message ID part 1
this.epoPacket[7] = (byte)((this.epoCount >> 8) & 0xFF); //Message ID part 2
if (!isFinalPacket)
{
int epoPacketIndex = 8;
for (int i = epoPacketIndex; i <= (epoMaxCount + epoPacketIndex) -1; i++)
{
this.epoPacket[i] = epoFileData[currentFileDataIndex];
currentFileDataIndex++;
}
}
else
{
this.finalEpoPacketRequired = true;
}
this.epoPacket[188] = this.GenerateChecksum(this.epoPacket); //Checksum
this.epoPacket[189] = 0x0D; this.epoPacket[190] = 0x0A; //End word
}
private void SetModeNMEA(int baudRate)
{
byte[] NemaPacket = new byte[14];
NemaPacket[0] = 0x04; NemaPacket[1] = 0x24; // Preamble
NemaPacket[2] = 0x0E; NemaPacket[3] = 0x00; // Length
NemaPacket[4] = 0xFD; NemaPacket[5] = 0x00; // Command: Change UART packet protocol
NemaPacket[6] = 0x00; // PMTK protocol
NemaPacket[7] = (byte)(baudRate & 0xFF); // Set UART baudrate (4 bytes)
NemaPacket[8] = (byte)((baudRate >> 8) & 0xFF);
NemaPacket[9] = (byte)((baudRate >> 16) & 0xFF);
NemaPacket[10] = (byte)((baudRate >> 24) & 0xFF);
NemaPacket[11] = GenerateChecksum(NemaPacket); // Checksum
NemaPacket[12] = 0x0D; NemaPacket[13] = 0x0A; // End word
this.serialPort.Write(NemaPacket, 0, 14);
Thread.Sleep(500);
serialPort.Close();
serialPort.BaudRate = baudRate;
currentProtocol = CommsProtocol.ASCII;
serialPort.Open();
if (Debugger.IsAttached) { Debug.Print("Set to NEMA mode"); }
}
byte GenerateChecksum(byte[] packet)
{
var xorByte = packet[2]; //Avoid the preamble
int endIndex = packet.Length - 3; //Avoid the End word
for (int i = 3; i <= endIndex; i++)
{
xorByte ^= (byte)(packet[i] & 0xff);
}
return xorByte;
}
bool readInProgress = false;
void serialPort_DataReceived(GTI.Serial sender)
{
try
{
if (!readInProgress)
{
readInProgress = true;
while (sender.BytesToRead > 0)
{
byte[] receivedBytes = new byte[100];
int i = 0;
if (currentProtocol == CommsProtocol.Binary)
{
receivedBytes[i] = (byte)serialPort.ReadByte();
i++;
}
if (receivedBytes[0] == 0x04 | currentProtocol == CommsProtocol.ASCII)
{
receivedBytes[i] = (byte)serialPort.ReadByte();
if (receivedBytes[i] == 0x24)
{
//Debug.Print("got packet start");
i++;
while (true)
{
//read until the endword is received
receivedBytes[i] = (byte)serialPort.ReadByte();
if (receivedBytes[i] == 0x0A)
{
if (currentProtocol == CommsProtocol.Binary)
{
//Debug.Print("got packet end");
ParseACK(receivedBytes);
}
else
{
serialPort_LineReceived(new string(UTF8Encoding.UTF8.GetChars(receivedBytes)));
}
break;
}
i++;
}
}
}
}
readInProgress = false;
}
}
catch (Exception ex)
{
if (Debugger.IsAttached) { Debug.Print("binary mode: error receiving bytes, " + ex); }
}
}
private void ParseACK(byte[] receivedBytes)
{
try
{
bool success = false;
if ((receivedBytes[0] == (byte)0x04) & (receivedBytes[1] == (byte)0x24) & // Preamble (4, 36)
(receivedBytes[2] == (byte)0x0C) & (receivedBytes[3] == (byte)0x00) & // Response Length (12, 0)
(receivedBytes[4] == (byte)0x02) & (receivedBytes[5] == (byte)0x00) & // Command ID (2, 0)
(receivedBytes[6] == (byte)(this.epoCount - 1 & 0xff) & (receivedBytes[7] == (byte)(this.epoCount - 1 >> 8))))// && ((millis()-startTime)<timeOut)) // LSB-MSB sequence
{
if (receivedBytes[8] != 0x01) //the sent epo data was unsuccessful
{
this.SetModeNMEA(9600);
if (Debugger.IsAttached) { Debug.Print("EPO File is corrupt at packet" + (epoCount - 1) + ", exiting"); }
success = true;
}
else
{
if (Debugger.IsAttached) { Debug.Print("EPO packet successful, sending the next one"); }
this.SendEpoPacket();
}
}
if (!success)
{
if (Debugger.IsAttached) { Debug.Print("Packet incorrect, ignoring"); }
this.failCount++;
}
if (this.failCount >= 1920)
{
this.SetModeNMEA(9600);
if (Debugger.IsAttached) { Debug.Print("EPO File upload has failed too many times, exiting."); }
}
}
catch (Exception ex)
{
if (Debugger.IsAttached) { Debug.Print(ex.ToString()); }
this.SetModeNMEA(9600);
}
}
I call this from the main program using:
try
{
TraceLog("Downloading EPO data", LogType.Information);
var strName = "gtopagpsenduser01";
var strPWD = "enduser080807";
var strFTPPath = "ftp.gtop-tech.com";
//byte[] data;
TraceLog("Connecting to FTP Server", LogType.Information);
FtpClient ftpclient = new FtpClient();
ftpclient.connectToRemoteFtpServer(strFTPPath, 21, strName, strPWD);
var ltemp = ftpclient.getfilesize("MTK14.EPO");
byte[] buffer = new byte[ltemp];
TraceLog("Receiving file via FTP", LogType.Information);
ftpclient.download("MTK14.EPO", buffer);
TraceLog("Updating GPS sensor", LogType.Information);
gps.UpdateEpoData(buffer);
}
catch (Exception ex)
{
TraceLog(ex.ToString(), LogType.Error);
}
I have also found a python solution: [url]https://github.com/f5eng/mt3339-utils[/url] if it helps.