001package com.pi4j.jni;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  Serial.java
009 *
010 * This file is part of the Pi4J project. More information about
011 * this project can be found here:  https://www.pi4j.com/
012 * **********************************************************************
013 * %%
014 * Copyright (C) 2012 - 2021 Pi4J
015 * %%
016 * This program is free software: you can redistribute it and/or modify
017 * it under the terms of the GNU Lesser General Public License as
018 * published by the Free Software Foundation, either version 3 of the
019 * License, or (at your option) any later version.
020 *
021 * This program is distributed in the hope that it will be useful,
022 * but WITHOUT ANY WARRANTY; without even the implied warranty of
023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
024 * GNU General Lesser Public License for more details.
025 *
026 * You should have received a copy of the GNU General Lesser Public
027 * License along with this program.  If not, see
028 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
029 * #L%
030 */
031
032import com.pi4j.util.NativeLibraryLoader;
033
034import java.io.*;
035import java.nio.ByteBuffer;
036import java.nio.CharBuffer;
037import java.nio.charset.Charset;
038import java.nio.charset.StandardCharsets;
039import java.util.Collection;
040
041/**
042 *  THIS IS CURRENTLY A NO-IMPL STUB.
043 *  THIS IS WHERE A NEW SERIAL LIBRARY IMPLEMENTATION IS PLANNED.
044 */
045public class Serial {
046
047    /**
048     * The default hardware COM port provided via the Raspberry Pi GPIO header.
049     *
050     * @see #open(String,int)
051     */
052    public static final String DEFAULT_COM_PORT = "/dev/ttyAMA0";
053    public static final String FIRST_USB_COM_PORT = "/dev/ttyUSB0";
054    public static final String SECOND_USB_COM_PORT = "/dev/ttyUSB1";
055
056    public static int BAUD_RATE_50     = 50;
057    public static int BAUD_RATE_75     = 75;
058    public static int BAUD_RATE_110    = 110;
059    public static int BAUD_RATE_134    = 134;
060    public static int BAUD_RATE_150    = 150;
061    public static int BAUD_RATE_200    = 200;
062    public static int BAUD_RATE_300    = 300;
063    public static int BAUD_RATE_600    = 600;
064    public static int BAUD_RATE_1200   = 1200;
065    public static int BAUD_RATE_1800   = 1800;
066    public static int BAUD_RATE_2400   = 2400;
067    public static int BAUD_RATE_4800   = 4800;
068    public static int BAUD_RATE_9600   = 9600;
069    public static int BAUD_RATE_19200  = 19200;
070    public static int BAUD_RATE_38400  = 38400;
071    public static int BAUD_RATE_57600  = 57600;
072    public static int BAUD_RATE_115200 = 115200;
073    public static int BAUD_RATE_230400 = 230400;
074
075    public static int PARITY_NONE  = 0;
076    public static int PARITY_ODD   = 1;
077    public static int PARITY_EVEN  = 2;
078    public static int PARITY_MARK  = 3;   // NOT ALL UNIX SYSTEM SUPPORT 'MARK' PARITY; THIS IS EXPERIMENTAL
079    public static int PARITY_SPACE = 4;   // NOT ALL UNIX SYSTEM SUPPORT 'SPACE' PARITY; THIS IS EXPERIMENTAL
080
081    public static int DATA_BITS_5 = 5;
082    public static int DATA_BITS_6 = 6;
083    public static int DATA_BITS_7 = 7;
084    public static int DATA_BITS_8 = 8;
085
086    public static int STOP_BITS_1 = 1;
087    public static int STOP_BITS_2 = 2;
088
089    public static int FLOW_CONTROL_NONE     = 0;
090    public static int FLOW_CONTROL_HARDWARE = 1;
091    public static int FLOW_CONTROL_SOFTWARE = 2;
092
093
094    // private constructor
095    private Serial() {
096        // forbid object construction
097    }
098
099    static {
100        // Load the platform library
101        NativeLibraryLoader.load("libpi4j.so", "pi4j");
102    }
103
104    /**
105     * <p>
106     * This opens and initializes the serial port/device and sets the communication parameters.
107     * It sets the port into raw mode (character at a time and no translations).
108     * </p>
109     *
110     * <p>
111     * (ATTENTION: the 'device' argument can only be a maximum of 128 characters.)
112     * </p>
113     *
114     * @see #DEFAULT_COM_PORT
115     *
116     * @param device
117     *          The device address of the serial port to access. You can use constant
118     *          'DEFAULT_COM_PORT' if you wish to access the default serial port provided via the
119     *          GPIO header.
120     * @param baud
121     *          The baud rate to use with the serial port. (Custom baud rate are not supported)
122     * @param dataBits
123     *          The data bits to use for serial communication. (5,6,7,8)
124     * @param parity
125     *          The parity setting to use for serial communication. (None, Event, Odd, Mark, Space)
126     * @param stopBits
127     *          The stop bits to use for serial communication. (1,2)
128     * @param flowControl
129     *          The stop bits to use for serial communication. (none, hardware, software)
130     *
131     * @return The return value is the file descriptor or a negative value for any error.
132     *          An IOException will be thrown for all error conditions.
133     */
134    public synchronized static native int open(String device, int baud, int dataBits, int parity, int stopBits,
135                                               int flowControl) throws IOException;
136
137    /**
138     * <p>
139     * This opens and initializes the serial port/device and sets the communication parameters.
140     * It sets the port into raw mode (character at a time and no translations).
141     *
142     * The following default serial communications parameters are applied using this overloaded method instance:
143     *      flow control = FLOW_CONTROL_NONE
144     * </p>
145     *
146     * <p>
147     * (ATTENTION: the 'device' argument can only be a maximum of 128 characters.)
148     * </p>
149     *
150     * @see #DEFAULT_COM_PORT
151     * @see #FLOW_CONTROL_NONE
152     *
153     * @param device
154     *          The device address of the serial port to access. You can use constant
155     *          'DEFAULT_COM_PORT' if you wish to access the default serial port provided via the
156     *          GPIO header.
157     * @param baud
158     *          The baud rate to use with the serial port. (Custom baud rate are not supported)
159     * @param dataBits
160     *          The data bits to use for serial communication. (5,6,7,8)
161     * @param parity
162     *          The parity setting to use for serial communication. (None, Event, Odd, Mark, Space)
163     * @param stopBits
164     *          The stop bits to use for serial communication. (1,2)
165     *
166     * @return The return value is the file descriptor or a negative value for any error.
167     *          An IOException will be thrown for all error conditions.
168     */
169    public synchronized static int open(String device, int baud, int dataBits, int parity, int stopBits)
170                                               throws IOException {
171        return open(device, baud, dataBits, parity, stopBits, FLOW_CONTROL_NONE);
172    }
173
174    /**
175     * <p>
176     * This opens and initializes the serial port/device and sets the communication parameters.
177     * It sets the port into raw mode (character at a time and no translations).
178     *
179     * The following default serial communications parameters are applied using this overloaded method instance:
180     *      stop bits    = STOP_BITS_1
181     *      flow control = FLOW_CONTROL_NONE
182     * </p>
183     *
184     * <p>
185     * (ATTENTION: the 'device' argument can only be a maximum of 128 characters.)
186     * </p>
187     *
188     * @see #DEFAULT_COM_PORT
189     * @see #STOP_BITS_1
190     * @see #FLOW_CONTROL_NONE
191     *
192     * @param device
193     *          The device address of the serial port to access. You can use constant
194     *          'DEFAULT_COM_PORT' if you wish to access the default serial port provided via the
195     *          GPIO header.
196     * @param baud
197     *          The baud rate to use with the serial port. (Custom baud rate are not supported)
198     * @param dataBits
199     *          The data bits to use for serial communication. (5,6,7,8)
200     *
201     * @return The return value is the file descriptor or a negative value for any error.
202     *          An IOException will be thrown for all error conditions.
203     */
204    public synchronized static int open(String device, int baud, int dataBits, int parity) throws IOException {
205        return open(device, baud, dataBits, parity, STOP_BITS_1, FLOW_CONTROL_NONE);
206    }
207
208    /**
209     * <p>
210     * This opens and initializes the serial device and sets the communication parameters.
211     * It sets the port into raw mode (character at a time and no translations).
212     *
213     * The following default serial communications parameters are applied using this overloaded method instance:
214     *      parity       = PARITY_NONE
215     *      stop bits    = STOP_BITS_1
216     *      flow control = FLOW_CONTROL_NONE
217     * </p>
218     *
219     * <p>
220     * (ATTENTION: the 'device' argument can only be a maximum of 128 characters.)
221     * </p>
222     *
223     * @see #DEFAULT_COM_PORT
224     * @see #PARITY_NONE
225     * @see #STOP_BITS_1
226     * @see #FLOW_CONTROL_NONE
227     *
228     * @param device
229     *          The device address of the serial port to access. You can use constant
230     *          'DEFAULT_COM_PORT' if you wish to access the default serial port provided via the
231     *          GPIO header.
232     * @param baud
233     *          The baud rate to use with the serial port. (Custom baud rate are not supported)
234     * @param dataBits
235     *          The data bits to use for serial communication. (5,6,7,8)
236     *
237     * @return The return value is the file descriptor or a negative value for any error.
238     *          An IOException will be thrown for all error conditions.
239     */
240    public synchronized static int open(String device, int baud, int dataBits) throws IOException {
241        return open(device, baud, dataBits, PARITY_NONE, STOP_BITS_1, FLOW_CONTROL_NONE);
242    }
243
244    /**
245     * <p>
246     * This opens and initializes the serial device and sets the communication parameters.
247     * It sets the port into raw mode (character at a time and no translations).
248     *
249     * The following default serial communications parameters are applied using this overloaded method instance:
250     *      data bits    = DATA_BITS_8
251     *      parity       = PARITY_NONE
252     *      stop bits    = STOP_BITS_1
253     *      flow control = FLOW_CONTROL_NONE
254     * </p>
255     *
256     * <p>
257     * (ATTENTION: the 'device' argument can only be a maximum of 128 characters.)
258     * </p>
259     *
260     * @see #DEFAULT_COM_PORT
261     * @see #DATA_BITS_8
262     * @see #PARITY_NONE
263     * @see #STOP_BITS_1
264     * @see #FLOW_CONTROL_NONE
265     *
266     * @param device
267     *          The device address of the serial port to access. You can use constant
268     *          'DEFAULT_COM_PORT' if you wish to access the default serial port provided via the
269     *          GPIO header.
270     * @param baud
271     *          The baud rate to use with the serial port. (Custom baud rate are not supported)
272     *
273     * @return The return value is the file descriptor or a negative value for any error.
274     *          An IOException will be thrown for all error conditions.
275     */
276    public synchronized static int open(String device, int baud) throws IOException {
277        return open(device, baud, DATA_BITS_8, PARITY_NONE, STOP_BITS_1, FLOW_CONTROL_NONE);
278    }
279
280    /**
281     * <p>
282     * Closes the serial port/device identified by the file descriptor.
283     * </p>
284     *
285     * @param fd
286     *          The file descriptor of the serial port/device.
287     */
288    public synchronized static native void close(int fd) throws IOException;
289
290    /**
291     * <p>
292     *     Discards all data in the serial receive and transmit buffer.
293     * </p>
294     *
295     * @param fd
296     *          The file descriptor of the serial port/device.
297     */
298    public synchronized static native void discardInput(int fd) throws IOException;
299
300    /**
301     * <p>
302     *     Discards all data in the serial transmit buffer.
303     * </p>
304     *
305     * @param fd
306     *          The file descriptor of the serial port/device.
307     */
308    public synchronized static native void discardOutput(int fd) throws IOException;
309
310    /**
311     * <p>
312     *     Discards all data in the serial transmit and receive buffers.
313     * </p>
314     *
315     * @param fd
316     *          The file descriptor of the serial port/device.
317     */
318    public synchronized static native void discardAll(int fd) throws IOException;
319
320    /**
321     * <p>
322     *     Forces (drains) all data in transmit buffers.
323     * </p>
324     *
325     * @param fd
326     *          The file descriptor of the serial port/device.
327     */
328    public synchronized static native void flush(int fd) throws IOException;
329
330    /**
331     * <p>
332     *     Send a BREAK signal to connected device.
333     * </p>
334     *
335     * @param fd
336     *          The file descriptor of the serial port/device.
337     * @param duration
338     *          The length of time (milliseconds) to send the BREAK signal
339     */
340    public synchronized static native void sendBreak(int fd, int duration) throws IOException;
341
342    /**
343     * <p>
344     *     Send a BREAK signal to connected device for at least 0.25 seconds, and not more than 0.5 seconds
345     * </p>
346     *
347     * @param fd
348     *          The file descriptor of the serial port/device.
349     */
350    public synchronized static void sendBreak(int fd) throws IOException {
351        sendBreak(fd, 0);
352    }
353
354    /**
355     * <p>
356     *     Send a constant BREAK signal to connected device. (Turn break on/off)
357     *     When enabled this will send a steady stream of zero bits.
358     *     When enabled, no (other) data transmitting is possible.
359     * </p>
360     *
361     * @param fd
362     *          The file descriptor of the serial port/device.
363     * @param enabled
364     *          The enable or disable state to control the BREAK signal
365     */
366    public synchronized static native void setBreak(int fd, boolean enabled) throws IOException;
367
368    /**
369     * <p>
370     *     Control the RTS (request-to-send) pin state.
371     *     When enabled this will set the RTS pin to the HIGH state.
372     * </p>
373     *
374     * @param fd
375     *          The file descriptor of the serial port/device.
376     * @param enabled
377     *          The enable or disable state to control the RTS pin state.
378     */
379    public synchronized static native void setRTS(int fd, boolean enabled) throws IOException;
380
381    /**
382     * <p>
383     *     Control the DTR (data-terminal-ready) pin state.
384     *     When enabled this will set the DTR pin to the HIGH state.
385     * </p>
386     *
387     * @param fd
388     *          The file descriptor of the serial port/device.
389     * @param enabled
390     *          The enable or disable state to control the RTS pin state.
391     */
392    public synchronized static native void setDTR(int fd, boolean enabled) throws IOException;
393
394    /**
395     * <p>
396     *     Get the RTS (request-to-send) pin state.
397     * </p>
398     *
399     * @param fd
400     *          The file descriptor of the serial port/device.
401     */
402    public synchronized static native boolean getRTS(int fd) throws IOException;
403
404    /**
405     * <p>
406     *     Get the DTR (data-terminal-ready) pin state.
407     * </p>
408     *
409     * @param fd
410     *          The file descriptor of the serial port/device.
411     */
412    public synchronized static native boolean getDTR(int fd) throws IOException;
413
414    /**
415     * <p>
416     *     Get the CST (clear-to-send) pin state.
417     * </p>
418     *
419     * @param fd
420     *          The file descriptor of the serial port/device.
421     */
422    public synchronized static native boolean getCTS(int fd) throws IOException;
423
424    /**
425     * <p>
426     *     Get the DSR (data-set-ready) pin state.
427     * </p>
428     *
429     * @param fd
430     *          The file descriptor of the serial port/device.
431     */
432    public synchronized static native boolean getDSR(int fd) throws IOException;
433
434    /**
435     * <p>
436     *     Get the RI (ring-indicator) pin state.
437     * </p>
438     *
439     * @param fd
440     *          The file descriptor of the serial port/device.
441     */
442    public synchronized static native boolean getRI(int fd) throws IOException;
443
444    /**
445     * <p>
446     *     Get the CD (carrier-detect) pin state.
447     * </p>
448     *
449     * @param fd
450     *          The file descriptor of the serial port/device.
451     */
452    public synchronized static native boolean getCD(int fd) throws IOException;
453
454    // ----------------------------------------
455    // READ OPERATIONS
456    // ----------------------------------------
457
458    /**
459     * Returns the number of characters available for reading, or -1 for any error condition, in
460     * which case errno will be set appropriately.
461     *
462     * @param fd
463     *          The file descriptor of the serial port/device.
464     *
465     * @return Returns the number of characters available for reading, or -1 for any error
466     */
467    public synchronized static native int available(int fd);
468
469
470    /**
471     * <p>Reads all available bytes from the serial port/device.</p>
472     *
473     * @param fd
474     *          The file descriptor of the serial port/device.
475     *
476     * @return Returns a byte array with the data read from the serial port.
477     */
478    public synchronized static native byte[] read(int fd) throws IOException;
479
480    /**
481     * <p>Reads a length of bytes from the port/serial device.</p>
482     *
483     * @param fd
484     *          The file descriptor of the serial port/device.
485     * @param length
486     *          The number of bytes to get from the serial port/device.
487     *          This number must not be higher than the number of available bytes.
488     *
489     * @return Returns a byte array with the data read from the serial port.
490     */
491    public synchronized static native byte[] read(int fd, int length) throws IOException;
492
493    /**
494     * <p>Reads all available bytes from the serial device into a provided ByteBuffer.</p>
495     *
496     * @param fd
497     *          The file descriptor of the serial port/device.
498     * @param buffer
499     *          The ByteBuffer object to write to.
500     */
501    public synchronized static void read(int fd, ByteBuffer buffer) throws IOException{
502        byte[] data = read(fd);
503        buffer.put(data);
504    }
505
506    /**
507     * <p>Reads a length bytes from the serial port/device into a provided ByteBuffer.</p>
508     *
509     * @param fd
510     *          The file descriptor of the serial port/device.
511     * @param length
512     *          The number of bytes to get from the serial port/device.
513     *          This number must not be higher than the number of available bytes.
514     * @param buffer
515     *          The ByteBuffer object to write to.
516     *
517     */
518    public synchronized static void read(int fd, int length, ByteBuffer buffer) throws IOException{
519        buffer.put(read(fd, length));
520    }
521
522    /**
523     * <p>Reads all available bytes from the serial device into a provided OutputStream.</p>
524     *
525     * @param fd
526     *          The file descriptor of the serial port/device.
527     * @param stream
528     *          The OutputStream object to write to.
529     */
530    public synchronized static void read(int fd, OutputStream stream) throws IOException{
531        stream.write(read(fd));
532    }
533
534    /**
535     * <p>Reads a length bytes from the serial port/device into a provided OutputStream.</p>
536     *
537     * @param fd
538     *          The file descriptor of the serial port/device.
539     * @param length
540     *          The number of bytes to get from the serial port/device.
541     *          This number must not be higher than the number of available bytes.
542     * @param stream
543     *          The OutputStream object to write to.
544     *
545     */
546    public synchronized static void read(int fd, int length, OutputStream stream) throws IOException{
547        stream.write(read(fd, length));
548    }
549
550    /**
551     * <p>Reads all available bytes from the serial port/device into a provided collection of ByteBuffer objects.</p>
552     *
553     * @param fd
554     *          The file descriptor of the serial port/device.
555     * @param collection
556     *          The collection of CharSequence objects to append to.
557     *
558     */
559    public synchronized static void read(int fd, Collection<ByteBuffer> collection) throws IOException{
560        collection.add(ByteBuffer.wrap(read(fd)));
561    }
562
563    /**
564     * <p>Reads a length of bytes from the serial port/device into a provided collection of ByteBuffer objects.</p>
565     *
566     * @param fd
567     *          The file descriptor of the serial port/device.
568     * @param length
569     *          The number of bytes to get from the serial port/device.
570     *          This number must not be higher than the number of available bytes.
571     * @param collection
572     *          The collection of CharSequence objects to append to.
573     *
574     */
575    public synchronized static void read(int fd, int length, Collection<ByteBuffer> collection) throws IOException{
576        collection.add(ByteBuffer.wrap(read(fd)));
577    }
578
579    /**
580     * <p>Reads all available bytes from the port/serial device.</p>
581     *
582     * @param fd
583     *          The file descriptor of the serial port/device.
584     * @param charset
585     *          The character set to use for encoding/decoding bytes to/from text characters
586     *
587     * @return Returns a character set with the data read from the serial port.
588     */
589    public synchronized static CharBuffer read(int fd, Charset charset) throws IOException{
590        return charset.decode(ByteBuffer.wrap(read(fd)));
591    }
592
593    /**
594     * <p>Reads a length of bytes from the port/serial device.</p>
595     *
596     * @param fd
597     *          The file descriptor of the serial port/device.
598     * @param length
599     *          The number of bytes to get from the serial port/device.
600     *          This number must not be higher than the number of available bytes.
601     * @param charset
602     *          The character set to use for encoding/decoding bytes to/from text characters
603     *
604     * @return Returns a character set with the data read from the serial port.
605     */
606    public synchronized static CharBuffer read(int fd, int length, Charset charset) throws IOException{
607        return charset.decode(ByteBuffer.wrap(read(fd, length)));
608    }
609
610    /**
611     * <p>Reads all available bytes from the serial port/device into a provided Writer.</p>
612     *
613     * @param fd
614     *          The file descriptor of the serial port/device.
615     * @param charset
616     *          The character set to use for encoding/decoding bytes to/from text characters
617     * @param writer
618     *          The Writer object to write to.
619     *
620     */
621    public synchronized static void read(int fd, Charset charset, Writer writer) throws IOException{
622        writer.write(read(fd, charset).toString());
623    }
624
625    /**
626     * <p>Reads a length bytes from the serial port/device into a provided Writer.</p>
627     *
628     * @param fd
629     *          The file descriptor of the serial port/device.
630     * @param length
631     *          The number of bytes to get from the serial port/device.
632     *          This number must not be higher than the number of available bytes.
633     * @param charset
634     *          The character set to use for encoding/decoding bytes to/from text characters
635     * @param writer
636     *          The Writer object to write to.
637     *
638     */
639    public synchronized static void read(int fd, int length, Charset charset, Writer writer) throws IOException{
640        writer.write(read(fd, length, charset).toString());
641    }
642
643
644    // ----------------------------------------
645    // WRITE OPERATIONS
646    // ----------------------------------------
647
648    /**
649     * <p>Sends an array of bytes to the serial port/device identified by the given file descriptor.</p>
650     *
651     *
652     * @param fd
653     *            The file descriptor of the serial port/device.
654     * @param data
655     *            A ByteBuffer of data to be transmitted.
656     * @param length
657     *            The number of bytes from the byte array to transmit to the serial port.
658     */
659    private synchronized static native void write(int fd, byte[] data, long length) throws IOException;
660
661    /**
662     * <p>Sends an array of bytes to the serial port/device identified by the given file descriptor.</p>
663     *
664     * @param fd
665     *            The file descriptor of the serial port/device.
666     * @param data
667     *            A ByteBuffer of data to be transmitted.
668     * @param offset
669     *            The starting index (inclusive) in the array to send from.
670     * @param length
671     *            The number of bytes from the byte array to transmit to the serial port.
672     */
673    public synchronized static void write(int fd, byte[] data, int offset, int length) throws IOException {
674
675        // we make a copy of the data argument because we don't want to modify the original source data
676        byte[] buffer = new byte[length];
677        System.arraycopy(data, offset, buffer, 0, length);
678
679        // write the buffer contents to the serial port via JNI native method
680        write(fd, buffer, length);
681    }
682
683    /**
684     * <p>Sends one of more bytes to the serial device identified by the given file descriptor.</p>
685     *
686     * @param fd
687     *            The file descriptor of the serial port/device.
688     * @param data
689     *            One or more bytes (or an array) of data to be transmitted. (variable-length-argument)
690     */
691    public synchronized static void write(int fd, byte ... data) throws IOException {
692
693        // write the data contents to the serial port via JNI native method
694        write(fd, data, data.length);
695    }
696
697    /**
698     * <p>Sends one of more bytes arrays to the serial device identified by the given file descriptor.</p>
699     *
700     * @param fd
701     *            The file descriptor of the serial port/device.
702     * @param data
703     *            One or more byte arrays of data to be transmitted. (variable-length-argument)
704     */
705    public synchronized static void write(int fd, byte[] ... data) throws IOException {
706        for(byte[] single : data) {
707            // write the data contents to the serial port via JNI native method
708            write(fd, single, single.length);
709        }
710    }
711
712    /**
713     * Read the content of byte buffer and write the data to the serial port transmit buffer.
714     * (The buffer is read from the current position up to the 'limit' value, not the 'capacity'.  You may need to
715     * rewind() or flip() the byte buffer if you have just written to it.)
716     *
717     * @param fd
718     *            The file descriptor of the serial port/device.
719     * @param data
720     *            A ByteBuffer of data to be transmitted.
721     */
722    public synchronized static void write(int fd, ByteBuffer ... data) throws IOException{
723
724        // write each byte buffer to the serial port
725        for(ByteBuffer single : data) {
726
727            // read the byte buffer from the current position up to the limit
728            byte[] payload = new byte[single.remaining()];
729            single.get(payload);
730
731            // write the data contents to the serial port via JNI native method
732            write(fd, payload, payload.length);
733        }
734    }
735
736    /**
737     * Read content from an input stream of data and write it to the serial port transmit buffer.
738     *
739     * @param fd
740     *          The file descriptor of the serial port/device.
741     * @param input
742     *          An InputStream of data to be transmitted
743     */
744    public synchronized static void write(int fd, InputStream input) throws IOException {
745
746        // ensure bytes are available
747        if(input.available() <= 0){
748            throw new IOException("No available bytes in input stream to write to serial port.");
749        }
750
751        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
752        int length;
753        byte[] data = new byte[1024];
754        while ((length = input.read(data, 0, data.length)) != -1) {
755            buffer.write(data, 0, length);
756        }
757        buffer.flush();
758
759        // write bytes to serial port
760        write(fd, buffer.toByteArray(), buffer.size());
761    }
762
763    /**
764     * <p>Sends an array of characters to the serial port/device identified by the given file descriptor.</p>
765     *
766     * @param fd
767     *           The file descriptor of the serial port/device.
768     * @param charset
769     *           The character set to use for encoding/decoding bytes to/from text characters
770     * @param data
771     *           An array of chars to be decoded into bytes and transmitted.
772     * @param offset
773     *           The starting index (inclusive) in the array to send from.
774     * @param length
775     *           The number of characters from the char array to transmit to the serial port.
776     */
777    public synchronized static void write(int fd, Charset charset, char[] data, int offset, int length) throws IOException {
778
779        // write the buffer contents to the serial port via JNI native method
780        write(fd, charset, CharBuffer.wrap(data, offset, length));
781    }
782
783    /**
784     * <p>Sends an array of characters to the serial port/device identified by the given file descriptor.</p>
785     *
786     * @param fd
787     *           The file descriptor of the serial port/device.
788     * @param charset
789     *           The character set to use for encoding/decoding bytes to/from text characters
790     * @param data
791     *           One or more characters (or an array) of data to be transmitted. (variable-length-argument)
792     */
793    public synchronized static void write(int fd, Charset charset, char ... data) throws IOException {
794
795        // write the buffer contents to the serial port via JNI native method
796        write(fd, charset, CharBuffer.wrap(data));
797    }
798
799    /**
800     * <p>Sends an array of ASCII characters to the serial port/device identified by the given file descriptor.</p>
801     *
802     * @param fd
803     *           The file descriptor of the serial port/device.
804     * @param data
805     *           One or more ASCII characters (or an array) of data to be transmitted. (variable-length-argument)
806     */
807    public synchronized static void write(int fd, char ... data) throws IOException {
808
809        // write the buffer contents to the serial port via JNI native method
810        write(fd, StandardCharsets.US_ASCII, CharBuffer.wrap(data));
811    }
812
813    /**
814     * <p>Sends one or more CharBuffers to the serial port/device identified by the given file descriptor.</p>
815     *
816     * @param fd
817     *           The file descriptor of the serial port/device.
818     * @param charset
819     *           The character set to use for encoding/decoding bytes to/from text characters
820     * @param data
821     *           One or more CharBuffers (or an array) of data to be transmitted. (variable-length-argument)
822     */
823    public synchronized static void write(int fd, Charset charset, CharBuffer ... data) throws IllegalStateException, IOException {
824        for(CharBuffer single : data) {
825            write(fd, charset.encode(single));
826        }
827    }
828
829    /**
830     * <p>Sends one or more ASCII CharBuffers to the serial port/device identified by the given file descriptor.</p>
831     *
832     * @param fd
833     *           The file descriptor of the serial port/device.
834     * @param data
835     *           One or more ASCII CharBuffers (or an array) of data to be transmitted. (variable-length-argument)
836     */
837    public synchronized static void write(int fd, CharBuffer ... data) throws IllegalStateException, IOException {
838        write(fd, StandardCharsets.US_ASCII, data);
839    }
840
841    /**
842     * <p>Sends one or more string objects to the serial port/device identified by the given file descriptor.</p>
843     *
844     * @param fd
845     *           The file descriptor of the serial port/device.
846     * @param charset
847     *           The character set to use for encoding/decoding bytes to/from text characters
848     * @param data
849     *           One or more string objects (or an array) of data to be transmitted. (variable-length-argument)
850     */
851    public synchronized static void write(int fd, Charset charset, CharSequence ... data) throws IllegalStateException, IOException {
852        for(CharSequence single : data) {
853            write(fd, charset.encode(CharBuffer.wrap(single)));
854        }
855    }
856
857    /**
858     * <p>Sends one or more ASCII string objects to the serial port/device identified by the given file descriptor.</p>
859     *
860     * @param fd
861     *           The file descriptor of the serial port/device.
862     * @param data
863     *           One or more ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
864     */
865    public synchronized static void write(int fd, CharSequence ... data) throws IllegalStateException, IOException {
866        write(fd, StandardCharsets.US_ASCII, data);
867    }
868
869
870    /**
871     * <p>Sends a collection of string objects to the serial port/device identified by the given file descriptor.</p>
872     *
873     * @param fd
874     *           The file descriptor of the serial port/device.
875     * @param charset
876     *           The character set to use for encoding/decoding bytes to/from text characters
877     * @param data
878     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
879     */
880    public synchronized static void write(int fd, Charset charset, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
881        for(CharSequence single : data) {
882            write(fd, charset.encode(CharBuffer.wrap(single)));
883        }
884    }
885
886    /**
887     * <p>Sends a collection of ASCII string objects to the serial port/device identified by the given file descriptor.</p>
888     *
889     * @param fd
890     *           The file descriptor of the serial port/device.
891     * @param data
892     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
893     */
894    public synchronized static void write(int fd, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
895        write(fd, StandardCharsets.US_ASCII, data);
896    }
897
898
899    /**
900     * <p>Sends one or more string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
901     *
902     * @param fd
903     *           The file descriptor of the serial port/device.
904     * @param charset
905     *           The character set to use for encoding/decoding bytes to/from text characters
906     * @param data
907     *           One or more string objects (or an array) of data to be transmitted. (variable-length-argument)
908     */
909    public synchronized static void writeln(int fd, Charset charset, CharSequence ... data) throws IllegalStateException, IOException {
910        for(CharSequence single : data) {
911            write(fd, charset.encode(CharBuffer.wrap(single + "\r\n")));
912        }
913    }
914
915    /**
916     * <p>Sends one or more ASCII string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
917     *
918     * @param fd
919     *           The file descriptor of the serial port/device.
920     * @param data
921     *           One or more ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
922     */
923    public synchronized static void writeln(int fd, CharSequence ... data) throws IllegalStateException, IOException {
924        writeln(fd, StandardCharsets.US_ASCII, data);
925    }
926
927    /**
928     * <p>Sends a collection of string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
929     *
930     * @param fd
931     *           The file descriptor of the serial port/device.
932     * @param charset
933     *           The character set to use for encoding/decoding bytes to/from text characters
934     * @param data
935     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
936     */
937    public synchronized static void writeln(int fd, Charset charset, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
938        for(CharSequence single : data) {
939            write(fd, charset.encode(CharBuffer.wrap(single + "\r\n")));
940        }
941    }
942
943    /**
944     * <p>Sends a collection of ASCII string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
945     *
946     * @param fd
947     *           The file descriptor of the serial port/device.
948     * @param data
949     *           A collection of ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
950     */
951    public synchronized static void writeln(int fd, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
952        writeln(fd, StandardCharsets.US_ASCII, data);
953    }
954
955}