Example #1
0
        /// <summary>
        /// Writes the "on" and "off" values of a channel together, and updates it in <see cref="Channels"/>.
        /// </summary>
        /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param>
        /// <param name="value"><see cref="Pca9685ChannelValue"/> to write.</param>
        /// <returns>
        /// Updated channel value or null when all channels were updated.
        /// </returns>
        public Pca9685ChannelValue?WriteChannel(int index, Pca9685ChannelValue value)
        {
            // Validate
            if (index <0 | index> ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            // Calculate register address
            var register = GetChannelAddress(index);

            // Convert and write value
            var bytes = value.ToByteArray();

            I2cExtensions.WriteJoinBytes(_hardware, register, bytes);

            // Read and return result when single channel
            if (index < ChannelCount)
            {
                return(ReadChannel(index));
            }

            // Read all channels when "all call".
            ReadAllChannels();
            return(null);
        }
Example #2
0
        /// <summary>
        /// Reads the PWM "off" (falling) value of a channel, and updates it in <see cref="Channels"/>.
        /// </summary>
        /// <param name="index">Zero based channel number (0-15).</param>
        /// <returns>Channel value.</returns>
        public int ReadChannelOff(int index)
        {
            // Validate
            if (index < 0 | index >= ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }

            // Calculate register address of second word value
            var register = (byte)(GetChannelAddress(index) + sizeof(ushort));

            // Read and convert value
            var bytes = I2cExtensions.WriteReadBytes(_hardware, register, sizeof(ushort));
            var value = BitConverter.ToUInt16(bytes, 0);

            // Update channel when changed
            var oldValue = _channels[index];

            if (oldValue.Off != value)
            {
                _channels[index] = new Pca9685ChannelValue(oldValue.On, value);
            }

            // Return result
            return(value);
        }
Example #3
0
        /// <summary>
        /// Calculates the prescale value from the frequency (according to <see cref="ClockSpeed"/>)
        /// then writes that register, then calls <see cref="ReadFrequency"/> to update properties.
        /// Note the actual frequency may differ to the requested frequency due to clock scale (rounding).
        /// </summary>
        /// <remarks>
        /// The prescale can only be set during sleep mode. This method enters <see cref="Sleep"/> if necessary,
        /// then only if the device was awake before, calls <see cref="Wake"/> afterwards. It's important not to
        /// start output unexpectedly to avoid damage, i.e. if the device was sleeping before, the frequency is
        /// changed without starting the oscillator.
        /// </remarks>
        /// <param name="frequency">Desired frequency to set in Hz.</param>
        /// <returns>
        /// Effective frequency in Hz, read-back and recalculated after setting the desired frequency.
        /// Frequency in Hz. Related properties are also updated.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown when <paramref name="frequency"/> is less than <see cref="FrequencyMinimum"/> or greater than
        /// <see cref="FrequencyMaximum"/>.
        /// </exception>
        public int WriteFrequency(int frequency)
        {
            // Validate
            if (frequency < FrequencyMinimum || frequency > FrequencyMaximum)
            {
                throw new ArgumentOutOfRangeException(nameof(frequency));
            }

            // Calculate prescale
            var prescale = CalculatePrescale(frequency, ClockSpeed);

            // Enter sleep mode and record wake status
            var wasAwake = Sleep();

            // Write prescale
            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.Prescale, prescale);

            // Read result
            var actual = ReadFrequency();

            // Wake-up if previously running
            if (wasAwake)
            {
                Wake();
            }

            // Update related properties
            PwmMsMinimum = Pca9685ChannelValue.CalculateWidthMs(frequency, 0);
            PwmMsMaximum = Pca9685ChannelValue.CalculateWidthMs(frequency, Pca9685ChannelValue.Maximum);

            // Return actual frequency
            return(actual);
        }
Example #4
0
        /// <summary>
        /// Reads all channels and updates <see cref="Channels"/>.
        /// </summary>
        public void ReadAllChannels()
        {
            // Read all channels as one block of data
            var data = I2cExtensions.WriteReadBytes(_hardware, ChannelStartAddress, ChannelSize * ChannelCount);

            // Update properties
            for (var index = 0; index < ChannelCount; index++)
            {
                _channels[index] = Pca9685ChannelValue.FromByteArray(data, ChannelSize * index);
            }
        }
Example #5
0
        /// <summary>
        /// Reads the prescale register and calculates the <see cref="Frequency"/> (and related properties)
        /// based on <see cref="ClockSpeed"/>.
        /// </summary>
        /// <returns>
        /// Frequency in Hz. Related properties are also updated.
        /// </returns>
        public int ReadFrequency()
        {
            // Read prescale register
            var prescale = I2cExtensions.WriteReadByte(_hardware, (byte)Pca9685Register.Prescale);

            // Calculate frequency
            var frequency = CalculateFrequency(prescale, ClockSpeed);

            // Update related properties
            Frequency    = frequency;
            PwmMsMinimum = Pca9685ChannelValue.CalculateWidthMs(frequency, 0);
            PwmMsMaximum = Pca9685ChannelValue.CalculateWidthMs(frequency, Pca9685ChannelValue.Maximum);

            // Return result
            return(frequency);
        }
Example #6
0
        /// <summary>
        /// Reads a whole channel value (on and off), and updates it in <see cref="Channels"/>.
        /// </summary>
        /// <param name="index">Zero based channel number (0-15).</param>
        /// <returns>Channel value</returns>
        public Pca9685ChannelValue ReadChannel(int index)
        {
            // Validate
            if (index < 0 | index >= ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }

            // Calculate register address
            var register = GetChannelAddress(index);

            // Read value
            var bytes = I2cExtensions.WriteReadBytes(_hardware, register, sizeof(ushort) * 2);

            // Update channel property and return result
            var value = Pca9685ChannelValue.FromByteArray(bytes);

            return(_channels[index] = value);
        }
Example #7
0
        /// <summary>
        /// Writes multiple channels together (both "on" and "off" values), and updates it in <see cref="Channels"/>.
        /// </summary>
        /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param>
        /// <param name="values">Collection of <see cref="Pca9685ChannelValue"/>s to write.</param>
        public void WriteChannels(int index, IList <Pca9685ChannelValue> values)
        {
            // Validate
            if (index <0 | index> ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }
            if (values == null || values.Count == 0)
            {
                throw new ArgumentNullException(nameof(values));
            }
            var count = values.Count;

            if (index + count > ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(values));
            }

            // Build I2C packet
            var data = new byte[1 + ChannelSize * count];

            // Calculate first register address
            var register = GetChannelAddress(index);

            data[0] = register;

            // Write channels and update properties
            for (int dataIndex = 0, dataOffset = 1; dataIndex < count; dataIndex++, dataOffset += ChannelSize)
            {
                // Get channel data
                var channelData = values[dataIndex].ToByteArray();

                // Copy to buffer
                Array.ConstrainedCopy(channelData, 0, data, dataOffset, ChannelSize);

                // Update property
                _channels[index + dataIndex] = Pca9685ChannelValue.FromByteArray(channelData);
            }

            // Send packet
            I2cExtensions.WriteBytes(_hardware, data);
        }
Example #8
0
        /// <summary>
        /// Reads multiple channel values (both on and off for each), and updates it in <see cref="Channels"/>.
        /// </summary>
        /// <param name="index">Zero based channel number (0-15).</param>
        /// <param name="count">Number of channels to read.</param>
        /// <returns>Channel values</returns>
        public Collection <Pca9685ChannelValue> ReadChannels(int index, int count)
        {
            // Validate
            if (index < 0 | index >= ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }
            if (count < 1 || index + count > ChannelCount)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            // Calculate register address
            var register = GetChannelAddress(index);

            // Send I2C command to read channels in one operation
            var data = I2cExtensions.WriteReadBytes(_hardware, register, ChannelSize * count);

            // Update channel properties and add to results
            var results = new Collection <Pca9685ChannelValue>();

            for (int channelIndex = index, offset = 0; count > 0; count--, channelIndex++, offset += ChannelSize)
            {
                // Calculate value
                var value = Pca9685ChannelValue.FromByteArray(data, offset);

                // Update property
                _channels[channelIndex] = value;

                // Add to results
                results.Add(value);
            }

            // Return results
            return(results);
        }
Example #9
0
 /// <summary>
 /// Calculates the "on" and "off" values of a channel from milliseconds (and optional delay),
 /// then writes them together, and updates it in <see cref="Channels"/>.
 /// </summary>
 /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param>
 /// <param name="width">
 /// Pulse width in milliseconds. Cannot be greater than one clock interval (1000 / frequency).
 /// </param>
 /// <param name="delay">Optional delay in milliseconds. Cannot be greater than one clock interval (1000 / frequency).</param>
 /// <returns>
 /// Updated channel value or null when all channels were updated.
 /// </returns>
 public Pca9685ChannelValue?WriteChannelMs(int index, decimal width, int delay = 0)
 {
     // Call overloaded method
     return(WriteChannel(index, Pca9685ChannelValue.FromWidthMs(width, Frequency, delay)));
 }
Example #10
0
 /// <summary>
 /// Calculates the "on" and "off" values of a channel from length (and optional delay),
 /// then writes them together, and updates it in <see cref="Channels"/>.
 /// </summary>
 /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param>
 /// <param name="width">Pulse width in clock ticks.</param>
 /// <param name="delay">Optional delay in clock ticks.</param>
 /// <returns>
 /// Updated channel value or null when all channels were updated.
 /// </returns>
 public Pca9685ChannelValue?WriteChannelLength(int index, int width, int delay = 0)
 {
     // Call overloaded method
     return(WriteChannel(index, Pca9685ChannelValue.FromWidth(width, delay)));
 }