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