All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pi4j.library.pigpio.impl.PiGpioSocketImpl Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
package com.pi4j.library.pigpio.impl;

/*-
 * #%L
 * **********************************************************************
 * ORGANIZATION  :  Pi4J
 * PROJECT       :  Pi4J :: LIBRARY  :: JNI Wrapper for PIGPIO Library
 * FILENAME      :  PiGpioSocketImpl.java
 *
 * This file is part of the Pi4J project. More information about
 * this project can be found here:  https://pi4j.com/
 * **********************************************************************
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.pi4j.library.pigpio.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

import static com.pi4j.library.pigpio.PiGpioCmd.*;
import static com.pi4j.library.pigpio.PiGpioConst.DEFAULT_HOST;
import static com.pi4j.library.pigpio.PiGpioConst.DEFAULT_PORT;

/**
 * 

PiGpioSocketImpl class.

* * @author Robert Savage (http://www.savagehomeautomation.com) * @version $Id: $Id */ public class PiGpioSocketImpl extends PiGpioSocketBase implements PiGpio { protected Logger logger = LoggerFactory.getLogger(this.getClass()); /** * Creates a PiGpio instance using TCP Socket communication for remote I/O access. * Connects to a user specified socket hostname/ip address and port. * * @param host hostname or IP address of the RaspberryPi to connect to via TCP/IP socket. * @param port TCP port number of the RaspberryPi to connect to via TCP/IP socket. * @return a {@link com.pi4j.library.pigpio.PiGpio} object. */ public static PiGpio newInstance(String host, String port) { return new PiGpioSocketImpl(host, Integer.parseInt(port)); } /** * Creates a PiGpio instance using TCP Socket communication for remote I/O access. * Connects to a user specified socket hostname/ip address and port. * * @param host hostname or IP address of the RaspberryPi to connect to via TCP/IP socket. * @param port TCP port number of the RaspberryPi to connect to via TCP/IP socket. * @return a {@link com.pi4j.library.pigpio.PiGpio} object. */ public static PiGpio newInstance(String host, int port) { return new PiGpioSocketImpl(host, port); } /** * Creates a PiGpio instance using TCP Socket communication for remote I/O access. * Connects to a user specified socket hostname/ip address using the default port (8888). * * @param host hostname or IP address of the RaspberryPi to connect to via TCP/IP socket. * @return a {@link com.pi4j.library.pigpio.PiGpio} object. */ public static PiGpio newInstance(String host) { return new PiGpioSocketImpl(host, DEFAULT_PORT); } /** * Creates a PiGpio instance using TCP Socket communication for remote I/O access. * Connects to the local system (127.0.0.1) using the default port (8888). * * @return a {@link com.pi4j.library.pigpio.PiGpio} object. */ public static PiGpio newInstance() { return new PiGpioSocketImpl(DEFAULT_HOST, DEFAULT_PORT); } /** * DEFAULT PRIVATE CONSTRUCTOR *

* Connects to a user specified socket hostname/ip address and port. * * @param host hostname or IP address of the RaspberryPi to connect to via TCP/IP socket. * @param port TCP port number of the RaspberryPi to connect to via TCP/IP socket. */ private PiGpioSocketImpl(String host, int port) { super(host, port); } /** * {@inheritDoc} * * Returns the pigpio library version. * @see PIGPIO::gpioVersion */ @Override public int gpioVersion() { logger.trace("[VERSION] -> GET VERSION"); validateReady(); PiGpioPacket result = sendCommand(PIGPV); int version = result.result(); logger.trace("[VERSION] <- RESULT={}", version); return version; } /** * {@inheritDoc} * * Returns the hardware revision. *

* If the hardware revision can not be found or is not a valid hexadecimal number the function returns 0. * The hardware revision is the last few characters on the Revision line of /proc/cpuinfo. * The revision number can be used to determine the assignment of GPIO to pins (see gpio). *

* There are at least three types of board. * - Type 1 boards have hardware revision numbers of 2 and 3. * - Type 2 boards have hardware revision numbers of 4, 5, 6, and 15. * - Type 3 boards have hardware revision numbers of 16 or greater. *

* for "Revision : 0002" the function returns 2. * for "Revision : 000f" the function returns 15. * for "Revision : 000g" the function returns 0. * @see PIGPIO::gpioHardwareRevision */ @Override public long gpioHardwareRevision() { logger.trace("[HARDWARE] -> GET REVISION"); validateReady(); PiGpioPacket result = sendCommand(HWVER); long revision = result.result(); logger.trace("[HARDWARE] <- REVISION: {}", revision); if(revision <= 0) throw new PiGpioException("Hardware revision could not be determined."); return revision; } // ***************************************************************************************************** // ***************************************************************************************************** // GPIO IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * Sets or clears resistor pull ups or downs on the GPIO. * @see PIGPIO::gpioSetPullUpDown */ @Override public void gpioSetPullUpDown(int pin, PiGpioPud pud) { logger.trace("[GPIO::PUD-SET] -> PIN: {}; PUD={}({});", pin, pud.name(), pud.value()); validateReady(); validatePin(pin); PiGpioPacket result = sendCommand(PUD, pin, pud.value()); logger.trace("[GPIO::PUD-SET] <- PIN: {}; PUD={}({}); SUCCESS={}", pud.name(), pud.value(), result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_GPIO or PI_BAD_MODE. } /** * {@inheritDoc} * * Gets the GPIO mode. * @see PIGPIO::gpioGetMode */ @Override public PiGpioMode gpioGetMode(int pin) { logger.trace("[GPIO::MODE-GET] -> PIN: {};", pin); validateReady(); validatePin(pin); PiGpioPacket result = sendCommand(MODEG, pin); validateResult(result); // Returns the GPIO mode if OK, otherwise PI_BAD_GPIO. PiGpioMode mode = PiGpioMode.from(result.result()); logger.trace("[GPIO::MODE-GET] <- PIN: {}; MODE={}({})", pin, mode.name(), mode.value()); return mode; } /** * {@inheritDoc} * * Sets the GPIO mode, typically input or output. *

* gpio: 0-53 * mode: 0-7 * @see PIGPIO::gpioSetMode */ @Override public void gpioSetMode(int pin, PiGpioMode mode) { logger.trace("[GPIO::MODE-SET] -> PIN: {}; MODE={}({});", pin, mode.name(), mode.value()); validateReady(); validatePin(pin); PiGpioPacket result = sendCommand(MODES, pin, mode.value()); logger.trace("[GPIO::MODE-SET] <- PIN: {}; MODE={}({}); SUCCESS={}", mode.name(), mode.value(), result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_GPIO or PI_BAD_PUD. } /** * {@inheritDoc} * * Reads the GPIO level, on (HIGH) or off (LOW). * @see PIGPIO::gpioRead */ @Override public PiGpioState gpioRead(int pin) { logger.trace("[GPIO::GET] -> PIN: {}", pin); validateReady(); validatePin(pin); PiGpioPacket result = sendCommand(READ, pin); validateResult(result); // Returns the GPIO level if OK, otherwise PI_BAD_GPIO. PiGpioState state = PiGpioState.from(result.p3()); // result value stored in P3 logger.trace("[GPIO::GET] <- PIN: {} is {}({})", pin, state.name(), state.value()); return state; } /** * {@inheritDoc} * * Sets the GPIO level, on (HIGH) or off (LOW). * @see PIGPIO::gpioWrite */ @Override public void gpioWrite(int pin, PiGpioState state) { logger.trace("[GPIO::SET] -> PIN: {}; {}({});", pin, state.name(), state.value()); validateReady(); validatePin(pin); PiGpioPacket result = sendCommand(WRITE, pin, state.value()); logger.trace("[GPIO::SET] <- PIN: {}; {}({}); SUCCESS={}", pin, state.name(), state.value(), result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_GPIO or PI_BAD_LEVEL. } /** * {@inheritDoc} * * Sets a glitch filter on a GPIO. (AKA Debounce) *

* Level changes on the GPIO are not reported unless the level has been stable for at * least 'steady' microseconds. The level is then reported. Level changes of less * than 'steady' microseconds are ignored. *

* This filter affects the GPIO samples returned to callbacks set up with: * - gpioSetAlertFunc * - gpioSetAlertFuncEx * - gpioSetGetSamplesFunc * - gpioSetGetSamplesFuncEx. *

* It does not affect interrupts set up with gpioSetISRFunc, gpioSetISRFuncEx, or * levels read by gpioRead, gpioRead_Bits_0_31, or gpioRead_Bits_32_53. * Each (stable) edge will be timestamped steady microseconds after it was first detected. * @see PIGPIO::gpioGlitchFilter */ public void gpioGlitchFilter(int pin, int steady) { logger.trace("[GPIO::GLITCH] -> PIN: {}; INTERVAL: {};", pin, steady); validateReady(); validatePin(pin); validateGpioGlitchFilter(steady); PiGpioPacket result = sendCommand(FG, pin, steady); logger.trace("[GPIO::GLITCH] <- PIN: {}; SUCCESS={}", pin, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER. } /** * {@inheritDoc} * * Sets a noise filter on a GPIO. *

* Level changes on the GPIO are ignored until a level which has been stable for 'steady' * microseconds is detected. Level changes on the GPIO are then reported for 'active' * microseconds after which the process repeats. *

* This filter affects the GPIO samples returned to callbacks set up with: * - gpioSetAlertFunc * - gpioSetAlertFuncEx * - gpioSetGetSamplesFunc * - gpioSetGetSamplesFuncEx. * * It does not affect interrupts set up with gpioSetISRFunc, gpioSetISRFuncEx, or * levels read by gpioRead, gpioRead_Bits_0_31, or gpioRead_Bits_32_53. *

* Level changes before and after the active period may be reported. * Your software must be designed to cope with such reports. * @see PIGPIO::gpioGlitchFilter */ public void gpioNoiseFilter(int pin, int steady, int active){ logger.trace("[GPIO::NOISE] -> PIN: {}; INTERVAL: {};", pin, steady); validateReady(); validatePin(pin); validateGpioNoiseFilter(steady, active); PiGpioPacket result = sendCommand(FN, pin, steady).data(active); logger.trace("[GPIO::NOISE] <- PIN: {}; SUCCESS={}", pin, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER. } // ***************************************************************************************************** // ***************************************************************************************************** // PWM IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * Starts PWM on the GPIO, dutycycle between 0 (off) and range (fully on). Range defaults to 255. *

* This and the servo functionality use the DMA and PWM or PCM peripherals to control and schedule * the pulse lengths and duty cycles. * @see PIGPIO::gpioPWM */ @Override public void gpioPWM(int pin, int dutyCycle) { logger.trace("[PWM::SET] -> PIN: {}; DUTY-CYCLE={};", pin, dutyCycle); validateReady(); validateUserPin(pin); validateDutyCycle(dutyCycle); PiGpioPacket result = sendCommand(PWM, pin, dutyCycle); logger.trace("[PWM::SET] <- PIN: {}; DUTY-CYCLE={}; SUCCESS={}", pin, dutyCycle, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_GPIO or PI_BAD_LEVEL. } /** * {@inheritDoc} * * Returns the PWM dutycycle setting for the GPIO. *

* For normal PWM the dutycycle will be out of the defined range for the GPIO (see gpioGetPWMrange). * If a hardware clock is active on the GPIO the reported dutycycle will be 500000 (500k) out of 1000000 (1M). * If hardware PWM is active on the GPIO the reported dutycycle will be out of a 1000000 (1M). *

* Normal PWM range defaults to 255. * @see PIGPIO::gpioGetPWMdutycycle */ @Override public int gpioGetPWMdutycycle(int pin) { logger.trace("[PWM::GET] -> PIN: {}", pin); validateReady(); validateUserPin(pin); PiGpioPacket result = sendCommand(GDC, pin); var dutyCycle = result.result(); logger.trace("[PWM::GET] <- PIN: {}; DUTY-CYCLE={}; SUCCESS={}", pin, dutyCycle, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_NOT_PWM_GPIO. return dutyCycle; } /** * {@inheritDoc} * * Selects the dutycycle range to be used for the GPIO. Subsequent calls to gpioPWM will use a dutycycle * between 0 (off) and range (fully on. If PWM is currently active on the GPIO its dutycycle will be * scaled to reflect the new range. *

* The real range, the number of steps between fully off and fully on for each frequency, * is given in the following table. *

* ------------------------------------------------------- * #1 #2 #3 #4 #5 #6 #7 #8 #9 * 25, 50, 100, 125, 200, 250, 400, 500, 625, * ------------------------------------------------------- * #10 #11 #12 #13 #14 #15 #16 #17 #18 * 800, 1000, 1250, 2000, 2500, 4000, 5000, 10000, 20000 * ------------------------------------------------------- *

* The real value set by gpioPWM is (dutycycle * real range) / range. *

* Example * gpioSetPWMrange(24, 2000); // Now 2000 is fully on * // 1000 is half on * // 500 is quarter on, etc. * @see PIGPIO::gpioSetPWMrange */ @Override public int gpioSetPWMrange(int pin, int range) { logger.trace("[PWM-RANGE::SET] -> PIN: {}; RANGE={}", pin, range); validateReady(); validateUserPin(pin); //validateDutyCycleRange(range); PiGpioPacket result = sendCommand(PRS, pin, range); var readRange = result.result(); logger.trace("[PWM-RANGE::SET] <- PIN: {}; REAL-RANGE={}; SUCCESS={}", pin, readRange, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_BAD_DUTYRANGE. return result.result(); } /** * {@inheritDoc} * * Returns the duty-cycle range used for the GPIO if OK. * If a hardware clock or hardware PWM is active on the GPIO the reported range will be 1000000 (1M). * @see PIGPIO::gpioGetPWMrange */ @Override public int gpioGetPWMrange(int pin) { logger.trace("[PWM-RANGE::GET] -> PIN: {}", pin); validateReady(); validateUserPin(pin); PiGpioPacket result = sendCommand(PRG, pin); var range = result.result(); logger.trace("[PWM-RANGE::GET] <- PIN: {}; RANGE={}; SUCCESS={}", pin, range, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_BAD_DUTYRANGE. return range; } /** * {@inheritDoc} * * Returns the real range used for the GPIO if OK. * If a hardware clock is active on the GPIO the reported real range will be 1000000 (1M). * If hardware PWM is active on the GPIO the reported real range will be approximately 250M * divided by the set PWM frequency. * @see PIGPIO::gpioGetPWMrealRange */ @Override public int gpioGetPWMrealRange(int pin) { logger.trace("[PWM-REAL-RANGE::GET] -> PIN: {}", pin); validateReady(); validateUserPin(pin); PiGpioPacket result = sendCommand(PRRG, pin); var range = result.result(); logger.trace("[PWM-REAL-RANGE::GET] <- PIN: {}; RANGE={}; SUCCESS={}", pin, range, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_BAD_DUTYRANGE. return range; } /** * {@inheritDoc} * * Sets the frequency in hertz to be used for the GPIO. *

* If PWM is currently active on the GPIO it will be switched off and then back on at the new frequency. * Each GPIO can be independently set to one of 18 different PWM frequencies. * The selectable frequencies depend upon the sample rate which may be 1, 2, 4, 5, 8, or 10 microseconds (default 5). *

* The frequencies for each sample rate are: *

* Hertz *

* 1: 40000 20000 10000 8000 5000 4000 2500 2000 1600 * 1250 1000 800 500 400 250 200 100 50 *

* 2: 20000 10000 5000 4000 2500 2000 1250 1000 800 * 625 500 400 250 200 125 100 50 25 *

* 4: 10000 5000 2500 2000 1250 1000 625 500 400 * 313 250 200 125 100 63 50 25 13 * sample * rate * (us) 5: 8000 4000 2000 1600 1000 800 500 400 320 * 250 200 160 100 80 50 40 20 10 *

* 8: 5000 2500 1250 1000 625 500 313 250 200 * 156 125 100 63 50 31 25 13 6 *

* 10: 4000 2000 1000 800 500 400 250 200 160 * 125 100 80 50 40 25 20 10 5 *

* * Example: * gpioSetPWMfrequency(23, 0); // Set GPIO23 to lowest frequency. * gpioSetPWMfrequency(24, 500); // Set GPIO24 to 500Hz. * gpioSetPWMfrequency(25, 100000); // Set GPIO25 to highest frequency. * @see PIGPIO::gpioSetPWMrange */ @Override public int gpioSetPWMfrequency(int pin, int frequency) { logger.trace("[PWM-FREQ::SET] -> PIN: {}; FREQUENCY={}", pin, frequency); validateReady(); validateUserPin(pin); // validateFrequency(frequency); TODO :: IMPLEMENT 'validateFrequency()' PiGpioPacket result = sendCommand(PFS, pin, frequency); var actualRange = result.result(); logger.trace("[PWM-FREQ::SET] <- PIN: {}; FREQUENCY={}; SUCCESS={}", pin, frequency, result.success()); validateResult(result); // Returns the numerically closest frequency if OK, otherwise PI_BAD_USER_GPIO. return actualRange; } /** * {@inheritDoc} * * Returns the frequency (in hertz) used for the GPIO *

* For normal PWM the frequency will be that defined for the GPIO by gpioSetPWMfrequency. * If a hardware clock is active on the GPIO the reported frequency will be that set by gpioHardwareClock. * If hardware PWM is active on the GPIO the reported frequency will be that set by gpioHardwarePWM. *

* Example: * f = gpioGetPWMfrequency(23); // Get frequency used for GPIO23. * @see PIGPIO::gpioGetPWMfrequency */ @Override public int gpioGetPWMfrequency(int pin) { logger.trace("[PWM-FREQ::GET] -> PIN: {}", pin); validateReady(); validateUserPin(pin); PiGpioPacket result = sendCommand(PFG, pin); var frequency = result.result(); logger.trace("[PWM-FREQ::GET] <- PIN: {}; FREQUENCY={}; SUCCESS={}", pin, frequency, result.success()); validateResult(result); // Returns the frequency (in hertz) used for the GPIO if OK, otherwise PI_BAD_USER_GPIO. return frequency; } /** * {@inheritDoc} * * Starts hardware PWM on a GPIO at the specified frequency and duty-cycle. * Frequencies above 30MHz are unlikely to work. *

* NOTE: Any waveform started by gpioWaveTxSend, or gpioWaveChain will be cancelled. *

* This function is only valid if the pigpio main clock is PCM. * The main clock defaults to PCM but may be overridden by a call to gpioCfgClock. *

* The same PWM channel is available on multiple GPIO. The latest frequency and duty-cycle * setting will be used by all GPIO which share a PWM channel. *

* The GPIO must be one of the following. *

* 12 PWM channel 0 All models but A and B * 13 PWM channel 1 All models but A and B * 18 PWM channel 0 All models * 19 PWM channel 1 All models but A and B *

* 40 PWM channel 0 Compute module only * 41 PWM channel 1 Compute module only * 45 PWM channel 1 Compute module only * 52 PWM channel 0 Compute module only * 53 PWM channel 1 Compute module only *

* * The actual number of steps between off and fully on is the integral part of * 250M/PWMfreq (375M/PWMfreq for the BCM2711). * The actual frequency set is 250M/steps (375M/steps for the BCM2711). * There will only be a million steps for a frequency of 250 (375 for the BCM2711). Lower * frequencies will have more steps and higher frequencies will have fewer steps. * dutyCycle is automatically scaled to take this into account. */ @Override public void gpioHardwarePWM(int pin, int frequency, int dutyCycle) { logger.trace("[HW-PWM::SET] -> PIN: {}; FREQUENCY={}; DUTY-CYCLE={}", pin, frequency, dutyCycle); validateReady(); validateUserPin(pin); // validateHwPwmFrequency(frequency); TODO :: IMPLEMENT 'validateHwPwmFrequency()' PiGpioPacket tx = new PiGpioPacket(HP, pin, frequency).data(dutyCycle); PiGpioPacket rx = sendPacket(tx); logger.trace("[HW-PWM::SET] <- PIN: {}; SUCCESS={}", pin, rx.success()); validateResult(rx); // Returns the numerically closest frequency if OK, otherwise PI_BAD_USER_GPIO. } // ***************************************************************************************************** // ***************************************************************************************************** // SERVO IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * Starts servo pulses on the GPIO, 0 (off), 500 (most anti-clockwise) to 2500 (most clockwise). *

* The range supported by servos varies and should probably be determined by experiment. A value * of 1500 should always be safe and represents the mid-point of rotation. You can DAMAGE a servo * if you command it to move beyond its limits. *

* The following causes an on pulse of 1500 microseconds duration to be transmitted on GPIO 17 at * a rate of 50 times per second. This will command a servo connected to GPIO 17 to rotate to its * mid-point. *

* Example: * - gpioServo(17, 1000); // Move servo to safe position anti-clockwise. * - gpioServo(23, 1500); // Move servo to centre position. * - gpioServo(25, 2000); // Move servo to safe position clockwise. *

* OTHER UPDATE RATES: * This function updates servos at 50Hz. If you wish to use a different * update frequency you will have to use the PWM functions. *

* PWM Hz 50 100 200 400 500 * 1E6/Hz 20000 10000 5000 2500 2000 *

* Firstly set the desired PWM frequency using gpioSetPWMfrequency. * Then set the PWM range using gpioSetPWMrange to 1E6/frequency. Doing this * allows you to use units of microseconds when setting the servo pulsewidth. *

* E.g. If you want to update a servo connected to GPIO25 at 400Hz* * - gpioSetPWMfrequency(25, 400); * - gpioSetPWMrange(25, 2500); *

* Thereafter use the PWM command to move the servo, e.g. gpioPWM(25, 1500) will set a 1500 us pulse. * @see PIGPIO::gpioServo */ public void gpioServo(int pin, int pulseWidth){ logger.trace("[SERVO::SET] -> PIN: {}; PULSE-WIDTH={};", pin, pulseWidth); validateReady(); validateUserPin(pin); validatePulseWidth(pulseWidth); PiGpioPacket result = sendCommand(SERVO, pin, pulseWidth); logger.trace("[SERVO::SET] <- PIN: {}; PULSE-WIDTH={}; SUCCESS={}", pin, pulseWidth, result.success()); validateResult(result); // Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_BAD_PULSEWIDTH. } /** * {@inheritDoc} * * Returns the servo pulse-width setting for the GPIO. * @see PIGPIO::gpioGetServoPulsewidth */ public int gpioGetServoPulsewidth(int pin){ logger.trace("[SERVO::GET] -> PIN: {}", pin); validateReady(); validateUserPin(pin); PiGpioPacket result = sendCommand(GPW, pin); var pulseWidth = result.result(); logger.trace("[SERVO::GET] <- PIN: {}; PULSE-WIDTH={}; SUCCESS={}", pin, pulseWidth, result.success()); // Returns 0 (off), 500 (most anti-clockwise) to 2500 (most clockwise) // if OK, otherwise PI_BAD_USER_GPIO or PI_NOT_SERVO_GPIO. validateResult(result); return pulseWidth; } // ***************************************************************************************************** // ***************************************************************************************************** // DELAY/SLEEP/TIMER IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * Delays for at least the number of microseconds specified by micros. * (Delays of 100 microseconds or less use busy waits.) * @see PIGPIO::gpioDelay */ @Override public long gpioDelay(long micros) { logger.trace("[DELAY] -> MICROS: {}", micros); validateReady(); validateDelayMicroseconds(micros); PiGpioPacket result = sendCommand(MICS, (int)micros); logger.trace("[DELAY] <- MICROS: {}; SUCCESS={}", micros, result.success()); validateResult(result); // Upon success nothing is returned. On error a negative status code will be returned. return micros; } /** * {@inheritDoc} * * Delays for at least the number of milliseconds specified by micros. (between 1 and 60000 [1 minute]) * @see PIGPIO::MILS */ @Override public int gpioDelayMilliseconds(int millis){ logger.trace("[DELAY] -> MILLIS: {}", millis); validateReady(); validateDelayMilliseconds(millis); PiGpioPacket result = sendCommand(MILS, (int)millis); logger.trace("[DELAY] <- MILLIS: {}; SUCCESS={}", millis, result.success()); validateResult(result); // Upon success nothing is returned. On error a negative status code will be returned. return millis; } /** * {@inheritDoc} * * Returns the current system tick. * Tick is the number of microseconds since system boot. *

* As tick is an unsigned 32 bit quantity it wraps around after 2^32 microseconds, which is * approximately 1 hour 12 minutes. You don't need to worry about the wrap around as long as you * take a tick (uint32_t) from another tick, i.e. the following code will always provide the * correct difference. *

* Example * uint32_t startTick, endTick; * int diffTick; * startTick = gpioTick(); *

* // do some processing * endTick = gpioTick(); * diffTick = endTick - startTick; * printf("some processing took %d microseconds", diffTick); * @see PIGPIO::gpioTick */ @Override public long gpioTick() { logger.trace("[TICK::GET] -> Get current tick"); validateReady(); PiGpioPacket tx = new PiGpioPacket(TICK); PiGpioPacket rx = sendPacket(tx); long tick = Integer.toUnsignedLong(rx.result()); // convert (UInt32) 32-bit unsigned value to long logger.trace("[TICK::GET] <- TICK: {}; SUCCESS={}", tick, rx.success()); return tick; } // ***************************************************************************************************** // ***************************************************************************************************** // I2C IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * Opens a I2C device on a I2C bus for communications. * This returns a handle for the device at the address on the I2C bus. * Physically buses 0 and 1 are available on the Pi. * Higher numbered buses will be available if a kernel supported bus multiplexor is being used. *

* The GPIO used are given in the following table. * SDA SCL * I2C0 0 1 * I2C1 2 3 * @see PIGPIO::i2cOpen */ @Override public int i2cOpen(int bus, int device, int flags) { logger.trace("[I2C::OPEN] -> Open I2C Bus [{}] and Device [{}]; flags={}", bus, device, flags); validateReady(); validateI2cBus(bus); validateI2cDeviceAddress(device); PiGpioPacket tx = new PiGpioPacket(I2CO, bus, device).data(flags); PiGpioPacket rx = sendPacket(tx); int handle = rx.result(); logger.trace("[I2C::OPEN] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); // if the open was successful, then we need to cache the I2C handle if(rx.success()) { i2cHandles.add(handle); } // return handle return handle; } /** * {@inheritDoc} * * This closes the I2C device associated with the handle. * @see PIGPIO::i2cClose */ @Override public int i2cClose(int handle) { logger.trace("[I2C::CLOSE] -> HANDLE={}, Close I2C Bus", handle); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CC, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::CLOSE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); // if the close was successful, then we need to remove the I2C handle from cache if(rx.success()) i2cHandles.remove(handle); // return result return rx.result(); } /** * {@inheritDoc} * * This sends a single bit (in the Rd/Wr bit) to the device associated with handle. * @see PIGPIO::i2cWriteQuick */ @Override public int i2cWriteQuick(int handle, boolean bit) { logger.trace("[I2C::WRITE] -> HANDLE={}; R/W Bit [{}]", handle, bit ? 1 : 0); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWQ, handle, bit ? 1 : 0); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This sends a single byte to the device associated with handle. * @see PIGPIO::i2cWriteByte */ @Override public int i2cWriteByte(int handle, byte value) { logger.trace("[I2C::WRITE] -> HANDLE={}; Byte [{}]", handle, Byte.toUnsignedInt(value)); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWS, handle, Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This reads a single byte from the device associated with handle. * @see PIGPIO::i2cReadByte */ @Override public int i2cReadByte(int handle) { logger.trace("[I2C::READ] -> [{}]; Byte", handle); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CRS, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This writes a single byte to the specified register of the device associated with handle. * @see PIGPIO::i2cWriteByteData */ @Override public int i2cWriteByteData(int handle, int register, byte value) { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Byte [{}]", handle, register, Byte.toUnsignedInt(value)); validateReady(); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CWB, handle, register).data(Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This writes a single 16 bit word to the specified register of the device associated with handle. * @see PIGPIO::i2cWriteWordData */ @Override public int i2cWriteWordData(int handle, int register, int value) { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Word [{}]", handle, register, value); validateReady(); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CWW, handle, register).data(value); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This reads a single byte from the specified register of the device associated with handle. * @see PIGPIO::i2cReadByteData */ @Override public int i2cReadByteData(int handle, int register) { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Byte", handle, register); validateReady(); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRB, handle, register); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This reads a single 16 bit word from the specified register of the device associated with handle. * @see PIGPIO::i2cReadWordData */ @Override public int i2cReadWordData(int handle, int register) { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Word", handle, register); validateReady(); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRW, handle, register); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This writes 16 bits of data to the specified register of the device associated with * handle and reads 16 bits of data in return. (in a single transaction) * @see PIGPIO::i2cProcessCall */ @Override public int i2cProcessCall(int handle, int register, int value) { logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Word [{}]", handle, register, value); validateReady(); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CPC, handle, register).data(value); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::W/R] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This writes up to 32 bytes to the specified register of the device associated with handle. * @see PIGPIO::i2cWriteBlockData */ @Override public int i2cWriteBlockData(int handle, int register, byte[] data, int offset, int length) { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; Block [{} bytes]; offset={}", handle ,register, length, offset); validateReady(); Objects.checkFromIndexSize(offset, length, data.length); validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(length); PiGpioPacket tx = new PiGpioPacket(I2CWK, handle, register).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This reads a block of up to 32 bytes from the specified register of the device associated with handle. * The amount of returned data is set by the device. */ @Override public int i2cReadBlockData(int handle, int register, byte[] buffer, int offset, int length) { logger.trace("[I2C::READ] -> [{}]; Register [{}]; Block [{} bytes]; offset={}", handle ,register, length, offset); validateReady(); Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRK, handle, register); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); if(rx.success()) { int actual = rx.result(); if(rx.dataLength() < actual) actual = rx.dataLength(); System.arraycopy(rx.data(), 0, buffer, offset, actual); } return rx.result(); } /** * {@inheritDoc} * * This writes data bytes to the specified register of the device associated with handle and reads a * device specified number of bytes of data in return. *

* The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. * The total number of bytes sent/received must be 32 or less. * @see PIGPIO::i2cBlockProcessCall */ @Override public int i2cBlockProcessCall(int handle, int register, byte[] write, int writeOffset, int writeLength, byte[] read, int readOffset) { logger.trace("[I2C::W/R] -> [{}]; Register [{}]; Block [{} bytes]; woff={}; roff={}", handle, register, writeLength, writeOffset, readOffset); validateReady(); Objects.checkFromIndexSize(writeOffset, writeLength, write.length); validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(writeLength); // write/read from I2C device PiGpioPacket tx = new PiGpioPacket(I2CPK, handle, register).data(write, writeOffset, writeLength); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::W/R] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); // copy data bytes to provided "read" array/buffer if(rx.success()) { int readLength = rx.result(); if(rx.dataLength() < readLength) readLength = rx.dataLength(); // make sure the read array has sufficient space to store the bytes returned Objects.checkFromIndexSize(readOffset, readLength, read.length); System.arraycopy(rx.data(), 0, read, readOffset, readLength); } return rx.result(); } /** * {@inheritDoc} * * This writes data bytes to the specified register of the device associated with the handle and reads a * device specified number of bytes of data in return. *

* The SMBus 2.0 documentation states that a minimum of 1 byte may be sent and a minimum of 1 byte may be received. * The total number of bytes sent/received must be 32 or less. */ @Override public int i2cBlockProcessCall(int handle, int register, byte[] data, int offset, int length){ return i2cBlockProcessCall(handle, register, data, offset, length, data, offset); } /** * {@inheritDoc} * * This reads count bytes from the specified register of the device associated with handle . * The maximum length of data that can be read is 32 bytes. * The minimum length of data that can be read is 1 byte. * @see PIGPIO::i2cReadI2CBlockData */ @Override public int i2cReadI2CBlockData(int handle, int register, byte[] buffer, int offset, int length){ logger.trace("[I2C::READ] -> [{}]; Register [{}]; I2C Block [{} bytes]; offset={}", handle, register, length, offset); validateReady(); Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); validateI2cRegister(register); PiGpioPacket tx = new PiGpioPacket(I2CRI, handle, register).data(length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); // logger.trace("[I2C::READ] <- DATA SIZE={}", rx.result()); // logger.trace("[I2C::READ] <- DATA LENGTH={}", rx.dataLength()); // logger.trace("[I2C::READ] <- BUFFER SIZE={}", rx.data()); // logger.trace("[I2C::READ] <- OFFSET={}", offset); if(rx.success()) { try { int actual = rx.result(); if(rx.dataLength() < actual) actual = rx.dataLength(); System.arraycopy(rx.data(), 0, buffer, offset, actual); } catch (ArrayIndexOutOfBoundsException a){ logger.error(a.getMessage(), a); } } return rx.result(); } /** * {@inheritDoc} * * This writes 1 to 32 bytes to the specified register of the device associated with handle. * @see PIGPIO::i2cWriteI2CBlockData */ @Override public int i2cWriteI2CBlockData(int handle, int register, byte[] data, int offset, int length) { logger.trace("[I2C::WRITE] -> [{}]; Register [{}]; I2C Block [{} bytes]; offset={}", handle ,register, length, offset); validateReady(); validateHandle(handle); validateI2cRegister(register); validateI2cBlockLength(length); PiGpioPacket tx = new PiGpioPacket(I2CWI, handle, register).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This reads count bytes from the raw device into byte buffer array. * @see PIGPIO::i2cReadDevice */ @Override public int i2cReadDevice(int handle, byte[] buffer, int offset, int length) { logger.trace("[I2C::READ] -> [{}]; I2C Raw Read [{} bytes]; offset={}", handle, length, offset); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CRD, handle, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::READ] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); if(rx.success()) { int actual = rx.result(); if(rx.dataLength() < actual) actual = rx.dataLength(); System.arraycopy(rx.data(), 0, buffer, offset, actual); } return rx.result(); } /** * {@inheritDoc} * * This writes the length of bytes from the provided data array to the raw I2C device. * @see PIGPIO::i2cWriteDevice */ @Override public int i2cWriteDevice(int handle, byte[] data, int offset, int length) { logger.trace("[I2C::WRITE] -> [{}]; I2C Raw Write [{} bytes]; offset={}", handle, length, offset); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(I2CWD, handle).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[I2C::WRITE] <- HANDLE={}; SUCCESS={}; RESULT={}", handle, rx.success(), rx.result()); validateResult(rx, false); return rx.result(); } // ***************************************************************************************************** // ***************************************************************************************************** // SERIAL IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * This function opens a serial device at a specified baud rate and with specified flags. * The device name must start with "/dev/tty" or "/dev/serial". * @see PIGPIO::serOpen */ @Override public int serOpen(CharSequence device, int baud, int flags) { logger.trace("[SERIAL::OPEN] -> Open Serial Port [{}] at Baud Rate [{}]", device, baud); validateReady(); PiGpioPacket tx = new PiGpioPacket(SERO, baud, flags).data(device); PiGpioPacket rx = sendPacket(tx); int handle = rx.result(); logger.trace("[SERIAL::OPEN] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); // if the open was successful, then we need to add the SERIAL handle to cache if(rx.success()) serialHandles.add(handle); // return the handle return handle; } /** * {@inheritDoc} * * This function closes the serial device associated with handle. * @see PIGPIO::serClose */ @Override public int serClose(int handle) { logger.trace("[SERIAL::CLOSE] -> HANDLE={}, Close Serial Port", handle); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERC, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[SERIAL::CLOSE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); // if the close was successful, then we need to remove the SERIAL handle from cache if(rx.success()) serialHandles.remove(handle); // return result return rx.result(); } /** * {@inheritDoc} * * This function writes a single byte "value" to the serial port associated with handle. * @see PIGPIO::serWriteByte */ @Override public int serWriteByte(int handle, byte value) { logger.trace("[SERIAL::WRITE] -> HANDLE={}; Byte [{}]", handle, Byte.toUnsignedInt(value)); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERWB, handle, Byte.toUnsignedInt(value)); PiGpioPacket rx = sendPacket(tx); logger.trace("[SERIAL::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); return 0; } /** * {@inheritDoc} * * This function reads a byte from the serial port associated with handle. * If no data is ready PI_SER_READ_NO_DATA is returned. * @see PIGPIO::serReadByte */ @Override public int serReadByte(int handle) { logger.trace("[SERIAL::READ] -> [{}]; Byte", handle); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERRB, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[SERIAL::READ] <- HANDLE={}; SUCCESS={}", handle, rx.p3()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This function writes multiple bytes from the buffer array ('data') to the serial * port associated with handle. * @see PIGPIO::serWrite */ @Override public int serWrite(int handle, byte[] data, int offset, int length) { logger.trace("[SERIAL::WRITE] -> [{}]; Serial Write [{} bytes]", handle, data.length); validateReady(); Objects.checkFromIndexSize(offset, length, data.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERW, handle).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[SERIAL::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This function reads up count bytes from the serial port associated with handle and * writes them to the buffer parameter. If no data is ready, zero is returned. * @see PIGPIO::serRead */ @Override public int serRead(int handle, byte[] buffer, int offset, int length) { logger.trace("[SERIAL::READ] -> [{}]; Serial Read [{} bytes]", handle, length); validateReady(); Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SERR, handle, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[SERIAL::READ] <- HANDLE={}; SUCCESS={}; BYTES-READ={}", handle, rx.success(), rx.dataLength()); validateResult(rx, false); if(rx.success()) { int actual = rx.result(); if(rx.dataLength() < actual) actual = rx.dataLength(); System.arraycopy(rx.data(), 0, buffer, offset, actual); } return rx.result(); } /** * {@inheritDoc} * * This function returns the number of bytes available to be read from the device associated with handle. * @see PIGPIO::serDataAvailable */ @Override public int serDataAvailable(int handle) { logger.trace("[SERIAL::AVAIL] -> Get number of bytes available to read"); validateReady(); PiGpioPacket tx = new PiGpioPacket(SERDA, handle); PiGpioPacket rx = sendPacket(tx); int available = rx.result(); logger.trace("[SERIAL::AVAIL] <- HANDLE={}; SUCCESS={}; AVAILABLE={}", handle, rx.success(), available); validateResult(rx, false); return available; } /** * {@inheritDoc} * * This function will drain the current serial receive buffer of any lingering bytes. */ @Override public int serDrain(int handle){ logger.trace("[SERIAL::DRAIN] -> Drain any remaining bytes in serial RX buffer"); validateReady(); // get number of bytes available PiGpioPacket tx = new PiGpioPacket(SERDA, handle); PiGpioPacket rx = sendPacket(tx); validateResult(rx, false); int available = rx.result(); // if any bytes are available, then drain them now if(available > 0){ tx = new PiGpioPacket(SERR, handle, available); rx = sendPacket(tx); validateResult(rx, false); } logger.trace("[SERIAL::DRAIN] <- HANDLE={}; SUCCESS={}; DRAINED={}", handle, rx.success(), rx.result()); return available; } // ***************************************************************************************************** // ***************************************************************************************************** // SPI IMPLEMENTATION // ***************************************************************************************************** // ***************************************************************************************************** /** * {@inheritDoc} * * This function opens a SPI device channel at a specified baud rate and with specified flags. * Data will be transferred at baud bits per second. * The flags may be used to modify the default behaviour of 4-wire operation, mode 0, active low chip select. *

* The Pi has two SPI peripherals: main and auxiliary. * The main SPI has two chip selects (channels), the auxiliary has three. * The auxiliary SPI is available on all models but the A and B. *

* The GPIO pins used are given in the following table. *

* MISO MOSI SCLK CE0 CE1 CE2 * ------------------------------------- * Main SPI 9 10 11 8 7 - * Aux SPI 19 20 21 18 17 16 *

* * spiChan : 0-1 (0-2 for the auxiliary SPI) * baud : 32K-125M (values above 30M are unlikely to work) * spiFlags : see below *

* spiFlags consists of the least significant 22 bits. * ----------------------------------------------------------------- * 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 * b b b b b b R T n n n n W A u2 u1 u0 p2 p1 p0 m m * ----------------------------------------------------------------- *

* [mm] defines the SPI mode. * (Warning: modes 1 and 3 do not appear to work on the auxiliary SPI.) *

* Mode POL PHA * ------------- * 0 0 0 * 1 0 1 * 2 1 0 * 3 1 1 *

* [px] is 0 if CEx is active low (default) and 1 for active high. * [ux] is 0 if the CEx GPIO is reserved for SPI (default) and 1 otherwise. * [A] is 0 for the main SPI, 1 for the auxiliary SPI. * [W] is 0 if the device is not 3-wire, 1 if the device is 3-wire. Main SPI only. * [nnnn] defines the number of bytes (0-15) to write before switching the MOSI line to MISO to read data. This field is ignored if W is not set. Main SPI only. * [T] is 1 if the least significant bit is transmitted on MOSI first, the default (0) shifts the most significant bit out first. Auxiliary SPI only. * [R] is 1 if the least significant bit is received on MISO first, the default (0) receives the most significant bit first. Auxiliary SPI only. * [bbbbbb] defines the word size in bits (0-32). The default (0) sets 8 bits per word. Auxiliary SPI only. *

* The spiRead, spiWrite, and spiXfer functions transfer data packed into 1, 2, or 4 bytes according to the word size in bits. * - For bits 1-8 there will be one byte per word. * - For bits 9-16 there will be two bytes per word. * - For bits 17-32 there will be four bytes per word. *

* Multi-byte transfers are made in least significant byte first order. * E.g. to transfer 32 11-bit words buf should contain 64 bytes and count should be 64. * E.g. to transfer the 14 bit value 0x1ABC send the bytes 0xBC followed by 0x1A. * The other bits in flags should be set to zero. * @see PIGPIO::spiOpen */ @Override public int spiOpen(int channel, int baud, int flags) { logger.trace("[SPI::OPEN] -> Open SPI Channel [{}] at Baud Rate [{}]; Flags=[{}]", channel, baud, flags); validateReady(); PiGpioPacket tx = new PiGpioPacket(SPIO, channel, baud).data(flags); PiGpioPacket rx = sendPacket(tx); int handle = rx.result(); logger.trace("[SPI::OPEN] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); // if the open was successful, then we need to add the SPI handle to cache if(rx.success()) spiHandles.add(handle); // return handle return handle; } /** * {@inheritDoc} * * This functions closes the SPI device identified by the handle. * @see PIGPIO::spiClose */ @Override public int spiClose(int handle) { logger.trace("[SPI::CLOSE] -> HANDLE={}, Close Serial Port", handle); validateReady(); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SPIC, handle); PiGpioPacket rx = sendPacket(tx); logger.trace("[SPI::CLOSE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); // if the close was successful, then we need to remove the SPI handle from cache if(rx.success()) spiHandles.remove(handle); // return result return rx.result(); } /** * {@inheritDoc} * * This function writes multiple bytes from the byte array ('data') to the SPI * device associated with the handle from the given offset index to the specified length. * @see PIGPIO::spiWrite */ @Override public int spiWrite(int handle, byte[] data, int offset, int length) { logger.trace("[SPI::WRITE] -> [{}]; Serial Write [{} bytes]", handle, data.length); validateReady(); Objects.checkFromIndexSize(offset, length, data.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SPIW, handle).data(data, offset, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[SPI::WRITE] <- HANDLE={}; SUCCESS={}", handle, rx.success()); validateResult(rx, false); return rx.result(); } /** * {@inheritDoc} * * This function reads a number of bytes specified by the 'length' parameter from the * SPI device associated with the handle and copies them to the 'buffer' byte array parameter. * The 'offset' parameter determines where to start copying/inserting read data in the byte array. * If no data is ready, zero is returned; otherwise, the number of bytes read is returned. * @see PIGPIO::spiRead */ @Override public int spiRead(int handle, byte[] buffer, int offset, int length) { logger.trace("[SPI::READ] -> [{}]; Serial Read [{} bytes]", handle, length); validateReady(); Objects.checkFromIndexSize(offset, length, buffer.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SPIR, handle, length); PiGpioPacket rx = sendPacket(tx); logger.trace("[SPI::READ] <- HANDLE={}; SUCCESS={}; BYTES-READ={}", handle, rx.success(), rx.dataLength()); validateResult(rx, false); if(rx.success()) { int actual = rx.result(); if(rx.dataLength() < actual) actual = rx.dataLength(); System.arraycopy(rx.data(), 0, buffer, offset, actual); } return rx.result(); } /** * {@inheritDoc} * * This function transfers (writes/reads simultaneously) multiple bytes with the SPI * device associated with the handle. Write data is taken from the 'write' byte array * from the given 'writeOffset' index to the specified length ('numberOfBytes'). Data * read from the SPI device is then copied to the 'read' byte array at the given 'readOffset' * using the same length. Both the 'write' and 'read' byte arrays must be at least the size * of the defined 'numberOfBytes' + their corresponding offsets. * @see PIGPIO::spiWrite */ @Override public int spiXfer(int handle, byte[] write, int writeOffset, byte[] read, int readOffset, int numberOfBytes) { logger.trace("[SPI::XFER] -> [{}]; Serial Transfer [{} bytes]", handle, numberOfBytes); validateReady(); Objects.checkFromIndexSize(writeOffset, numberOfBytes, write.length); Objects.checkFromIndexSize(readOffset, numberOfBytes, read.length); validateHandle(handle); PiGpioPacket tx = new PiGpioPacket(SPIX, handle).data(write, writeOffset, numberOfBytes); PiGpioPacket rx = sendPacket(tx); logger.trace("[SPI::XFER] <- HANDLE={}; SUCCESS={}; BYTES-READ={}", handle, rx.success(), rx.dataLength()); validateResult(rx, false); if(rx.success()) { int actual = rx.result(); if(rx.dataLength() < actual) actual = rx.dataLength(); System.arraycopy(rx.data(), 0, read, readOffset, actual); } return rx.result(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy