private void Synchronize()
        {
            clockPin.Write(true);
            Sleep(0.001m); // 1 microsecond pause - enable pulse must be > 450ns

            clockPin.Write(false);
            Sleep(0.001m); // commands need > 37us to settle
        }
        private void WriteByte4Pins(int bits, bool charMode)
        {
            registerSelectPin.Write(charMode);

            dataPins[0].Write((bits & 0x10) != 0);
            dataPins[1].Write((bits & 0x20) != 0);
            dataPins[2].Write((bits & 0x40) != 0);
            dataPins[3].Write((bits & 0x80) != 0);

            Synchronize();

            dataPins[0].Write((bits & 0x01) != 0);
            dataPins[1].Write((bits & 0x02) != 0);
            dataPins[2].Write((bits & 0x04) != 0);
            dataPins[3].Write((bits & 0x08) != 0);

            Synchronize();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="Hd44780LcdConnection"/> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="registerSelectPin">The register select pin.</param>
        /// <param name="clockPin">The clock pin.</param>
        /// <param name="dataPins">The data pins.</param>
        public Hd44780LcdConnection(Hd44780LcdConnectionSettings settings, IOutputPin registerSelectPin, IOutputPin clockPin, IEnumerable <IOutputPin> dataPins)
        {
            settings = settings ?? new Hd44780LcdConnectionSettings();

            this.registerSelectPin = registerSelectPin;
            this.clockPin          = clockPin;
            this.dataPins          = dataPins.ToArray();

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

            width  = settings.ScreenWidth;
            height = settings.ScreenHeight;
            if (height < 1 || height > 2)
            {
                throw new ArgumentOutOfRangeException("ScreenHeight", height, "Screen must have either 1 or 2 rows");
            }
            if (width * height > 80)
            {
                throw new ArgumentException("At most 80 characters are allowed");
            }

            if (settings.PatternWidth != 5)
            {
                throw new ArgumentOutOfRangeException("PatternWidth", settings.PatternWidth, "Pattern must be 5 pixels width");
            }
            if (settings.PatternHeight != 8 && settings.PatternHeight != 10)
            {
                throw new ArgumentOutOfRangeException("PatternHeight", settings.PatternWidth, "Pattern must be either 7 or 10 pixels height");
            }
            if (settings.PatternHeight == 10 && height == 2)
            {
                throw new ArgumentException("10 pixels height pattern cannot be used with 2 rows");
            }

            functions = (settings.PatternHeight == 8 ? Functions.Matrix5x8 : Functions.Matrix5x10)
                        | (height == 1 ? Functions.OneLine : Functions.TwoLines)
                        | (this.dataPins.Length == 4 ? Functions.Data4bits : Functions.Data8bits);

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

            encoding = settings.Encoding;

            registerSelectPin.Write(false);
            clockPin.Write(false);
            foreach (var dataPin in this.dataPins)
            {
                dataPin.Write(false);
            }

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

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

            Clear();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="Hd44780LcdConnection"/> class.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="registerSelectPin">The register select pin.</param>
        /// <param name="clockPin">The clock pin.</param>
        /// <param name="dataPins">The data pins.</param>
        public Hd44780LcdConnection(Hd44780LcdConnectionSettings settings, IOutputPin registerSelectPin, IOutputPin clockPin, IEnumerable<IOutputPin> dataPins)
        {
            settings = settings ?? new Hd44780LcdConnectionSettings();

            this.registerSelectPin = registerSelectPin;
            this.clockPin = clockPin;
            this.dataPins = dataPins.ToArray();

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

            width = settings.ScreenWidth;
            height = settings.ScreenHeight;
            if (height < 1 || height > 2)
                throw new ArgumentOutOfRangeException("ScreenHeight", height, "Screen must have either 1 or 2 rows");
            if (width * height > 80)
                throw new ArgumentException("At most 80 characters are allowed");

            if (settings.PatternWidth != 5)
                throw new ArgumentOutOfRangeException("PatternWidth", settings.PatternWidth, "Pattern must be 5 pixels width");
            if (settings.PatternHeight != 8 && settings.PatternHeight != 10)
                throw new ArgumentOutOfRangeException("PatternHeight", settings.PatternWidth, "Pattern must be either 7 or 10 pixels height");
            if (settings.PatternHeight == 10 && height == 2)
                throw new ArgumentException("10 pixels height pattern cannot be used with 2 rows");

            functions = (settings.PatternHeight == 8 ? Functions.Matrix5x8 : Functions.Matrix5x10)
                | (height == 1 ? Functions.OneLine : Functions.TwoLines)
                | (this.dataPins.Length == 4 ? Functions.Data4bits : Functions.Data8bits);

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

            encoding = settings.Encoding;

            registerSelectPin.Write(false);
            clockPin.Write(false);
            foreach (var dataPin in this.dataPins)
                dataPin.Write(false);

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

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

            Clear();
        }