/// <summary>
        ///     Write one or more words of data to the bus with the command flag asserted (RS=0);
        /// </summary>
        /// <param name="command"></param>
        public async Task WriteCommandAsync(uint[] command)
        {
            var cmdLen = command.Length;

            byte[] cmd;

            // we have data to send with the command
            if (DataBus.Count <= 8)
            {
                // 8-bit data
                cmd = new byte[cmdLen + 3];

                for (var i = 0; i < cmdLen; i++)
                {
                    cmd[3 + i] = (byte)command[i];
                }
            }
            else
            {
                // 16-bit data
                cmd = new byte[cmdLen * 2 + 3];

                for (var i = 0; i < cmdLen; i++)
                {
                    cmd[3 + i * 2]     = (byte)(command[2 * i] >> 8);
                    cmd[3 + i * 2 + 1] = (byte)command[2 * i + 1];
                }
            }

            cmd[0] = (byte)DeviceCommands.ParallelTransaction;
            cmd[1] = (byte)ParallelCmd.WriteCommand;
            cmd[2] = (byte)cmdLen;
            await _board.SendPeripheralConfigPacketAsync(cmd).ConfigureAwait(false);
        }
Beispiel #2
0
        /// <summary>
        ///     Send data
        /// </summary>
        /// <param name="dataToSend">The data to send</param>
        /// <returns>An awaitable task that completes upon transmission of the data</returns>
        public async Task SendAsync(byte[] dataToSend)
        {
            if (dataToSend.Length > 63)
            {
                throw new Exception("The maximum UART length for one transaction is 63 bytes");
            }

            var data = new byte[dataToSend.Length + 3];

            data[0] = (byte)DeviceCommands.UartTransaction;
            data[1] = (byte)UartCommand.Transmit;
            data[2] = (byte)dataToSend.Length;
            dataToSend.CopyTo(data, 3);
            using (await _device.ComsLock.LockAsync().ConfigureAwait(false))
            {
                await _device.SendPeripheralConfigPacketAsync(data).ConfigureAwait(false);

                await _device.ReceiveCommsResponsePacketAsync(1).ConfigureAwait(false);
            }
        }
        internal Task SendConfigAsync()
        {
            var configuration = new byte[9];

            configuration[0] = (byte)DeviceCommands.PwmConfig;

            configuration[1] = (byte)_mode;
            configuration[2] = (byte)_frequency;

            configuration[3] = _dutyCyclePin7[0];
            configuration[4] = _dutyCyclePin7[1];

            configuration[5] = _dutyCyclePin8[0];
            configuration[6] = _dutyCyclePin8[1];

            configuration[7] = _dutyCyclePin9[0];
            configuration[8] = _dutyCyclePin9[1];

            return(_board.SendPeripheralConfigPacketAsync(configuration));
        }
Beispiel #4
0
        /// <summary>
        ///     Send/receive data
        /// </summary>
        /// <param name="dataToWrite">
        ///     a byte array of the data to send. The length of the transaction is determined by the length of this array.
        /// </param>
        /// <param name="chipSelect">The chip select pin, if any, to use during this transaction.</param>
        /// <param name="chipSelectMode">The chip select mode to use during this transaction (if a CS pin is selected)</param>
        /// <param name="speedMhz">The speed to perform this transaction at.</param>
        /// <param name="burstMode"The burst mode (if any) to use.</param>
        /// <param name="spiMode">The SPI mode to use during this transaction.</param>
        /// <returns>An awaitable byte array with the received data.</returns>
        public async Task <byte[]> SendReceiveAsync(byte[] dataToWrite, SpiChipSelectPin chipSelect = null,
                                                    ChipSelectMode chipSelectMode = ChipSelectMode.SpiActiveLow, double speedMhz = 6,
                                                    SpiBurstMode burstMode        = SpiBurstMode.NoBurst, SpiMode spiMode = SpiMode.Mode00)
        {
            var transactionLength = dataToWrite.Length;
            var returnedData      = new byte[transactionLength];

            if (Enabled != true)
            {
                Utility.Error("SPI module must be enabled before starting transaction", true);
            }

            if (chipSelect != null && chipSelect.SpiModule != this)
            {
                Utility.Error("Chip select pin must belong to this SPI module", true);
            }

            if (speedMhz > 0.8 && speedMhz < 6)
            {
                Debug.WriteLine(
                    "NOTICE: automatically rounding up SPI speed to 6 MHz, due to a possible silicon bug. This bug affects SPI speeds between 0.8 and 6 MHz, so if you need a speed lower than 6 MHz, please set to 0.8 MHz or lower.");

                speedMhz = 6;
            }

            using (await _device.ComsLock.LockAsync().ConfigureAwait(false))
            {
                var spi0Ckr = (int)Math.Round(24.0 / speedMhz - 1);
                if (spi0Ckr > 255.0)
                {
                    spi0Ckr = 255;
                    Debug.WriteLine(
                        "NOTICE: Requested SPI frequency of {0} MHz is below the minimum frequency, and will be clipped to 0.09375 MHz (93.75 kHz).",
                        speedMhz);
                }
                else if (spi0Ckr < 0)
                {
                    spi0Ckr = 0;
                    Debug.WriteLine(
                        "NOTICE: Requested SPI frequency of {0} MHz is above the maximum frequency, and will be clipped to 24 MHz.",
                        speedMhz);
                }

                var actualFrequency = 48.0 / (2.0 * (spi0Ckr + 1.0));

                if (Math.Abs(actualFrequency - speedMhz) > 1)
                {
                    Debug.WriteLine(
                        "NOTICE: SPI module actual frequency of {0} MHz is more than 1 MHz away from the requested frequency of {1} MHz",
                        actualFrequency, speedMhz);
                }

                if (dataToWrite.Length > 255)
                {
                    throw new Exception("Maximum packet length is 255 bytes");
                }

                var header = new byte[7];
                header[0] = (byte)DeviceCommands.SpiTransaction;
                header[1] = (byte)(chipSelect?.PinNumber ?? 255);
                header[2] = (byte)chipSelectMode;
                header[3] = (byte)spi0Ckr;
                header[4] = (byte)spiMode;
                header[5] = (byte)burstMode;
                header[6] = (byte)transactionLength;

                // just send the header
                if (burstMode == SpiBurstMode.BurstRx)
                {
                    await _device.SendPeripheralConfigPacketAsync(header).ConfigureAwait(false);
                }
                else
                {
                    var dataToSend = new byte[transactionLength + header.Length];
                    Array.Copy(header, dataToSend, header.Length);
                    Array.Copy(dataToWrite, 0, dataToSend, header.Length, transactionLength);

                    var bytesRemaining = dataToSend.Length;
                    var offset         = 0;
                    while (bytesRemaining > 0)
                    {
                        var transferLength = bytesRemaining > 64 ? 64 : bytesRemaining;
                        var tmp            = dataToSend.Skip(offset).Take(transferLength);
                        await _device.SendPeripheralConfigPacketAsync(tmp.ToArray()).ConfigureAwait(false);

                        offset         += transferLength;
                        bytesRemaining -= transferLength;
                    }
                }

                // no need to wait if we're not reading anything
                if (burstMode != SpiBurstMode.BurstTx)
                {
                    var bytesRemaining = transactionLength;
                    var srcIndex       = 0;
                    while (bytesRemaining > 0)
                    {
                        var numBytesToTransfer = bytesRemaining > 64 ? 64 : bytesRemaining;
                        var receivedData       = await _device.ReceiveCommsResponsePacketAsync((uint)numBytesToTransfer)
                                                 .ConfigureAwait(false);

                        Array.Copy(receivedData, 0, returnedData, srcIndex,
                                   receivedData.Length); // just in case we don't get what we're expecting
                        srcIndex       += numBytesToTransfer;
                        bytesRemaining -= numBytesToTransfer;
                    }
                }
            }

            return(returnedData);
        }
Beispiel #5
0
        /// <summary>
        ///     Sends and Receives data.
        /// </summary>
        /// <param name="address">The 7-bit address of the device. This address should not include the read/write bit.</param>
        /// <param name="dataToWrite">Array of one or more bytes to write to the device.</param>
        /// <param name="numBytesToRead">Number of bytes to receive from the device.</param>
        /// <returns>Data read from the device.</returns>

        /**
         * Reading and writing data occurs according to dataToWrite and numBytesToRead.
         *
         * The board will write the 7-bit address. If dataToWrite is set, the "read" bit is cleared to indicate a "write" transaction, and %Treehopper will write dataToWrite to the board. If numBytesToRead is 0, a stop condition will be sent. But if numBytesToRead is not 0, a restart condition will be sent, followed by the address and "read" bit. %Treehopper will then read numBytesToRead bytes from the device.
         *
         * On the other hand, if dataToWrite is null, the board will write the 7-bit address, setting the "read" bit and reading out numBytesToRead bytes.
         *
         * By supporting both null dataToWrite and numBytesToRead=0 conditions, this function can be used for all standard I2C/SMBus transactions.
         *
         * Most %I2C devices use a register-based scheme for exchanging data; consider using Treehopper.Libraries.SMBusDevice for interacting with these devices.
         */

        public async Task <byte[]> SendReceiveAsync(byte address, byte[] dataToWrite, byte numBytesToRead)
        {
            if (!Enabled)
            {
                Debug.WriteLine(
                    "NOTICE: I2c.SendReceive() called before enabling the peripheral. This call will be ignored.");
            }

            var receivedData = new byte[numBytesToRead];
            var txLen        = dataToWrite?.Length ?? 0;

            using (await _device.ComsLock.LockAsync().ConfigureAwait(false))
            {
                var dataToSend = new byte[4 + txLen]; // 2 bytes for the header
                dataToSend[0] = (byte)DeviceCommands.I2cTransaction;
                dataToSend[1] = address;
                dataToSend[2] = (byte)txLen;  // total length (0-255)
                dataToSend[3] = numBytesToRead;

                if (txLen > 0)
                {
                    Array.Copy(dataToWrite, 0, dataToSend, 4, txLen);
                }

                var bytesRemaining = dataToSend.Length;
                var offset         = 0;

                // for long transactions (> 64 bytes - 4 byte header), we send <=64 byte chunks, one by one.
                while (bytesRemaining > 0)
                {
                    var transferLength = bytesRemaining > 64 ? 64 : bytesRemaining;
                    var tmp            = dataToSend.Skip(offset).Take(transferLength);
                    await _device.SendPeripheralConfigPacketAsync(tmp.ToArray()).ConfigureAwait(false);

                    offset         += transferLength;
                    bytesRemaining -= transferLength;
                }

                if (numBytesToRead == 0)
                {
                    var result = await _device.ReceiveCommsResponsePacketAsync(1).ConfigureAwait(false);

                    if (result[0] != 255)
                    {
                        var error = (I2CTransferError)result[0];
                        Debug.WriteLine("NOTICE: I2C transaction resulted in an error: " + error);
                        if (TreehopperUsb.Settings.ThrowExceptions)
                        {
                            throw new I2CTransferException {
                                      Error = error
                            }
                        }
                        ;
                    }
                }
                else
                {
                    bytesRemaining = numBytesToRead + 1; // received data length + status byte
                    var srcIndex = 0;
                    var result   = new byte[bytesRemaining];
                    while (bytesRemaining > 0)
                    {
                        var numBytesToTransfer = bytesRemaining > 64 ? 64 : bytesRemaining;
                        var chunk = await _device.ReceiveCommsResponsePacketAsync((uint)numBytesToTransfer).ConfigureAwait(false);

                        Array.Copy(chunk, 0, result, srcIndex,
                                   chunk.Length); // just in case we don't get what we're expecting
                        srcIndex       += numBytesToTransfer;
                        bytesRemaining -= numBytesToTransfer;
                    }

                    if (result[0] != 255)
                    {
                        var error = (I2CTransferError)result[0];
                        Debug.WriteLine("NOTICE: I2C transaction resulted in an error: " + error);
                        if (TreehopperUsb.Settings.ThrowExceptions)
                        {
                            throw new I2CTransferException {
                                      Error = error
                            }
                        }
                        ;
                    }
                    else
                    {
                        Array.Copy(result, 1, receivedData, 0, numBytesToRead);
                    }
                }
            }

            return(receivedData);
        }
        private Task UpdateConfigAsync()
        {
            if (_pins.Count > 0)
            {
                foreach (var entry in _pins)
                {
                    // for pins that use pulse width, calculate value based on resolution
                    if (entry.Value.UsePulseWidth)
                    {
                        entry.Value.Ticks = (ushort)(entry.Value.PulseWidthUs / _resolution);

                        // just in case the user wants to retrieve duty cycle, update its value, too
                        entry.Value.DutyCycle = entry.Value.Ticks / 65535d;
                    }
                    else
                    {
                        // for pins that use duty-cycle, calculate based on period count
                        entry.Value.Ticks = (ushort)Math.Round(entry.Value.DutyCycle * 65535);

                        // just in case the user wants to retrieve pulse width, update its value too
                        entry.Value.PulseWidthUs = (int)(entry.Value.Ticks * _resolution);
                    }
                }


                // now the fun part; let's figure out the delta delays between each pin
                var orderedValues = _pins.Values.OrderBy(pin => pin.Ticks);

                var list = orderedValues.ToList();

                var count  = list.Count + 1;
                var config = new byte[2 + 3 * count]; // { , (byte)pins.Count, timerVal };
                config[0] = (byte)DeviceCommands.SoftPwmConfig;
                config[1] = (byte)count;
                if (count > 1)
                {
                    var i    = 2;
                    var time = 0;

                    for (var j = 0; j < count; j++)
                    {
                        int ticks;

                        if (j < list.Count)
                        {
                            ticks = list[j].Ticks - time;
                        }
                        else
                        {
                            ticks = ushort.MaxValue - time;
                        }

                        var tmrVal = ushort.MaxValue - ticks;
                        if (j == 0)
                        {
                            config[i++] = 0;
                        }
                        else
                        {
                            config[i++] = (byte)list[j - 1].Pin.PinNumber;
                        }

                        config[i++] = (byte)(tmrVal >> 8);
                        config[i++] = (byte)(tmrVal & 0xff);
                        time       += ticks;
                    }
                }
                else
                {
                    config[1] = 0;
                }

                return(_board.SendPeripheralConfigPacketAsync(config));
            }
            else
            {
                // disable SoftPWM
                return(_board.SendPeripheralConfigPacketAsync(new byte[] { (byte)DeviceCommands.SoftPwmConfig, 0 }));
            }
        }