示例#1
0
文件: PiThread.cs 项目: hugener/Pi
        /// <summary>
        /// Sleeps the specified delay.
        /// </summary>
        /// <param name="delay">The delay.</param>
        /// <param name="currentThread">The current thread.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        ///   <c>true</c>, if the thread slept for the specified delay otherwise <c>false</c>.
        /// </returns>
        internal static bool Sleep(TimeSpan delay, ICurrentThread currentThread, CancellationToken cancellationToken)
        {
            // Based on [BCM2835 C library](http://www.open.com.au/mikem/bcm2835/)

            // Calling nanosleep() takes at least 100-200 us, so use it for
            // long waits and use a busy wait on the hires timer for the rest.
            var stopwatch = Stopwatch.StartNew();

            if (delay >= MinLongDelay || delay == Timeout.InfiniteTimeSpan)
            {
                // Do not use high resolution timer for long interval (>= 100ms)
                currentThread.Sleep(delay, cancellationToken);
                return(!cancellationToken.IsCancellationRequested);
            }

            if (delay > MinNanoDelay)
            {
                var t1 = default(Interop.Timespec);
                var t2 = default(Interop.Timespec);

                // Use nanosleep if interval is higher than 450µs
                t1.TvSec  = IntPtr.Zero;
                t1.TvNsec = (IntPtr)((delay.Ticks * 100) - NanoSleepOffset);

                Interop.Nanosleep(ref t1, ref t2);
                return(true);
            }

            while (stopwatch.Elapsed < delay)
            {
            }

            return(true);
        }
示例#2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GroveBarDevice"/> class.
 /// </summary>
 /// <param name="dataPin">The data pin.</param>
 /// <param name="clockPin">The clock pin.</param>
 /// <param name="threadFactory">The thread factory.</param>
 public GroveBarDevice(IOutputBinaryPin dataPin, IInputOutputBinaryPin clockPin, IThreadFactory threadFactory = null)
 {
     this.dataPin  = dataPin;
     this.clockPin = clockPin;
     this.thread   = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
     this.Initialize();
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="RemotePiDevice" /> class.
 /// </summary>
 /// <param name="gpioController">The gpio controller.</param>
 /// <param name="shutdownButtonDevice">The shutdown button device.</param>
 /// <param name="shutdownOutPin">The shutdown out pin.</param>
 /// <param name="operatingSystemShutdown">The operation system shutdown.</param>
 /// <param name="activate">if set to <c>true</c> [activate].</param>
 /// <param name="shutdownTimeSpan">The shutdown time span.</param>
 /// <param name="dateTime">The date time.</param>
 public RemotePiDevice(
     GpioController gpioController,
     IButtonDevice shutdownButtonDevice,
     int shutdownOutPin,
     IOperatingSystemShutdown operatingSystemShutdown,
     bool activate,
     TimeSpan shutdownTimeSpan,
     IDateTime?dateTime = null)
 {
     this.gpioController          = gpioController;
     this.shutdownButtonDevice    = shutdownButtonDevice;
     this.shutdownOutPin          = shutdownOutPin;
     this.operatingSystemShutdown = operatingSystemShutdown;
     this.shutdownTimeSpan        = shutdownTimeSpan > MaxShutdownTimeSpan ? MaxShutdownTimeSpan : shutdownTimeSpan;
     this.dateTime = dateTime ?? new DateTimeProvider();
     this.thread   = new CurrentThread();
     this.shutdownButtonDevice.Pressed += this.OnShutdown;
     this.activation = new Activation(
         () => this.shutdownButtonDevice.IsActivated,
         () =>
     {
         this.shutdownButtonDevice.SetActivation(true);
         this.gpioController.OpenPin(this.shutdownOutPin, PinMode.Output);
     },
         () =>
     {
         this.shutdownButtonDevice.SetActivation(false);
         this.gpioController.ClosePin(this.shutdownOutPin);
     },
         activate);
 }
示例#4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PinsBehavior" /> class.
        /// </summary>
        /// <param name="configurations">The configurations.</param>
        /// <param name="threadFactory">The thread factory.</param>
        protected PinsBehavior(IEnumerable <PinConfiguration> configurations, IThreadFactory threadFactory)
        {
            this.Configurations = configurations.ToArray();
            this.thread         = threadFactory.Create();

            this.timer       = Timer.Create();
            this.interval    = TimeSpan.FromMilliseconds(250);
            this.timer.Tick += this.OnTimer;
        }
示例#5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Pca9685Device" /> class.
        /// </summary>
        /// <param name="connection">The I2C connection.</param>
        /// <param name="threadFactory">The thread factory.</param>
        /// <param name="pca9685DeviceReporter">The pca9685 device reporter.</param>
        public Pca9685Device(I2cDeviceConnection connection, IThreadFactory threadFactory = null, IPca9685DeviceReporter pca9685DeviceReporter = null)
        {
            this.connection            = connection;
            this.pca9685DeviceReporter = pca9685DeviceReporter;
            this.thread = ThreadFactory.EnsureThreadFactory(threadFactory).Create();

            this.pca9685DeviceReporter?.Resetting();
            this.WriteRegister(Register.Mode1, 0x00);
        }
示例#6
0
文件: I2cDriver.cs 项目: hugener/Pi
        /// <summary>
        /// Initializes a new instance of the <see cref="I2cDriver" /> class.
        /// </summary>
        /// <param name="sdaPin">The SDA pin.</param>
        /// <param name="sclPin">The SCL pin.</param>
        /// <param name="threadFactory">The thread factory.</param>
        /// <exception cref="InvalidOperationException">Unable to access device memory.</exception>
        public I2cDriver(ProcessorPin sdaPin, ProcessorPin sclPin, IThreadFactory threadFactory = null)
        {
            this.sdaPin = sdaPin;
            this.sclPin = sclPin;
            this.thread = ThreadFactory.EnsureThreadFactory(threadFactory).Create();

            var bscBase = GetBscBase(sdaPin, sclPin);

            var memoryFile = Interop.Open("/dev/mem", Interop.ORdwr + Interop.OSync);

            try
            {
                this.gpioAddress = Interop.Mmap(
                    IntPtr.Zero,
                    Interop.Bcm2835BlockSize,
                    Interop.ProtRead | Interop.ProtWrite,
                    Interop.MapShared,
                    memoryFile,
                    GetProcessorGpioAddress(Board.Current.Processor));

                this.bscAddress = Interop.Mmap(
                    IntPtr.Zero,
                    Interop.Bcm2835BlockSize,
                    Interop.ProtRead | Interop.ProtWrite,
                    Interop.MapShared,
                    memoryFile,
                    bscBase);
            }
            finally
            {
                Interop.Close(memoryFile);
            }

            if (this.bscAddress == (IntPtr)Interop.MapFailed)
            {
                throw new InvalidOperationException("Unable to access device memory");
            }

            // Set the I2C pins to the Alt 0 function to enable I2C access on them
            // remembers if the values were actually changed to clear them or not upon dispose
            this.wasSdaPinSet = this.SetPinMode((uint)(int)sdaPin, Interop.Bcm2835GpioFselAlt0); // SDA
            this.wasSclPinSet = this.SetPinMode((uint)(int)sclPin, Interop.Bcm2835GpioFselAlt0); // SCL

            // Read the clock divider register
            var dividerAddress = this.bscAddress + (int)Interop.Bcm2835BscDiv;
            var divider        = (ushort)SafeReadUInt32(dividerAddress);

            this.waitInterval = GetWaitInterval(divider);

            var addressAddress = this.bscAddress + (int)Interop.Bcm2835BscA;

            SafeWriteUInt32(addressAddress, (uint)this.currentDeviceAddress);
        }
示例#7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="GroveRgbDevice"/> class.
        /// </summary>
        /// <param name="dataPin">The data pin.</param>
        /// <param name="clockPin">The clock pin.</param>
        /// <param name="ledCount">The led count.</param>
        /// <param name="threadFactory">The thread factory.</param>
        public GroveRgbDevice(IOutputBinaryPin dataPin, IOutputBinaryPin clockPin, int ledCount, IThreadFactory threadFactory = null)
        {
            this.thread    = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
            this.ledColors = new List <RgbColor>();
            for (int i = 0; i < ledCount; i++)
            {
                // Initialize all leds with white color
                this.ledColors.Add(new RgbColor());
            }

            this.dataPin  = dataPin;
            this.clockPin = clockPin;
        }
示例#8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GpioConnectionDriver" /> class.
 /// </summary>
 /// <param name="threadFactory">The thread factory.</param>
 public GpioConnectionDriver(IThreadFactory threadFactory = null)
 {
     this.thread = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
     using (var memoryFile = UnixFile.Open("/dev/mem", UnixFileMode.ReadWrite | UnixFileMode.Synchronized))
     {
         this.gpioAddress = MemoryMap.Create(
             IntPtr.Zero,
             Interop.Bcm2835BlockSize,
             MemoryProtection.ReadWrite,
             MemoryFlags.Shared,
             memoryFile.Descriptor,
             GetProcessorBaseAddress(Board.Current.Processor));
     }
 }
示例#9
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DhtDevice" /> class.
        /// </summary>
        /// <param name="pin">The pin.</param>
        /// <param name="autoStart">if set to <c>true</c>, DHT is automatically started. Default value is <c>true</c>.</param>
        /// <param name="threadFactory">The thread factory.</param>
        /// <param name="dhtDeviceReporter">The DHT device reporter.</param>
        protected DhtDevice(IInputOutputBinaryPin pin, bool autoStart = true, IThreadFactory threadFactory = null, IDhtDeviceReporter dhtDeviceReporter = null)
        {
            this.thread            = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
            this.pin               = pin;
            this.dhtDeviceReporter = dhtDeviceReporter;

            if (autoStart)
            {
                this.Start();
            }
            else
            {
                this.Stop();
            }
        }
示例#10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="HcSr04Device" /> class.
        /// </summary>
        /// <param name="triggerPin">The trigger pin.</param>
        /// <param name="echoPin">The echo pin.</param>
        /// <param name="threadFactory">The thread factory.</param>
        public HcSr04Device(IOutputBinaryPin triggerPin, IInputBinaryPin echoPin, IThreadFactory threadFactory = null)
        {
            this.triggerPin = triggerPin;
            this.echoPin    = echoPin;
            this.thread     = ThreadFactory.EnsureThreadFactory(threadFactory).Create();

            this.SetTimeout(DefaultTimeout);

            try
            {
                this.GetDistance();
            }
            catch
            {
            }
        }
示例#11
0
 public MainTextView(Mfrc522Device rfidTransceiver, Ky040Device rotaryEncoder, ButtonDevice menuButton, ButtonDevice playButton, ButtonDevice nextButton, ButtonDevice prevButton)
 {
     this.rfidTransceiver              = rfidTransceiver;
     this.rotaryEncoder                = rotaryEncoder;
     this.menuButton                   = menuButton;
     this.playButton                   = playButton;
     this.nextButton                   = nextButton;
     this.prevButton                   = prevButton;
     this.menuButton.Pressed          += (_, e) => this.Pressed('M');
     this.playButton.Pressed          += (_, e) => this.Pressed('P');
     this.nextButton.Pressed          += (_, e) => this.Pressed('N');
     this.prevButton.Pressed          += (_, e) => this.Pressed('B');
     this.rotaryEncoder.Pressed       += (_, e) => this.Pressed('R');
     this.rotaryEncoder.Rotated       += this.OnRotaryEncoderRotated;
     this.rfidTransceiver.TagDetected += this.OnRfidTransceiverTagDetected;
     this.thread = new CurrentThread();
 }
示例#12
0
 public MainTextView(Mfrc522Connection rfidTransceiver, Ky040Device rotaryEncoder, PullDownButtonDevice menuButton, PullDownButtonDevice playButton, PullDownButtonDevice nextButton, PullDownButtonDevice prevButton)
 {
     this.rfidTransceiver              = rfidTransceiver;
     this.rotaryEncoder                = rotaryEncoder;
     this.menuButton                   = menuButton;
     this.playButton                   = playButton;
     this.nextButton                   = nextButton;
     this.prevButton                   = prevButton;
     this.menuButton.Pressed          += (_, e) => this.Pressed('M');
     this.playButton.Pressed          += (_, e) => this.Pressed('P');
     this.nextButton.Pressed          += (_, e) => this.Pressed('N');
     this.prevButton.Pressed          += (_, e) => this.Pressed('B');
     this.rotaryEncoder.Pressed       += (_, e) => this.Pressed('R');
     this.rotaryEncoder.Rotated       += this.OnRotaryEncoderRotated;
     this.rfidTransceiver.TagDetected += this.OnRfidTransceiverTagDetected;
     this.thread = new ThreadFactory(Board.Current, true).Create();
 }
示例#13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Mfrc522Connection" /> class.
 /// </summary>
 /// <param name="spiDevicePath">The spi device path.</param>
 /// <param name="resetConnectorPin">The reset connector pin.</param>
 /// <param name="gpioConnectionDriverFactory">The gpio connection driver factory.</param>
 /// <param name="threadFactory">The thread factory.</param>
 /// <param name="rfidConnectionReporter">The rfid connection reporter.</param>
 public Mfrc522Connection(
     string spiDevicePath,
     ConnectorPin?resetConnectorPin,
     IGpioConnectionDriverFactory?gpioConnectionDriverFactory = null,
     IThreadFactory?threadFactory = null,
     IRfidConnectionReporter?rfidConnectionReporter = null)
 {
     this.spiDevicePath          = spiDevicePath;
     this.resetConnectorPin      = resetConnectorPin;
     this.rfidConnectionReporter = rfidConnectionReporter;
     this.rfidConnectionReporter?.SetSource(typeof(IRfidConnectionReporter), this);
     this.thread = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
     this.gpioConnectionDriverFactory =
         GpioConnectionDriverFactory.EnsureGpioConnectionDriverFactory(gpioConnectionDriverFactory);
     this.gpioConnectionDriver = this.gpioConnectionDriverFactory.Get();
     this.mfrc522Device        = new Mfrc522Device(this.thread, this.gpioConnectionDriver);
     this.scanningJob          = new ContinuousJob(this.CheckForTags, (Exception exception, ref bool _) => this.rfidConnectionReporter?.OnException(exception));
 }
示例#14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SpiConnection" /> class.
        /// </summary>
        /// <param name="clockPin">The clock pin.</param>
        /// <param name="selectSlavePin">The select slave pin.</param>
        /// <param name="misoPin">The miso pin.</param>
        /// <param name="mosiPin">The mosi pin.</param>
        /// <param name="endianness">The endianness.</param>
        /// <param name="threadFactory">The thread factory.</param>
        public SpiConnection(
            IOutputBinaryPin clockPin,
            IOutputBinaryPin selectSlavePin,
            IInputBinaryPin misoPin,
            IOutputBinaryPin mosiPin,
            Endianness endianness        = Endianness.LittleEndian,
            IThreadFactory threadFactory = null)
        {
            this.clockPin       = clockPin;
            this.selectSlavePin = selectSlavePin;
            this.misoPin        = misoPin;
            this.mosiPin        = mosiPin;
            this.endianness     = endianness;
            this.thread         = ThreadFactory.EnsureThreadFactory(threadFactory).Create();

            clockPin.Write(false);
            selectSlavePin.Write(true);

            mosiPin?.Write(false);
        }
示例#15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RemotePiDevice" /> class.
        /// </summary>
        /// <param name="shutdownInConnectorPin">The shutdown in connector pin.</param>
        /// <param name="shutdownOutConnectorPin">The shutdown out connector pin.</param>
        /// <param name="operatingSystemShutdown">The operation system shutdown.</param>
        /// <param name="shutdownTimeSpan">The shutdown time span.</param>
        /// <param name="gpioConnectionDriverFactory">The gpio connection driver factory.</param>
        /// <param name="dateTime">The date time.</param>
        /// <param name="threadFactory">The thread factory.</param>
        public RemotePiDevice(
            ConnectorPin shutdownInConnectorPin,
            ConnectorPin shutdownOutConnectorPin,
            IOperatingSystemShutdown operatingSystemShutdown,
            TimeSpan shutdownTimeSpan,
            IGpioConnectionDriverFactory?gpioConnectionDriverFactory = null,
            IDateTime?dateTime           = null,
            IThreadFactory?threadFactory = null)
        {
            this.gpioConnectionDriverFactory = GpioConnectionDriverFactory.EnsureGpioConnectionDriverFactory(gpioConnectionDriverFactory);
            this.gpioConnectionDriver        = this.gpioConnectionDriverFactory.Get();
            this.shutdownInConnectorPin      = shutdownInConnectorPin;
            this.shutdownOutConnectorPin     = shutdownOutConnectorPin;
            this.operatingSystemShutdown     = operatingSystemShutdown;
            this.shutdownTimeSpan            = shutdownTimeSpan < TimeSpan.FromSeconds(4) ? TimeSpan.FromSeconds(4) : shutdownTimeSpan;
            this.dateTime = dateTime ?? new DateTimeProvider();
            this.thread   = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
            var pinConfiguration = shutdownInConnectorPin.Input().PullDown();

            pinConfiguration.OnStatusChanged(this.OnShutdown);
            this.gpioConnection = new GpioConnection(new GpioConnectionDriverFactory(this.gpioConnectionDriver), pinConfiguration);
        }
示例#16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="GpioConnection" /> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="pins">The pins.</param>
        /// <param name="gpioConnectionDriverFactory">The gpio connection driver factory.</param>
        /// <param name="threadFactory">The thread factory.</param>
        public GpioConnection(GpioConnectionSettings settings, IEnumerable <PinConfiguration> pins, IGpioConnectionDriverFactory gpioConnectionDriverFactory = null, IThreadFactory threadFactory = null)
        {
            this.settings = settings ?? new GpioConnectionSettings();
            this.gpioConnectionDriverFactory = GpioConnectionDriverFactory.EnsureGpioConnectionDriverFactory(gpioConnectionDriverFactory);
            this.gpioConnectionDriver        = this.gpioConnectionDriverFactory.Get();
            this.thread = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
            this.Pins   = new ConnectedPins(this);

            var pinList = pins.ToList();

            this.pinConfigurations = pinList.ToDictionary(p => p.Pin);

            this.namedPins = pinList.Where(p => !string.IsNullOrEmpty(p.Name)).ToDictionary(p => p.Name);

            this.timer = Core.Timers.Timer.Create();

            this.timer.Tick += this.CheckInputPins;

            if (this.settings.Opened)
            {
                this.Open();
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="Mfrc522Device" /> class.
 /// </summary>
 /// <param name="gpioController">The gpio controller.</param>
 /// <param name="busId">The bus identifier.</param>
 /// <param name="chipLineSelect">The chip line select.</param>
 /// <param name="resetPin">The reset pin.</param>
 /// <param name="activate">if set to <c>true</c> [activate].</param>
 /// <param name="rfidDeviceReporter">The rfid connection reporter.</param>
 public Mfrc522Device(
     GpioController gpioController,
     int busId,
     int chipLineSelect,
     int? resetPin,
     bool activate,
     IRfidDeviceReporter? rfidDeviceReporter = null)
 {
     this.gpioController = gpioController;
     this.rfidDeviceReporter = rfidDeviceReporter;
     this.rfidDeviceReporter?.SetSource(typeof(IRfidDeviceReporter), this);
     this.thread = new CurrentThread();
     this.mfrc522 = new Mfrc522(this.thread, this.gpioController);
     this.scanningJob = new ContinuousJob(this.CheckForTags, (Exception e, ref bool _) => this.rfidDeviceReporter?.OnException(e));
     this.activation = new Activation(
         () => this.scanningJob.IsRunning,
         () =>
         {
             this.mfrc522.Initialize(busId, chipLineSelect, resetPin, AntennaGain.Gain48);
             this.scanningJob.Start();
         },
         () => this.scanningJob.Stop(),
         activate);
 }
示例#18
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Bmp085Device" /> class.
 /// </summary>
 /// <param name="connection">The connection.</param>
 /// <param name="thread">The thread.</param>
 public Bmp085Device(I2cDeviceConnection connection, ICurrentThread thread)
 {
     this.connection = connection;
     this.thread     = thread;
     this.Initialize();
 }
示例#19
0
 internal Mfrc522(ICurrentThread thread, GpioController gpioController)
 {
     this.thread         = thread;
     this.gpioController = gpioController;
 }
示例#20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Bh1750Device"/> class.
 /// </summary>
 /// <param name="connection">The connection.</param>
 /// <param name="thread">The thread.</param>
 public Bh1750Device(I2cDeviceConnection connection, ICurrentThread thread)
 {
     this.thread     = thread;
     this.Connection = connection;
 }
 internal Mfrc522Device(ICurrentThread thread, IGpioConnectionDriver gpioConnectionDriver)
 {
     this.thread = thread;
     this.gpioConnectionDriver = gpioConnectionDriver;
 }
示例#22
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Hd44780LcdDevice"/> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="gpioConnectionDriverFactory">The gpio connection driver factory.</param>
        /// <param name="registerSelectPin">The register select pin.</param>
        /// <param name="clockPin">The clock pin.</param>
        /// <param name="hd44780DataPins">The HD44780 data pins.</param>
        /// <param name="backlight">The backlight.</param>
        /// <param name="readWrite">The read write.</param>
        /// <param name="threadFactory">The thread factory.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// pins - There must be either 4 or 8 data pins
        /// or
        /// settings - ScreenHeight must be between 1 and 4 rows
        /// or
        /// settings - PatternWidth must be 5 pixels
        /// or
        /// settings - PatternWidth must be either 7 or 10 pixels height.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// At most 80 characters are allowed
        /// or
        /// 10 pixels height pattern cannot be used with an even number of rows.
        /// </exception>
        public Hd44780LcdDevice(
            Hd44780LcdDeviceSettings settings,
            IGpioConnectionDriverFactory gpioConnectionDriverFactory,
            ConnectorPin registerSelectPin,
            ConnectorPin clockPin,
            Hd44780DataPins hd44780DataPins,
            ConnectorPin?backlight       = null,
            ConnectorPin?readWrite       = null,
            IThreadFactory threadFactory = null)
        {
            this.gpioConnectionDriverFactory = GpioConnectionDriverFactory.EnsureGpioConnectionDriverFactory(gpioConnectionDriverFactory);
            this.gpioConnectionDriver        = gpioConnectionDriverFactory.Get();
            this.pins      = new Hd44780Pins(this.gpioConnectionDriver, registerSelectPin, clockPin, backlight, readWrite, hd44780DataPins.ConnectorPins);
            this.thread    = ThreadFactory.EnsureThreadFactory(threadFactory).Create();
            this.syncDelay = settings.SyncDelay;

            if (this.pins.Data.Length != 4 && this.pins.Data.Length != 8)
            {
                throw new ArgumentOutOfRangeException(nameof(hd44780DataPins), this.pins.Data.Length, "There must be either 4 or 8 data pins");
            }

            this.width  = settings.ScreenWidth;
            this.height = settings.ScreenHeight;
            if (this.height < 1 || this.height > MaxHeight)
            {
                throw new ArgumentOutOfRangeException(nameof(settings.ScreenHeight), this.height, "ScreenHeight must be between 1 and 4 rows");
            }

            if (this.width * this.height > MaxChar)
            {
                throw new ArgumentException("At most 80 characters are allowed");
            }

            if (settings.PatternWidth != 5)
            {
                throw new ArgumentOutOfRangeException(nameof(settings.PatternWidth), settings.PatternWidth, "PatternWidth must be 5 pixels");
            }

            if (settings.PatternHeight != 8 && settings.PatternHeight != 10)
            {
                throw new ArgumentOutOfRangeException(nameof(settings.PatternHeight), settings.PatternHeight, "PatternHeight must be either 7 or 10 pixels height");
            }

            if (settings.PatternHeight == 10 && this.height % 2 == 0)
            {
                throw new ArgumentException("10 pixels height pattern cannot be used with an even number of rows");
            }

            this.functions = (settings.PatternHeight == 8 ? Functions.Matrix5X8 : Functions.Matrix5X10)
                             | (this.height == 1 ? Functions.OneLine : Functions.TwoLines)
                             | (this.pins.Data.Length == 4 ? Functions.Data4Bits : Functions.Data8Bits);

            this.entryModeFlags = /*settings.RightToLeft
                                   * ? EntryModeFlags.EntryRight | EntryModeFlags.EntryShiftDecrement
                                   * :*/EntryModeFlags.EntryLeft | EntryModeFlags.EntryShiftDecrement;

            this.encoding = settings.Encoding;

            this.BacklightEnabled = false;

            this.pins.ReadWrite?.Write(false);

            this.pins.RegisterSelect.Write(false);
            this.pins.Clock.Write(false);
            foreach (var dataPin in this.pins.Data)
            {
                dataPin.Write(false);
            }

            this.WriteByte(0x33, false); // Initialize
            this.WriteByte(0x32, false);

            this.thread.Sleep(TimeSpanUtility.FromMicroseconds(50));

            this.WriteCommand(Command.SetFunctions, (int)this.functions);
            this.WriteCommand(Command.SetDisplayFlags, (int)this.displayFlags);
            this.WriteCommand(Command.SetEntryModeFlags, (int)this.entryModeFlags);

            this.Clear();
            this.BacklightEnabled = true;
        }