jdk.dio.pwm.PWMChannel Maven / Gradle / Ivy
Show all versions of org.openjdk.dio Show documentation
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.dio.pwm;
import java.io.IOException;
import java.nio.IntBuffer;
import jdk.dio.BufferAccess;
import jdk.dio.ClosedDeviceException;
import jdk.dio.Device;
import jdk.dio.DeviceManager;
import jdk.dio.UnavailableDeviceException;
import jdk.dio.UnsupportedByteOrderException;
import jdk.dio.gpio.GPIOPin;
import romizer.WeakDontRenameClass;
/**
* The {@code PWMChannel} interface provides methods for controlling a PWM (Pulse Width Modulation) signal generator
* channel.
*
* One PWM generator/controller can have several channels. A PWM channel can generate pulses on a digital output line
* (possibly a GPIO pin).
*
* A PWM channel may be identified by the numeric ID and by the name (if any defined) that correspond to its
* registered configuration. A {@code PWMChannel} instance can be opened by a call to one of the
* {@link DeviceManager#open(int) DeviceManager.open(id,...)} methods using its ID or by a call to one of the
* {@link DeviceManager#open(java.lang.String, java.lang.Class, java.lang.String[])
* DeviceManager.open(name,...)} methods using its name. When a {@code PWMChannel} instance is opened with an ad-hoc
* {@link PWMChannelConfig} configuration (which includes its hardware addressing information) using one of the
* {@link DeviceManager#open(jdk.dio.DeviceConfig) DeviceManager.open(config,...)} methods it is not
* assigned any ID nor name.
*
* Once opened, an application can set the pulse period using the {@link #setPulsePeriod setPulsePeriod} and then generate a certain
* number of pulses of a specified width by calling one of the {@link #generate generate} methods.
*
* An application can also asynchronously generate a train of pulses either of a specified width up to a specified
* maximum count or from widths specified in a buffer by calling one of the
* {@link #startGeneration(int, int, jdk.dio.pwm.GenerationListener) startGeneration} methods with a
* {@link GenerationListener} instance which will get notified upon completion. Such an asynchronous pulse generation
* can be stopped or canceled by calling the {@link #stopGeneration stopGeneration} method.
*
* Only one output/generation operation (synchronous or asynchronous) can be going on at any time.
*
* When an application is no longer using a PWM channel it should call the {@link #close PWMChannel.close} method to
* close the PWM channel. Any further attempt to use a PWM channel which has been closed will result in a
* {@link ClosedDeviceException} been thrown.
*
* Upon opening a PWM channel the default pulse width and duty cycle are always {@code 0}; the idle
* state is platform or configuration-specific.
*
Buffered I/O and Direct I/O Transfers
* A PWM channel may support buffered I/O or direct I/O operations depending on
* the capabilities of the underlying device hardware and driver.
* Buffered output - output in buffering mode - may be requested by setting the
* output buffer size parameter of the {@link PWMChannelConfig} configuration to
* a value greater than {@code 0} ; whether or not the channel will indeed work
* in buffering mode and will use an internal output buffer of the size requested
* is up to the device driver. An application may check whether a channel is
* working in buffering mode by calling the
* {@link PWMChannelConfig#getOutputBufferSize PWMChannelConfig.getOutputBufferSize} method.
* When a PWM channel is not working in buffering mode, direct I/O may be
* enabled by providing direct {@code Buffer}s to the output methods; whether
* efficient direct output transfers will be used depends on the underlying
* hardware and driver capabilities and on whether the provided buffers are
* suitable for such operations (see
* {@link BufferAccess#prepareBuffer BufferAccess.prepareBuffer}). Output methods
* using double buffering may only support efficient direct operations if both
* buffers are suitable for such operations.
* Permission Requirement For PWM Channels Configured with an Explicit GPIO Output Pin
* Opening a {@code PWMChannel} instance with an ad-hoc configuration requires
* the {@link jdk.dio.pwm.PWMPermission PWMPermission.OPEN} to be granted;
* opening an instance of a {@code PWMChannel} configured with an explicit {@code GPIOPin} output
* on which the pulses are to be generated requires, in addition, the
* {@link jdk.dio.gpio.GPIOPinPermission GPIOPinPermission.OPEN} permission to be granted
* on the designated GPIO pin.
*
* Opening a {@code PWMChannel} with the following ad hoc sample configuration:
*
*
* PWMChannelConfig config = new PWMChannelConfig.Builder()
* .setControllerNumber(1)
* .setChannelNumber(1)
* .setOutputConfig(new GPIOPinConfig.Builder()
* .setControllerNumber(3)
* .setPinNumber(1)
* .setDirection(GPIOPinConfig.DIR_OUTPUT_ONLY)
* .setDriveMode(GPIOPinConfig.MODE_OUTPUT_PUSH_PULL)
* .build())
* .setScaleFactor(1.0)
* .setPulsePeriod(10)
* .setIdleState(IDLE_STATE_HIGH)
* .setPulseAlignment(ALIGN_CENTER)
* .setOutputBufferSize(0)
* .build();
*
*
*
* requires the following permissions to be granted:
*
*
* PWMChannelPermission("1:1", "open")
* GPIOPinPermission("3:1", "open")
*
*
*
* @see GenerationListener
* @see PWMPermission
* @see jdk.dio.gpio.GPIOPinPermission
* @since 1.0
*/
@apimarker.API("device-io_1.1_pwm")
@WeakDontRenameClass
public interface PWMChannel extends Device, BufferAccess {
/**
* Sets the scaled pulse period of this PWM channel. The
* effective pulse period is calculated from the
* currently set scale factor as can be retrieved using {@link #getScaleFactor getScaleFactor}.
* Whether changing the pulse period
* has an immediate effect or not on an active (synchronous or asynchronous) generation is
* device- as well as platform-dependent.
*
* If the underlying platform or driver
* does not support the requested pulse period value
* then {@code period} will be aligned to the closest lower supported discrete period value. The resulting, actual
* pulse period can be retrieved by a call to {@link #getPulsePeriod() getPulsePeriod}.
* If the current scale factor as returned by
* {@link #getScaleFactor getScaleFactor} is {@code scale} and the current scaled
* pulse period value - after alignment - is {@code sPeriod}
* then the effective pulse period is calculated as follows:
*
*
* {@code ePeriod = (sPeriod / scale)}
*
*
*
* @param period
* the scaled pulse period as a period in microseconds.
* @throws IOException
* if some other I/O error occurs.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
* @throws InvalidPulseRateException
* if {@code period} is greater than the maximum pulse period (see {@link #getMaxPulsePeriod getMaxPulsePeriod})
* or lower than the minimum pulse period (see {@link #getMinPulsePeriod getMinPulsePeriod}).
* @throws IllegalArgumentException
* if {@code period} is negative or zero.
*/
void setPulsePeriod(int period) throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Gets the scaled pulse period of this PWM channel (in microseconds). The
* effective pulse period can then be calculated from the
* currently set scale factor as can be retrieved using {@link #getScaleFactor getScaleFactor}.
* If the pulse period was not set previously using
* {@link #setPulsePeriod setPulsePeriod} the device configuration-specific default value is returned.
* Additionally, the value returned may differ from the previously set or configured value as it may have
* been adjusted to account for the timer resolution or discrete pulse period values supported by the underlying platform or driver.
*
* @return the scaled pulse period (in microseconds).
* @throws IOException
* if some other I/O error occurs.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
*/
int getPulsePeriod() throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Sets the pulse period scale factor of this PWM channel.
* The current
* scaled pulse period value is reset to the new resulting minimum scaled pulse period
* value. A call to this method should be immediately followed by a call to
* the {@link #setPulsePeriod setPulsePeriod} method in order to set
* an appropriate scaled pulse period.
*
* @param factor the scale factor (a number greater or equal to {@code 1.0}).
* @throws IllegalArgumentException if {@code factor} is {@link Double#NaN NaN}, is less than {@code 1.0} or,
* if the setting of the scale factor would result
* in the scaled pulse period range to be outside the range {@code [1 - }{@link Integer#MAX_VALUE}{@code ]}.
* @throws IOException if some other I/O error occurs.
* @throws UnavailableDeviceException if this device is not currently
* available - such as it is locked by another application.
* @throws ClosedDeviceException if the device has been closed.
*
* @see #getScaleFactor
* @see #setPulsePeriod
*/
void setScaleFactor(double factor) throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Gets the pulse period scale factor of this PWM channel. If the scale
* factor is {@code scale} and the scaled pulse period value as
* returned by {@link #getPulsePeriod getPulsePeriod} is {@code sPeriod} then the
* effective pulse period is calculated as follows:
*
* {@code ePeriod = (sPeriod / scale)}
*
*
* Conversely, the scaled pulse period value to set using
* {@link #setPulsePeriod} to obtain the effective pulse
* period {@code ePeriod} is calculated as follows:
*
* {@code sPeriod = (ePeriod * scale)}
*
*
* The scale factor also applies to the minimum and maximum scaled pulse periods
* as respectively returned by {@link #getMinPulsePeriod getMinPulsePeriod}
* and {@link #getMaxPulsePeriod getMaxPulsePeriod}.
*
* If the pulse period scale factor was not set previously using
* {@link #setScaleFactor setScaleFactor}, the device configuration-specific
* default value is returned.
*
*
* @return the scale factor.
* @throws IOException
* if some other I/O error occurs.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another
* application.
* @throws ClosedDeviceException
* if the device has been closed.
*/
double getScaleFactor() throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Gets the scaled maximum pulse period of this PWM channel (in microseconds) that can bet set by a call to
* {@link #setPulsePeriod setPulsePeriod}. The maximum effective pulse period
* can be calculated from the currently set scale factor as can be retrieved using
* {@link #getScaleFactor getScaleFactor}.
*
* @return the maximum scaled pulse period (in microseconds).
* @throws IOException
* if some other I/O error occurs.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
*/
int getMaxPulsePeriod() throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Gets the minimum scaled pulse period of this PWM channel (in microseconds) that can bet set by a call to
* {@link #setPulsePeriod setPulsePeriod}. The minimum effective pulse period
* can be calculated from the currently set scale factor as can be retrieved using
* {@link #getScaleFactor getScaleFactor}.
*
* @return the minimum scaled pulse period (in microseconds).
* @throws IOException
* if some other I/O error occurs.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
*/
int getMinPulsePeriod() throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Generates a pulse train containing the specified count of pulses of the specified width.
* The pulse width value is scaled; the effective pulse width can be calculated
* from the currently set scale factor as can be retrieved using {@link #getScaleFactor getScaleFactor}.
*
* To generate pulses of a specific duty cycle {@code dutyCycle}, this method may be called as follows:
*
*
* float dutyCycle = 0.5f;
* pwmChannel.generate((pwmChannel.getPulsePeriod() * dutyCycle), count);
*
*
*
* If the underlying platform or driver
* does not support the requested width value
* then {@code width} will be aligned to the closest lower supported discrete width value.
*
* The operation will return only after generating all of the {@code count} requested pulses.
*
* The pulses will be generated according to the current effective pulse period
* as determined by the current scaled pulse period (see {@link #getPulsePeriod getPulsePeriod})
* and the current scale factor {@link #getScaleFactor getScaleFactor}.
*
* This method may be invoked at any time. If another thread has already initiated a synchronous output operation
* upon this channel then an invocation of this method will block until the first operation is complete.
*
* Only one output operation (synchronous or asynchronous) can be going on at any time.
*
*
* @param width
* the scaled pulse width (in microseconds).
* @param count
* the maximum number of pulses to generate.
*
* @throws IOException
* if some other I/O error occurs.
* @throws IllegalArgumentException
* if {@code width} or {@code count} is equal to or less than {@code 0} or if {@code width} is greater
* than the currently set period.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
* @throws IllegalStateException
* if an asynchronous pulse generation session is already active.
*/
void generate(int width, int count) throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Generates a pulse train from the specified sequence of pulse widths. The provided buffer contains the
* scaled widths of the pulses to generate; the effective pulse widths can be calculated
* from the currently set scale factor as can be retrieved using {@link #getScaleFactor getScaleFactor}.
*
* r pulses will be generated by this channel, where r is the number of integers (pulse widths)
* remaining in the buffer, that is, {@code src.remaining()}, at the moment this method is invoked.
*
* Suppose that a pulse width integer value sequence of length n is provided, where {@code 0 <= n <= r}
* . The sequence starts at index p, where p is the buffer's position at the moment this method is
* invoked; the index of the last pulse width integer value written will be {@code p + n - 1}. Upon return
* the buffer's position will be equal to {@code p + n}; its limit will not have changed.
*
* The operation will block until all of the r pulse width values
* remaining in the provided {@code src} buffer have been written or otherwise
* transferred to the driver/hardware. If this channel uses an internal output buffer and
* is therefore working in buffering mode this method will block until all the
* r pulse width values have been copied to the internal output buffer.
*
* The pulses will be generated according to the current effective pulse period
* as determined by the current scaled pulse period (see {@link #getPulsePeriod getPulsePeriod})
* and the current scale factor {@link #getScaleFactor getScaleFactor}.
*
* This method may be invoked at any time. If another thread has already initiated a synchronous pulse generation
* upon this channel, however, then an invocation of this method will block until the first operation is complete.
*
* Only one pulse generation (synchronous or asynchronous) can be going on at any time.
*
* This method does not throw an {@link IllegalArgumentException} if any of the designated pulse width values
* is greater than the currently set period. If a pulse width value is not within range
* the actual width of the pulse generated by the PWM device is hardware- or driver-specific: the pulse width
* may for example be equal to the set period, corresponding to a 100% duty cycle.
*
* If the underlying platform or driver
* does not support the requested width value
* then the actual width of the pulse generated by the PWM device is hardware- or driver-specific: the pulse width
* may, for example, be aligned to the closest lower supported discrete width value.
*
*
* @param src
* the buffer from which the scaled pulse width integer values can be retrieved.
* @throws NullPointerException
* If {@code src} is {@code null}.
* @throws IllegalStateException
* if an asynchronous pulse generation is already active.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws UnsupportedByteOrderException
* if the byte ordering of the provided buffer is not supported (see Device Byte Order).
* @throws ClosedDeviceException
* if the device has been closed.
* @throws IOException
* if some other I/O error occurs.
*/
void generate(IntBuffer src) throws IOException, UnavailableDeviceException, UnsupportedByteOrderException, ClosedDeviceException;
/**
* Starts an asynchronous pulse train generation session - continuously generating pulses of the specified width
* until explicitly stopped.
* The pulse width value is scaled; the effective pulse width can be calculated
* from the currently set scale factor as can be retrieved using {@link #getScaleFactor getScaleFactor}.
*
* The pulses will be generated according to the current effective pulse period
* as determined by the current scaled pulse period (see {@link #getPulsePeriod getPulsePeriod})
* and the current scale factor {@link #getScaleFactor getScaleFactor}.
*
* If the underlying platform or driver does not support the requested width value
* then {@code width} will be aligned to the closest lower supported discrete width value.
*
* Pulse generation will immediately start and proceed asynchronously. It may be stopped prior to completion by a
* call to {@link #stopGeneration stopGeneration}.
*
* Only one pulse generation session can be going on at any time.
*
*
* @param width
* the scaled pulse width (in microseconds).
*
* @throws IOException
* if some other I/O error occurs.
* @throws IllegalArgumentException
* if {@code width} is equal to or less than
* {@code 0} or if {@code width} is greater than the currently set period.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
* @throws IllegalStateException
* if another synchronous or asynchronous generation is already active.
*/
void startGeneration(int width) throws IOException,
UnavailableDeviceException, ClosedDeviceException;
/**
* Starts an asynchronous pulse train generation session - generating pulses of the specified width up to the
* specified count. The provided {@link GenerationListener} instance will be invoked upon completion, that is when
* the count of generated pulses reaches the specified count value.
* The pulse width value is scaled; the effective pulse width can be calculated
* from the currently set scale factor as can be retrieved using {@link #getScaleFactor getScaleFactor}.
*
* The pulses will be generated according to the current effective pulse period
* as determined by the current scaled pulse period (see {@link #getPulsePeriod getPulsePeriod})
* and the current scale factor {@link #getScaleFactor getScaleFactor}.
*
* If the underlying platform or driver does not support the requested width value
* then {@code width} will be aligned to the closest lower supported discrete width value.
*
* Pulse generation will immediately start and proceed asynchronously. It may be stopped prior to completion by a
* call to {@link #stopGeneration stopGeneration}.
*
* Only one pulse generation session can be going on at any time.
*
*
* @param width
* the scaled pulse width (in microseconds).
* @param count
* the maximum number of pulses to generate.
* @param listener
* the {@link GenerationListener} instance to be notified when the count of generated pulses reaches the
* specified count value.
*
* @throws IOException
* if some other I/O error occurs.
* @throws IllegalArgumentException
* if {@code count} is equal to or less than {@code 0} or if {@code width} is equal to or less than
* {@code 0} or if {@code width} is greater than the currently set period.
* @throws NullPointerException
* if {@code listener} is {@code null}.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
* @throws IllegalStateException
* if another synchronous or asynchronous generation is already active.
*/
void startGeneration(int width, int count, GenerationListener listener) throws IOException,
UnavailableDeviceException, ClosedDeviceException;
/**
* Starts asynchronous pulse train generation in successive rounds - initially generating pulses of the specified
* widths up to the specified initial count - as indicated by the number of remaining elements in the provided
* buffer. The provided buffer contains the scaled widths of the pulses to generate; the effective
* pulse widths can be calculated from the currently set scale factor as can be retrieved using
* {@link #getScaleFactor getScaleFactor}.
* Additional rounds are asynchronously fetched by notifying the provided {@link GenerationRoundListener}
* instance once the initial count of pulses have been generated. The widths of the initial pulses to be generated
* are read from the provided buffer; the widths of the pulses to generate during the subsequent rounds are read
* from that very same buffer upon invocation of the provided {@link GenerationRoundListener} instance.
*
* Pulse generation can be stopped by a call to {@link #stopGeneration stopGeneration}.
*
* r integers will be written to this channel, where r is the number of integers remaining in the
* buffer (possibly {@code 0}), that is, {@code src.remaining()}, at the moment this method is initially invoked and then subsequently when the listener is returning.
*
* Suppose that an integer sequence of length n is written, where {@code 0 <= n <= r}. This integer
* sequence will be transferred from the buffer starting at index p, where p is the buffer's position
* at the moment this method is invoked and then subsequently when the listener is returning; the index of the last integer written will be {@code p + n - 1}.
* Upon invocation of the listener to fetch the widths of more pulses to generate the buffer's position will be equal to {@code p + n}; its limit will not have changed.
*
* If this channel
* uses an internal output buffer and is therefore working in buffering mode the listener will only be
* invoked after all the r pulse width values have been copied to the
* internal output buffer; otherwise the listener will only be invoked after all the
* r pulse width values have been transferred to the driver/hardware.
* The buffer's position upon stopping this asynchronous operation by a call to {@link #stopGeneration stopGeneration}
* is not predictable unless called from within the listener.
*
* The pulses will be generated according to the current effective pulse period
* as determined by the current scaled pulse period (see {@link #getPulsePeriod getPulsePeriod})
* and the current scale factor {@link #getScaleFactor getScaleFactor}. The
* pulse period can be changed by the provided {@link GenerationRoundListener} instance upon notification of each
* pulse train subsequence.
*
* Upon notification of the provided {@code GenerationRoundListener}
* the reference to the provided {@code src} buffer can be retrieved from the
* {@code RoundCompletionEvent} using the {@link jdk.dio.RoundCompletionEvent#getBuffer() getBuffer} method.
*
* A buffer with {@code 0} integers remaining to be written (that is a buffer already empty) at the moment this method is initially
* invoked or then subsequently when the listener is returning will not stop the asynchronous operation; the listener is
* guaranteed to be called back again at the latest as soon as all other events pending at the time of notification have been dispatched.
* The underrun condition resulting from the listener notification
* returning with an empty buffer will be reported on the subsequent notifications through
* the {@link jdk.dio.RoundCompletionEvent#isOnError() RoundCompletionEvent.isOnError} method.
*
* Only one pulse generation (synchronous or asynchronous) can be going on at any time.
*
* Buffers are not safe for use by multiple concurrent threads so care should
* be taken to not access the provided buffer until the operation (or a round thereof) has completed.
* Interfering with the asynchronous operation by accessing and modifying the provided buffer concurrently
* may yield unpredictable results.
*
* This method does not throw an {@link IllegalArgumentException} if any of the designated pulse width values
* is greater than the currently set period. If a pulse width value is not within range
* the actual width of the pulse generated by the PWM device is hardware- or driver-specific: the pulse width
* may for example be equal to the set period, corresponding to a 100% duty cycle.
*
* If the underlying platform or driver does not support a requested width value
* then the actual width of the pulse generated by the PWM device is hardware- or driver-specific: the pulse width
* may, for example, be aligned to the closest lower supported discrete width value.
*
*
* @param src
* the buffer from which the scaled pulse width integer values can be retrieved.
* @param listener
* the {@link GenerationRoundListener} instance to be notified when pulses have been generated for all
* the width values remaining in the buffer.
* @throws NullPointerException
* If {@code src} or {@code listener} is {@code null}.
* @throws IllegalArgumentException
* if the provided buffer {@code src} has a zero-capacity.
* @throws IllegalStateException
* if another synchronous or asynchronous output generation is already active.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws UnsupportedByteOrderException
* if the byte ordering of the provided buffers is not supported.
* @throws ClosedDeviceException
* if the device has been closed.
* @throws IOException
* if some other I/O error occurs.
*/
void startGeneration(IntBuffer src, GenerationRoundListener listener) throws IOException,
UnavailableDeviceException, UnsupportedByteOrderException, ClosedDeviceException;
/**
* Starts asynchronous pulse train generation in successive rounds.
*
* This method behaves identically to {@link #startGeneration(IntBuffer, GenerationRoundListener)} excepts that it
* uses double-buffering - the provided buffers must not have a zero-capacity and must not overlap
* - that is the backing array sections or memory regions they refer to must not overlap.
* Notification will happen when pulses have been generated for all the width values
* remaining in the current working buffer (initially {@code src1}) and generation will proceed with the alternate buffer (which will become the
* current working buffer). Generation will only be suspended if the previous event has not yet been handled. Also,
* the position of the current working buffer upon stopping this asynchronous operation by a call to
* {@link #stopGeneration stopGeneration} is not predictable even if called from within the
* listener.
*
* Upon notification of the provided {@code GenerationRoundListener}
* the reference to the current working buffer (initially {@code src1}) can be retrieved from the
* {@code RoundCompletionEvent} using the {@link jdk.dio.RoundCompletionEvent#getBuffer() getBuffer} method.
*
* A working buffer with {@code 0} integers remaining to be written (that is a buffer already empty) at the moment this method is initially
* invoked or then subsequently when the listener is returning will not stop the asynchronous operation; the listener is
* guaranteed to be called back again at the latest as soon as all other events pending at the time of notification have been dispatched.
* The underrun condition resulting from the listener notification
* returning with an empty buffer will be reported on the subsequent notifications through
* the {@link jdk.dio.RoundCompletionEvent#isOnError() RoundCompletionEvent.isOnError} method.
*
* Only one pulse generation (synchronous or asynchronous) can be going on at any time.
*
* Buffers are not safe for use by multiple concurrent threads so care should
* be taken to not access the provided buffers until the operation (or a round thereof) has completed.
* Interfering with the asynchronous operation by accessing and modifying the provided buffers concurrently
* may yield unpredictable results.
*
* This method does not throw an {@link IllegalArgumentException} if any of the designated pulse width values
* is greater than the currently set period. If a pulse width value is not within range
* the actual width of the pulse generated by the PWM device is hardware- or driver-specific: the pulse width
* may for example be equal to the set period, corresponding to a 100% duty cycle.
*
* If the underlying platform or driver does not support a requested width value
* then the actual width of the pulse generated by the PWM device is hardware- or driver-specific: the pulse width
* may, for example, be aligned to the closest lower supported discrete width value.
*
*
* @param src1
* the first buffer from which the scaled pulse width integer values can be retrieved.
* @param src2
* the second buffer from which the scaled pulse width integer values can be retrieved.
* @param listener
* the {@link GenerationRoundListener} instance to be notified when pulses have been generated for all
* the width values remaining in the working buffer.
* @throws NullPointerException
* If {@code src1}, {@code src2} or {@code listener} is {@code null}.
* @throws IllegalStateException
* if another synchronous or asynchronous output generation is already active.
* @throws IllegalArgumentException
* if any of the buffers {@code src1} and {@code src2} has a zero-capacity or
* if they are the same or overlap.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws UnsupportedByteOrderException
* if the byte ordering of the any of the provided buffers is not supported (see Device Byte Order).
* @throws ClosedDeviceException
* if the device has been closed.
* @throws IOException
* if some other I/O error occurs.
*/
void startGeneration(IntBuffer src1, IntBuffer src2, GenerationRoundListener listener) throws IOException,
UnavailableDeviceException, UnsupportedByteOrderException, ClosedDeviceException;
/**
* Stops (cancels) the currently active pulse generation session as started by a call to one
* of the {@link #startGeneration startGeneration} methods.
*
* This method return silently if no pulse generation session is currently active.
*
*
* @throws IOException
* if some other I/O error occurs.
* @throws UnavailableDeviceException
* if this device is not currently available - such as it is locked by another application.
* @throws ClosedDeviceException
* if the device has been closed.
*/
void stopGeneration() throws IOException, UnavailableDeviceException, ClosedDeviceException;
/**
* Gets the output on which the pulses are generated.
*
* A concurrent runtime change of the dynamic configuration parameters of the
* output (such as of its direction) may result in {@code IOException} being
* thrown by PWM operations.
*
*
* @return the output on which the pulses are generated; or {@code null} if the output is implicit.
*
* @since 1.1
*/
GPIOPin getOutput();
}