Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/neo8 i2c #552

Merged
merged 1 commit into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Meadow.Foundation.Sensors.Gnss
{
public partial class NeoM8
{
/// <summary>
/// Valid addresses for the sensor
/// </summary>
public enum Addresses : byte
{
/// <summary>
/// Bus address 0x42
/// </summary>
Address_0x42 = 0x42,
/// <summary>
/// Default bus address
/// </summary>
Default = Address_0x42
}

enum CommunicationMode
{
Serial,
SPI,
I2C,
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Meadow.Hardware;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Gnss
{
public partial class NeoM8
{
I2cPeripheral i2CPeripheral;
readonly Memory<byte> i2cBuffer = new byte[BUFFER_SIZE];

/// <summary>
/// Create a new NeoM8 object using I2C
/// </summary>
public NeoM8(IMeadowDevice device, II2cBus i2cBus, byte address = (byte)Addresses.Default, IPin resetPin = null, IPin ppsPin = null)
{
if(resetPin!= null)
{
device.CreateDigitalOutputPort(resetPin, true);
}

if(ppsPin != null)
{
device.CreateDigitalInputPort(ppsPin, InterruptMode.EdgeRising, ResistorMode.InternalPullDown);
}

_ = InitializeI2c(i2cBus, address);
}

/// <summary>
/// Create a new NeoM8 object using I2C
/// </summary>
public NeoM8(II2cBus i2cBus, byte address = (byte)Addresses.Default, IDigitalOutputPort resetPort = null, IDigitalInputPort ppsPort = null)
{
ResetPort = resetPort;
PulsePerSecondPort = ppsPort;

_ = InitializeI2c(i2cBus, address);
}

async Task InitializeI2c(II2cBus i2cBus, byte address)
{
i2CPeripheral = new I2cPeripheral(i2cBus, address, 128);

messageProcessor = new SerialMessageProcessor(suffixDelimiter: Encoding.ASCII.GetBytes("\r\n"),
preserveDelimiter: true,
readBufferSize: 512);

communicationMode = CommunicationMode.I2C;
messageProcessor.MessageReceived += MessageReceived;

InitDecoders();

await Reset();

Resolver.Log.Debug("Finish NeoM8 I2C initialization");
}

async Task StartUpdatingI2c()
{
await Task.Run(() =>
{
int len;

while (true)
{
len = i2CPeripheral.ReadRegisterAsUShort(0xFD, ByteOrder.BigEndian);

if(len > 0)
{
if(len > 0)
{
var data = i2cBuffer.Slice(0, Math.Min(len, BUFFER_SIZE)).Span;

i2CPeripheral.ReadRegister(0xFF, data);
messageProcessor.Process(data.ToArray());
}
}
Thread.Sleep(COMMS_SLEEP_MS);
}
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Meadow.Hardware;
using System.Text;

namespace Meadow.Foundation.Sensors.Gnss
{
public partial class NeoM8
{
readonly ISerialMessagePort serialPort;

// TODO: if we want to make this public then we're going to have to add
// a bunch of checks around baud rate, 8n1, etc.
/// <summary>
/// Create a new NEOM8 object
/// </summary>
protected NeoM8(ISerialMessagePort serialPort, IDigitalOutputPort resetPort = null, IDigitalInputPort ppsPort = null)
{
this.serialPort = serialPort;
ResetPort = resetPort;
PulsePerSecondPort = ppsPort;

InitializeSerial();
}

/// <summary>
/// Create a new NEOM8 object
/// </summary>
/// <param name="device">IMeadowDevice instance</param>
/// <param name="serialPortName">The serial port name to create</param>
/// <param name="resetPin">The reset pin</param>
/// <param name="ppsPin">The pulse per second pin</param>
public NeoM8(IMeadowDevice device, SerialPortName serialPortName, IPin resetPin, IPin ppsPin = null)
: this(device.CreateSerialMessagePort(
serialPortName,
suffixDelimiter: Encoding.ASCII.GetBytes("\r\n"),
preserveDelimiter: true,
readBufferSize: 512),
device.CreateDigitalOutputPort(resetPin, true),
device.CreateDigitalInputPort(ppsPin, InterruptMode.EdgeRising, ResistorMode.InternalPullDown))
{ }

void InitializeSerial()
{
communicationMode = CommunicationMode.Serial;
serialPort.MessageReceived += MessageReceived;
InitDecoders();

Reset().Wait();

Resolver.Log.Debug("Finish NeoM8 Serial initialization");
}

void StartUpdatingSerial()
{
if (serialPort.IsOpen)
{
Resolver.Log.Debug("serial port already open");
return;
}

Resolver.Log.Debug("opening serial port");
serialPort.Open();
Resolver.Log.Debug("serial port opened");

Resolver.Log.Debug("Requesting NMEA data");
serialPort.Write(Encoding.ASCII.GetBytes(Commands.PMTK_SET_NMEA_OUTPUT_ALLDATA));
serialPort.Write(Encoding.ASCII.GetBytes(Commands.PMTK_Q_RELEASE));
serialPort.Write(Encoding.ASCII.GetBytes(Commands.PGCMD_ANTENNA));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,55 @@ namespace Meadow.Foundation.Sensors.Gnss
public partial class NeoM8
{
readonly ISpiPeripheral spiPeripheral;
readonly SerialMessageProcessor messageProcessor;

const byte NULL_VALUE = 0xFF;
const byte BUFFER_SIZE = 128;
const byte SPI_SLEEP_MS = 200;

/// <summary>
/// Create a new NEOM8 object using SPI
/// </summary>
public NeoM8(ISpiBus spiBus, IDigitalOutputPort chipSelectPort, IDigitalOutputPort resetPort = null)
public NeoM8(ISpiBus spiBus,
IDigitalOutputPort chipSelectPort,
IDigitalOutputPort resetPort = null,
IDigitalInputPort ppsPort = null)
{
ResetPort = resetPort;
PulsePerSecondPort = ppsPort;

spiPeripheral = new SpiPeripheral(spiBus, chipSelectPort);

messageProcessor = new SerialMessageProcessor(suffixDelimiter: Encoding.ASCII.GetBytes("\r\n"),
preserveDelimiter: true,
readBufferSize: 512);
_ = InitializeSpi();
}

/// <summary>
/// Create a new NeoM8 object using SPI
/// </summary>
public NeoM8(IMeadowDevice device, ISpiBus spiBus, IPin chipSelectPin = null, IPin resetPin = null, IPin ppsPin = null)
{
var chipSelectPort = device.CreateDigitalOutputPort(chipSelectPin);

spiPeripheral = new SpiPeripheral(spiBus, chipSelectPort);

if (resetPin != null)
{
device.CreateDigitalOutputPort(resetPin, true);
}

if (ppsPin != null)
{
device.CreateDigitalInputPort(ppsPin, InterruptMode.EdgeRising, ResistorMode.InternalPullDown);
}

_ = InitializeSpi();
}

//ToDo cancellation for sleep aware
async Task InitializeSpi()
{
messageProcessor = new SerialMessageProcessor(suffixDelimiter: Encoding.ASCII.GetBytes("\r\n"),
preserveDelimiter: true,
readBufferSize: 512);

communicationMode = CommunicationMode.SPI;
messageProcessor.MessageReceived += MessageReceived;

InitDecoders();
Expand All @@ -45,7 +70,7 @@ async Task StartUpdatingSpi()
{
byte[] data = new byte[BUFFER_SIZE];

bool HasMoreData(byte[] data)
static bool HasMoreData(byte[] data)
{
bool hasNullValue = false;
for(int i = 1; i < data.Length; i++)
Expand All @@ -68,7 +93,7 @@ await Task.Run(() =>

if(HasMoreData(data) == false)
{
Thread.Sleep(SPI_SLEEP_MS);
Thread.Sleep(COMMS_SLEEP_MS);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ namespace Meadow.Foundation.Sensors.Gnss
/// </summary>
public partial class NeoM8
{
readonly ISerialMessagePort serialPort;
NmeaSentenceProcessor nmeaProcessor;

/// <summary>
Expand Down Expand Up @@ -56,46 +55,12 @@ public partial class NeoM8
/// </summary>
protected IDigitalOutputPort ResetPort { get; }

// TODO: if we want to make this public then we're going to have to add
// a bunch of checks around baud rate, 8n1, etc.
/// <summary>
/// Create a new NEOM8 object
/// </summary>
protected NeoM8(ISerialMessagePort serialPort, IDigitalOutputPort resetPort = null, IDigitalInputPort ppsPort = null)
{
this.serialPort = serialPort;
ResetPort = resetPort;
PulsePerSecondPort = ppsPort;

InitializeSerial();
}
CommunicationMode communicationMode;

/// <summary>
/// Create a new NEOM8 object
/// </summary>
/// <param name="device">IMeadowDevice instance</param>
/// <param name="serialPortName">The serial port name to create</param>
/// <param name="resetPin">The reset pin</param>
/// <param name="ppsPin">The pulse per second pin</param>
public NeoM8(IMeadowDevice device, SerialPortName serialPortName, IPin resetPin, IPin ppsPin = null)
: this(device.CreateSerialMessagePort(
serialPortName,
suffixDelimiter: Encoding.ASCII.GetBytes("\r\n"),
preserveDelimiter: true,
readBufferSize: 512),
device.CreateDigitalOutputPort(resetPin, true),
device.CreateDigitalInputPort(ppsPin, InterruptMode.EdgeRising, ResistorMode.InternalPullDown))
{ }

void InitializeSerial()
{
serialPort.MessageReceived += MessageReceived;
InitDecoders();
SerialMessageProcessor messageProcessor;

Reset().Wait();

Resolver.Log.Debug("Finish NeoM8 Serial initialization");
}
const byte BUFFER_SIZE = 128;
const byte COMMS_SLEEP_MS = 200;

/// <summary>
/// Reset the device
Expand All @@ -115,32 +80,18 @@ public async Task Reset()
/// </summary>
public void StartUpdating()
{
if (serialPort == null)
switch(communicationMode)
{
_ = StartUpdatingSpi();
case CommunicationMode.Serial:
StartUpdatingSerial();
break;
case CommunicationMode.SPI:
_ = StartUpdatingSpi();
break;
case CommunicationMode.I2C:
_ = StartUpdatingI2c();
break;
}
else
{
StartUpdatingSerial();
}
}

void StartUpdatingSerial()
{
if (serialPort.IsOpen)
{
Resolver.Log.Debug("serial port already open");
return;
}

Resolver.Log.Debug("opening serial port");
serialPort.Open();
Resolver.Log.Debug("serial port opened");

Resolver.Log.Debug("Requesting NMEA data");
serialPort.Write(Encoding.ASCII.GetBytes(Commands.PMTK_SET_NMEA_OUTPUT_ALLDATA));
serialPort.Write(Encoding.ASCII.GetBytes(Commands.PMTK_Q_RELEASE));
serialPort.Write(Encoding.ASCII.GetBytes(Commands.PGCMD_ANTENNA));
}

void InitDecoders()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Meadow;
using Meadow.Devices;
Expand All @@ -18,10 +19,13 @@ public override Task Initialize()
Resolver.Log.Info("Initializing ...");

//SPI
gps = new NeoM8(Device.CreateSpiBus(), Device.CreateDigitalOutputPort(Device.Pins.D14));
//gps = new NeoM8(Device.CreateSpiBus(), Device.CreateDigitalOutputPort(Device.Pins.D14), null);

//I2C
//gps = new NeoM8(Device.CreateI2cBus());

//Serial
//gps = new NeoM8(Device, Device.PlatformOS.GetSerialPortName("COM4"), Device.Pins.D09, Device.Pins.D11);
gps = new NeoM8(Device, Device.PlatformOS.GetSerialPortName("COM1"), Device.Pins.D09, Device.Pins.D11);

gps.GgaReceived += (object sender, GnssPositionInfo location) =>
{
Expand Down