Managed File System

Hi

I moved code from a Portal to a Feather board.
As the Feather doesn’t have an SD card, I used a microSD click and the managed File system
I tried first the code provided in the doc to test and everything was running fine.
But I always had Exception ‘invalid Path’ with my code
The file was saved in \DATA\SensorData.txt
I got it solved by changing the name from SensorData.txt to Sensor.txt.
So, I assume that there is a limitation in the file name length (but not if you use the File.System for board having SD
Correct ?

The source files for the managed file system are on Github. They are a great source for answering the question you asked.

Feather does not have SD card connected, but it supports SDCard with full FileSystem.
it is much faster if you use full FileSystem.

I thought it would be very hard to use Managed FileSystem on SDCard, how did you do it?

Can you your share code?

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;
            }
        }

    

    }
}
1 Like