Hi Dat
I used Managed FileSystem because i read in the docs that Additionally, SPI SD drivers are also supported through the ManagedFileSystem
software utility drivers.
I used the Fullfile system on the portal but this didn’t seems to work on the Feather (unless i made a mistake)
The program.cs code is below
Feather is connected to some external sensors 'Temp, pressure, Humidity, light, Rain, wind speed …
The goal is to use MQTT but before that, i want to be able to create a log of the sensors reading on a SD card (1 : min)
Sensores data is read every 2 seconds, the data is written on the SD every minutes
The board can also received simple request from a server (desktop app).
Those are used to Send last sensor reading, send complete log, delete log, …
Note : If I try for example to delete a file using the File.Delete(), it doesn’t work
The Drive name seems to be the managedFs.Root (F;\)
File.Delete(managedFS.Root + filename) throws one exception
Using A: instead doesn’t work neither, but managedFs.Delete() works
I do not see a way to attach a file, so I just copy the code below
If you need more that just the Program.cs, let me know
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Network;
using GHIElectronics.TinyCLR.Devices.Spi;
using GHIElectronics.TinyCLR.Drivers.ManagedFileSystem;
using GHIElectronics.TinyCLR.Drivers.Microchip.Winc15x0;
using GHIElectronics.TinyCLR.Pins;
using FileMode = GHIElectronics.TinyCLR.Drivers.ManagedFileSystem.FileMode;
namespace Meteo_Station_FEZ_Feather
{
public class Program
{
private const string Ssid = "**************";
private const string Password = "*************";
private static readonly NetworkController NetworkController =
NetworkController.FromName(SC20100.NetworkController.ATWinc15x0);
private static bool _isWifiConnected;
private static Socket _listener;
private static string _logHeader = string.Empty;
private static string _sensordata = string.Empty;
private static ManagedFileSystem _managedFs;
private static double _freeSdSpace;
private static Rtc10ClickI2C _rtc;
private static string _logtrace = @"\LOGS\SENSORS.TXT";
public static void Main()
{
// Init Lcd
var lcd = new MatrixOrbitalI2C(FEZPortal.I2cBus.I2c1, 0x5C, 4);
lcd.ClearScreen();
InitWifiModule();
var networkSettings = new WiFiNetworkInterfaceSettings
{
Ssid = Ssid,
Password = Password,
DhcpEnable = true,
DynamicDnsEnable = true
};
NetworkController.SetInterfaceSettings(networkSettings);
NetworkController.SetAsDefaultController();
// Wait for IP address
NetworkController.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
NetworkController.Enable();
while (!_isWifiConnected) Thread.Sleep(100);
// SD Card Check if SD is inserted socket One: PA0 / Socket Two: PA3
var checkSdPresence = GpioController.GetDefault().OpenPin(FEZFeather.GpioPin.PA0);
checkSdPresence.SetDriveMode(GpioPinDriveMode.Input);
var spiController = SpiController.FromName(FEZFeather.SpiBus.Spi4);
// Socket 1 CS = PB1
// Socket 2 CD = PD6
var chipSelect = GpioController.GetDefault().OpenPin(FEZFeather.GpioPin.PB1);
_rtc = new Rtc10ClickI2C(FEZPortal.I2cBus.I2c1);
// Get Time form Internet
DateTime dt = GetNetworkTime();
_rtc.SetTime(dt);
if (checkSdPresence.Read() == GpioPinValue.Low)
{
_managedFs = new ManagedFileSystem(spiController, chipSelect);
_managedFs.Mount();
CreateLog(false);
lcd.SetCursor(1, 1);
lcd.SendText("SD Card Found");
}
else
{
lcd.SetCursor(1, 1);
lcd.SendText("No SD Card !!");
return;
}
var weatherClick = new WeatherClickI2C(true, FEZPortal.I2cBus.I2c1, (int)WeatherClickI2C.I2CAddress.Default);
weatherClick.Initialize();
weatherClick.ChangeSettings(WeatherClickI2C.SensorMode.Forced);
lcd.SetCursor(1, 1);
lcd.SendText("Ambient Initialized");
lcd.ClearScreen();
lcd.BlinkingBlockCursor(false);
// Init Ambient 8 Click
var ambient8 = new Ambient8Click(true, FEZPortal.I2cBus.I2c1);
bool init = ambient8.Initialization();
if (init)
{
lcd.SetCursor(1, 1);
lcd.SendText("Ambient Initialized");
}
// Set Gain to 8000
ambient8.SetAlsGain(8000);
lcd.SetCursor(1, 2);
lcd.SendText("Als Gain: " + ambient8.AlsGain);
// Set Measurement Time to 2000 ms
ambient8.SetAlsMeasurementRate(2000);
lcd.SetCursor(1, 3);
lcd.SendText("Als Rate: " + ambient8.AlsMeasurementRate);
Thread.Sleep(5000);
uint loop = 0;
long sdSize = _managedFs.TotalSize;
lcd.ClearScreen();
// Rain Sensor RG15 : Not connected
// RainSensorRg15 rainSensor = new RainSensorRg15(FEZFeather.UartPort.Uart1);
// Wind Sensor SEN0170 : Not Connected
// Sen0170WindSpeed windspeed = new Sen0170WindSpeed(FEZFeather.Adc.Controller1.Id, FEZFeather.Adc.Controller1.PA0);
Timer timer = new Timer(ServerTimerCallback, null, 0, 1000);
while (true)
{
int rssi = Winc15x0Interface.GetRssi();
double temp = _rtc.GetTemp();
ambient8.ReadAmbientLight();
double lux = ambient8.Lux;
if (weatherClick.Read())
{
lcd.SetCursor(1, 1);
lcd.SendText("Pa:" + weatherClick.Pressure);
lcd.SetCursor(11, 1);
lcd.SendText("Rh:" + weatherClick.Humidity);
lcd.SetCursor(1, 2);
lcd.SendText("T1:" + weatherClick.Temperature);
lcd.SetCursor(11, 2);
lcd.SendText("T2:" + temp);
}
else
{
lcd.SetCursor(1, 1);
lcd.SendText("Read Error ");
}
lcd.SetCursor(1, 3);
lcd.SendText("Lux:" + lux);
lcd.SetCursor(11, 3);
lcd.SendText("Rssi:" + rssi);
lcd.SetCursor(1, 4);
double sz = sdSize - _freeSdSpace;
string size = sz.ToString();
size += new string(' ', 8 - size.Length);
lcd.SendText("Log Size: " + size);
loop++;
_sensordata = _rtc.GetTime() + "|" + lux + "|" + temp + "|" + weatherClick.Temperature + "|" + weatherClick.Pressure + "|" + weatherClick.Humidity + "|||" + rssi;
// Write Data to Log +- every minute
if (loop == 30)
{
if (!string.IsNullOrEmpty(_sensordata)) WriteData(_sensordata);
loop = 0;
}
Thread.Sleep(2000);
}
}
/// <summary>
/// Wifi Module Initialization
/// </summary>
private static void InitWifiModule()
{
// Setup Pins
var enablePinNumber = FEZBit.GpioPin.WiFiEnable;
var chipSelectPinNumber = FEZBit.GpioPin.WiFiChipselect;
var irqPinNumber = FEZBit.GpioPin.WiFiInterrupt;
var resetPinNumber = FEZBit.GpioPin.WiFiReset;
var spiControllerName = FEZBit.SpiBus.WiFi;
var gpio = GpioController.GetDefault();
var enablePin = gpio.OpenPin(enablePinNumber);
enablePin.SetDriveMode(GpioPinDriveMode.Output);
enablePin.Write(GpioPinValue.High);
var networkCommunicationInterfaceSettings = new SpiNetworkCommunicationInterfaceSettings
{
SpiApiName = spiControllerName,
GpioApiName = SC20260.GpioPin.Id,
SpiSettings = new SpiConnectionSettings
{
ChipSelectLine = gpio.OpenPin(chipSelectPinNumber),
ClockFrequency = 4000000,
Mode = SpiMode.Mode0,
ChipSelectType = SpiChipSelectType.Gpio,
ChipSelectHoldTime = TimeSpan.FromTicks(10),
ChipSelectSetupTime = TimeSpan.FromTicks(10)
},
InterruptPin = gpio.OpenPin(irqPinNumber),
InterruptEdge = GpioPinEdge.FallingEdge,
InterruptDriveMode = GpioPinDriveMode.InputPullUp,
ResetPin = gpio.OpenPin(resetPinNumber),
ResetActiveState = GpioPinValue.Low
};
NetworkController.SetCommunicationInterfaceSettings(networkCommunicationInterfaceSettings);
}
private static void NetworkController_NetworkAddressChanged(NetworkController sender,
NetworkAddressChangedEventArgs e)
{
var ipProperties = sender.GetIPProperties();
_isWifiConnected = !Equals(ipProperties.Address, IPAddress.Any);
if (!_isWifiConnected) return;
try
{
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(new IPEndPoint(ipProperties.Address, 8080));
_listener.Listen(1);
}
catch (SocketException ex)
{
Debug.WriteLine("Socket Exception: " + ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex.Message);
}
}
/// <summary>
/// Respond to Server Request
/// </summary>
private static void ServerTimerCallback(object state)
{
try
{
if (_listener != null && _listener.Poll(100, SelectMode.SelectRead))
{
var client = _listener.Accept();
var buffer = new byte[1024];
int received = client.Receive(buffer);
var data = Encoding.UTF8.GetString(buffer, 0, received);
switch (data)
{
case "LogRequest":
if (_managedFs.FileExist(_logtrace))
{
try
{
var fileHandle = _managedFs.OpenFile("\\LOGS\\SENSORS.TXT", FileMode.Read);
buffer = new byte[1024];
int bytesRead;
while ((bytesRead = _managedFs.ReadFile(fileHandle,buffer, 0, (uint)buffer.Length)) > 0)
{
client.Send(buffer, bytesRead, SocketFlags.None);
}
_managedFs.CloseFile(fileHandle);
}
catch (Exception ex)
{
Debug.WriteLine($"Exception while sending log: {ex.Message}");
}
}
break;
case "DeleteLog":
if (_managedFs.FileExist(_logtrace))
{
try
{
_managedFs.Delete(_logtrace);
CreateLog(true);
}
catch (Exception e)
{
Debug.WriteLine($"Exception while deleting /log: {e.Message}");
}
}
break;
case "RecreateLog":
CreateLog(true);
break;
case "DataRequest":
var response = Encoding.UTF8.GetBytes("START|" + DateTime.Now.Hour + ":" + DateTime.Now.Minute +
":" +
DateTime.Now + "|" + _sensordata);
client.Send(response);
client.Close();
break;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Exception in ServerTimerCallback: {ex.Message}");
}
}
/// <summary>
/// GetNetworkTime from time1.google.com
/// </summary>
private static DateTime GetNetworkTime()
{
const string ntpServer = "time1.google.com";
byte[] ntpData = new byte[48];
var addresses = Dns.GetHostEntry(ntpServer).AddressList;
var endPoint = new IPEndPoint(addresses[0], 123);
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Connect(endPoint);
// Initialize NTP data
ntpData[0] = 0x1B;
socket.Send(ntpData);
socket.Receive(ntpData);
// Extract the timestamp
ulong intPart = BitConverter.ToUInt32(ntpData, 40);
ulong fracPart = BitConverter.ToUInt32(ntpData, 44);
intPart = SwapEndianness(intPart);
fracPart = SwapEndianness(fracPart);
var milliseconds = intPart * 1000 + fracPart * 1000 / 0x100000000L;
// Convert to DateTime (GMT +1)
var networkDateTime = new DateTime(1900, 1, 1).AddMilliseconds((long)milliseconds).AddHours(1);
return networkDateTime;
}
private static uint SwapEndianness(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) + ((x & 0x0000ff00) << 8) + ((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
/// <summary>
/// Create Sensor if not exist or if create parameter is set
/// </summary>
/// <param name="create"></param>
public static string CreateLog( bool create)
{
// Header
byte[] macAddress = Winc15x0Interface.GetMacAddress();
if (macAddress.Length > 0) _logHeader = _rtc.GetTime() + "METEO STATION MAC: ";
foreach (var b in macAddress) _logHeader += b.ToString("X2") + "-";
_logHeader += " Firmware: " + Winc15x0Interface.GetFirmwareVersion() + "\n\r";
_logHeader += "DATE|TEMP INT|TEMP EXT|PRESS|RH|WIND|RAIN|RSSI" + "\n\r";
if (!_managedFs.DirectoryExist(@"\LOGS"))
{
_managedFs.CreateDirectory(@"\LOGS");
}
try
{
var data = Encoding.UTF8.GetBytes(_logHeader);
FileHandle fileWrite;
if (!_managedFs.FileExist(@"\LOGS\SENSORS.TXT") || create)
fileWrite = _managedFs.OpenFile(@"\LOGS\SENSORS.TXT", FileMode.Write | FileMode.CreateAlways);
else
fileWrite = _managedFs.OpenFile(@"\LOGS\SENSORS.TXT", FileMode.Write | FileMode.Append);
_managedFs.WriteFile(fileWrite, data, 0, (uint)data.Length);
_managedFs.FlushFile(fileWrite);
_managedFs.CloseFile(fileWrite);
return "OK";
}
catch (Exception e)
{
return e.Message;
}
}
/// <summary>
/// Add Sensor Status to Log
/// </summary>
/// <param name="data"></param>
public static string WriteData(string data)
{
var dataWrite = Encoding.UTF8.GetBytes(data + "\r\n");
var filename = @"\LOGS\SENSORS.TXT";
try
{
var fileWrite = _managedFs.FileExist(@"\LOGS\SENSORS.TXT")
? _managedFs.OpenFile(filename, FileMode.Append | FileMode.Write)
: _managedFs.OpenFile(filename, FileMode.CreateNew | FileMode.Write);
_managedFs.WriteFile(fileWrite, dataWrite, 0, (uint)dataWrite.Length);
_managedFs.FlushFile(fileWrite);
_freeSdSpace = _managedFs.AvailableFreeSpace;
_managedFs.CloseFile(fileWrite);
return "OK";
}
catch (Exception e)
{
return e.Message;
}
}
}
}