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 - 2019 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");
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     *     Please note that this does not force the transmission of data, it discards it!
294     * </p>
295     *
296     * @param fd
297     *          The file descriptor of the serial port/device.
298     */
299    public synchronized static native void discardInput(int fd) throws IOException;
300
301    /**
302     * <p>
303     *     Discards all data in the serial transmit buffer.
304     *     Please note that this does not force the transmission of data, it discards it!
305     * </p>
306     *
307     * @param fd
308     *          The file descriptor of the serial port/device.
309     */
310    public synchronized static native void discardOutput(int fd) throws IOException;
311
312    /**
313     * <p>
314     *     Discards all data in the serial transmit and receive buffers.
315     *     Please note that this does not force the transmission of data, it discards it!
316     * </p>
317     *
318     * @param fd
319     *          The file descriptor of the serial port/device.
320     */
321    public synchronized static native void discardAll(int fd) throws IOException;
322
323    /**
324     * <p>
325     *     Forces (drains) all data in transmit buffers.
326     * </p>
327     *
328     * @param fd
329     *          The file descriptor of the serial port/device.
330     */
331    public synchronized static native void flush(int fd) throws IOException;
332
333    /**
334     * <p>
335     *     Send a BREAK signal to connected device.
336     * </p>
337     *
338     * @param fd
339     *          The file descriptor of the serial port/device.
340     * @param duration
341     *          The length of time (milliseconds) to send the BREAK signal
342     */
343    public synchronized static native void sendBreak(int fd, int duration) throws IOException;
344
345    /**
346     * <p>
347     *     Send a BREAK signal to connected device for at least 0.25 seconds, and not more than 0.5 seconds
348     * </p>
349     *
350     * @param fd
351     *          The file descriptor of the serial port/device.
352     */
353    public synchronized static void sendBreak(int fd) throws IOException {
354        sendBreak(fd, 0);
355    }
356
357    /**
358     * <p>
359     *     Send a constant BREAK signal to connected device. (Turn break on/off)
360     *     When enabled this will send a steady stream of zero bits.
361     *     When enabled, no (other) data transmitting is possible.
362     * </p>
363     *
364     * @param fd
365     *          The file descriptor of the serial port/device.
366     * @param enabled
367     *          The enable or disable state to control the BREAK signal
368     */
369    public synchronized static native void setBreak(int fd, boolean enabled) throws IOException;
370
371    /**
372     * <p>
373     *     Control the RTS (request-to-send) pin state.
374     *     When enabled this will set the RTS pin to the HIGH state.
375     * </p>
376     *
377     * @param fd
378     *          The file descriptor of the serial port/device.
379     * @param enabled
380     *          The enable or disable state to control the RTS pin state.
381     */
382    public synchronized static native void setRTS(int fd, boolean enabled) throws IOException;
383
384    /**
385     * <p>
386     *     Control the DTR (data-terminal-ready) pin state.
387     *     When enabled this will set the DTR pin to the HIGH state.
388     * </p>
389     *
390     * @param fd
391     *          The file descriptor of the serial port/device.
392     * @param enabled
393     *          The enable or disable state to control the RTS pin state.
394     */
395    public synchronized static native void setDTR(int fd, boolean enabled) throws IOException;
396
397    /**
398     * <p>
399     *     Get the RTS (request-to-send) pin state.
400     * </p>
401     *
402     * @param fd
403     *          The file descriptor of the serial port/device.
404     */
405    public synchronized static native boolean getRTS(int fd) throws IOException;
406
407    /**
408     * <p>
409     *     Get the DTR (data-terminal-ready) pin state.
410     * </p>
411     *
412     * @param fd
413     *          The file descriptor of the serial port/device.
414     */
415    public synchronized static native boolean getDTR(int fd) throws IOException;
416
417    /**
418     * <p>
419     *     Get the CST (clear-to-send) pin state.
420     * </p>
421     *
422     * @param fd
423     *          The file descriptor of the serial port/device.
424     */
425    public synchronized static native boolean getCTS(int fd) throws IOException;
426
427    /**
428     * <p>
429     *     Get the DSR (data-set-ready) pin state.
430     * </p>
431     *
432     * @param fd
433     *          The file descriptor of the serial port/device.
434     */
435    public synchronized static native boolean getDSR(int fd) throws IOException;
436
437    /**
438     * <p>
439     *     Get the RI (ring-indicator) pin state.
440     * </p>
441     *
442     * @param fd
443     *          The file descriptor of the serial port/device.
444     */
445    public synchronized static native boolean getRI(int fd) throws IOException;
446
447    /**
448     * <p>
449     *     Get the CD (carrier-detect) pin state.
450     * </p>
451     *
452     * @param fd
453     *          The file descriptor of the serial port/device.
454     */
455    public synchronized static native boolean getCD(int fd) throws IOException;
456
457    // ----------------------------------------
458    // READ OPERATIONS
459    // ----------------------------------------
460
461    /**
462     * Returns the number of characters available for reading, or -1 for any error condition, in
463     * which case errno will be set appropriately.
464     *
465     * @param fd
466     *          The file descriptor of the serial port/device.
467     *
468     * @return Returns the number of characters available for reading, or -1 for any error
469     */
470    public synchronized static native int available(int fd);
471
472
473    /**
474     * <p>Reads all available bytes from the serial port/device.</p>
475     *
476     * @param fd
477     *          The file descriptor of the serial port/device.
478     *
479     * @return Returns a byte array with the data read from the serial port.
480     */
481    public synchronized static native byte[] read(int fd) throws IOException;
482
483    /**
484     * <p>Reads a length of bytes from the port/serial device.</p>
485     *
486     * @param fd
487     *          The file descriptor of the serial port/device.
488     * @param length
489     *          The number of bytes to get from the serial port/device.
490     *          This number must not be higher than the number of available bytes.
491     *
492     * @return Returns a byte array with the data read from the serial port.
493     */
494    public synchronized static native byte[] read(int fd, int length) throws IOException;
495
496    /**
497     * <p>Reads all available bytes from the serial device into a provided ByteBuffer.</p>
498     *
499     * @param fd
500     *          The file descriptor of the serial port/device.
501     * @param buffer
502     *          The ByteBuffer object to write to.
503     */
504    public synchronized static void read(int fd, ByteBuffer buffer) throws IOException{
505        byte[] data = read(fd);
506        buffer.put(data);
507    }
508
509    /**
510     * <p>Reads a length bytes from the serial port/device into a provided ByteBuffer.</p>
511     *
512     * @param fd
513     *          The file descriptor of the serial port/device.
514     * @param length
515     *          The number of bytes to get from the serial port/device.
516     *          This number must not be higher than the number of available bytes.
517     * @param buffer
518     *          The ByteBuffer object to write to.
519     *
520     */
521    public synchronized static void read(int fd, int length, ByteBuffer buffer) throws IOException{
522        buffer.put(read(fd, length));
523    }
524
525    /**
526     * <p>Reads all available bytes from the serial device into a provided OutputStream.</p>
527     *
528     * @param fd
529     *          The file descriptor of the serial port/device.
530     * @param stream
531     *          The OutputStream object to write to.
532     */
533    public synchronized static void read(int fd, OutputStream stream) throws IOException{
534        stream.write(read(fd));
535    }
536
537    /**
538     * <p>Reads a length bytes from the serial port/device into a provided OutputStream.</p>
539     *
540     * @param fd
541     *          The file descriptor of the serial port/device.
542     * @param length
543     *          The number of bytes to get from the serial port/device.
544     *          This number must not be higher than the number of available bytes.
545     * @param stream
546     *          The OutputStream object to write to.
547     *
548     */
549    public synchronized static void read(int fd, int length, OutputStream stream) throws IOException{
550        stream.write(read(fd, length));
551    }
552
553    /**
554     * <p>Reads all available bytes from the serial port/device into a provided collection of ByteBuffer objects.</p>
555     *
556     * @param fd
557     *          The file descriptor of the serial port/device.
558     * @param collection
559     *          The collection of CharSequence objects to append to.
560     *
561     */
562    public synchronized static void read(int fd, Collection<ByteBuffer> collection) throws IOException{
563        collection.add(ByteBuffer.wrap(read(fd)));
564    }
565
566    /**
567     * <p>Reads a length of bytes from the serial port/device into a provided collection of ByteBuffer objects.</p>
568     *
569     * @param fd
570     *          The file descriptor of the serial port/device.
571     * @param length
572     *          The number of bytes to get from the serial port/device.
573     *          This number must not be higher than the number of available bytes.
574     * @param collection
575     *          The collection of CharSequence objects to append to.
576     *
577     */
578    public synchronized static void read(int fd, int length, Collection<ByteBuffer> collection) throws IOException{
579        collection.add(ByteBuffer.wrap(read(fd)));
580    }
581
582    /**
583     * <p>Reads all available bytes from the port/serial device.</p>
584     *
585     * @param fd
586     *          The file descriptor of the serial port/device.
587     * @param charset
588     *          The character set to use for encoding/decoding bytes to/from text characters
589     *
590     * @return Returns a character set with the data read from the serial port.
591     */
592    public synchronized static CharBuffer read(int fd, Charset charset) throws IOException{
593        return charset.decode(ByteBuffer.wrap(read(fd)));
594    }
595
596    /**
597     * <p>Reads a length of bytes from the port/serial device.</p>
598     *
599     * @param fd
600     *          The file descriptor of the serial port/device.
601     * @param length
602     *          The number of bytes to get from the serial port/device.
603     *          This number must not be higher than the number of available bytes.
604     * @param charset
605     *          The character set to use for encoding/decoding bytes to/from text characters
606     *
607     * @return Returns a character set with the data read from the serial port.
608     */
609    public synchronized static CharBuffer read(int fd, int length, Charset charset) throws IOException{
610        return charset.decode(ByteBuffer.wrap(read(fd, length)));
611    }
612
613    /**
614     * <p>Reads all available bytes from the serial port/device into a provided Writer.</p>
615     *
616     * @param fd
617     *          The file descriptor of the serial port/device.
618     * @param charset
619     *          The character set to use for encoding/decoding bytes to/from text characters
620     * @param writer
621     *          The Writer object to write to.
622     *
623     */
624    public synchronized static void read(int fd, Charset charset, Writer writer) throws IOException{
625        writer.write(read(fd, charset).toString());
626    }
627
628    /**
629     * <p>Reads a length bytes from the serial port/device into a provided Writer.</p>
630     *
631     * @param fd
632     *          The file descriptor of the serial port/device.
633     * @param length
634     *          The number of bytes to get from the serial port/device.
635     *          This number must not be higher than the number of available bytes.
636     * @param charset
637     *          The character set to use for encoding/decoding bytes to/from text characters
638     * @param writer
639     *          The Writer object to write to.
640     *
641     */
642    public synchronized static void read(int fd, int length, Charset charset, Writer writer) throws IOException{
643        writer.write(read(fd, length, charset).toString());
644    }
645
646
647    // ----------------------------------------
648    // WRITE OPERATIONS
649    // ----------------------------------------
650
651    /**
652     * <p>Sends an array of bytes to the serial port/device identified by the given file descriptor.</p>
653     *
654     *
655     * @param fd
656     *            The file descriptor of the serial port/device.
657     * @param data
658     *            A ByteBuffer of data to be transmitted.
659     * @param length
660     *            The number of bytes from the byte array to transmit to the serial port.
661     */
662    private synchronized static native void write(int fd, byte[] data, long length) throws IOException;
663
664    /**
665     * <p>Sends an array of bytes to the serial port/device identified by the given file descriptor.</p>
666     *
667     * @param fd
668     *            The file descriptor of the serial port/device.
669     * @param data
670     *            A ByteBuffer of data to be transmitted.
671     * @param offset
672     *            The starting index (inclusive) in the array to send from.
673     * @param length
674     *            The number of bytes from the byte array to transmit to the serial port.
675     */
676    public synchronized static void write(int fd, byte[] data, int offset, int length) throws IOException {
677
678        // we make a copy of the data argument because we don't want to modify the original source data
679        byte[] buffer = new byte[length];
680        System.arraycopy(data, offset, buffer, 0, length);
681
682        // write the buffer contents to the serial port via JNI native method
683        write(fd, buffer, length);
684    }
685
686    /**
687     * <p>Sends one of more bytes to the serial device identified by the given file descriptor.</p>
688     *
689     * @param fd
690     *            The file descriptor of the serial port/device.
691     * @param data
692     *            One or more bytes (or an array) of data to be transmitted. (variable-length-argument)
693     */
694    public synchronized static void write(int fd, byte ... data) throws IOException {
695
696        // write the data contents to the serial port via JNI native method
697        write(fd, data, data.length);
698    }
699
700    /**
701     * <p>Sends one of more bytes arrays to the serial device identified by the given file descriptor.</p>
702     *
703     * @param fd
704     *            The file descriptor of the serial port/device.
705     * @param data
706     *            One or more byte arrays of data to be transmitted. (variable-length-argument)
707     */
708    public synchronized static void write(int fd, byte[] ... data) throws IOException {
709        for(byte[] single : data) {
710            // write the data contents to the serial port via JNI native method
711            write(fd, single, single.length);
712        }
713    }
714
715    /**
716     * Read the content of byte buffer and write the data to the serial port transmit buffer.
717     * (The buffer is read from the current position up to the 'limit' value, not the 'capacity'.  You may need to
718     * rewind() or flip() the byte buffer if you have just written to it.)
719     *
720     * @param fd
721     *            The file descriptor of the serial port/device.
722     * @param data
723     *            A ByteBuffer of data to be transmitted.
724     */
725    public synchronized static void write(int fd, ByteBuffer ... data) throws IOException{
726
727        // write each byte buffer to the serial port
728        for(ByteBuffer single : data) {
729
730            // read the byte buffer from the current position up to the limit
731            byte[] payload = new byte[single.remaining()];
732            single.get(payload);
733
734            // write the data contents to the serial port via JNI native method
735            write(fd, payload, payload.length);
736        }
737    }
738
739    /**
740     * Read content from an input stream of data and write it to the serial port transmit buffer.
741     *
742     * @param fd
743     *          The file descriptor of the serial port/device.
744     * @param input
745     *          An InputStream of data to be transmitted
746     */
747    public synchronized static void write(int fd, InputStream input) throws IOException {
748
749        // ensure bytes are available
750        if(input.available() <= 0){
751            throw new IOException("No available bytes in input stream to write to serial port.");
752        }
753
754        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
755        int length;
756        byte[] data = new byte[1024];
757        while ((length = input.read(data, 0, data.length)) != -1) {
758            buffer.write(data, 0, length);
759        }
760        buffer.flush();
761
762        // write bytes to serial port
763        write(fd, buffer.toByteArray(), buffer.size());
764    }
765
766    /**
767     * <p>Sends an array of characters to the serial port/device identified by the given file descriptor.</p>
768     *
769     * @param fd
770     *           The file descriptor of the serial port/device.
771     * @param charset
772     *           The character set to use for encoding/decoding bytes to/from text characters
773     * @param data
774     *           An array of chars to be decoded into bytes and transmitted.
775     * @param offset
776     *           The starting index (inclusive) in the array to send from.
777     * @param length
778     *           The number of characters from the char array to transmit to the serial port.
779     */
780    public synchronized static void write(int fd, Charset charset, char[] data, int offset, int length) throws IOException {
781
782        // write the buffer contents to the serial port via JNI native method
783        write(fd, charset, CharBuffer.wrap(data, offset, length));
784    }
785
786    /**
787     * <p>Sends an array of characters to the serial port/device identified by the given file descriptor.</p>
788     *
789     * @param fd
790     *           The file descriptor of the serial port/device.
791     * @param charset
792     *           The character set to use for encoding/decoding bytes to/from text characters
793     * @param data
794     *           One or more characters (or an array) of data to be transmitted. (variable-length-argument)
795     */
796    public synchronized static void write(int fd, Charset charset, char ... data) throws IOException {
797
798        // write the buffer contents to the serial port via JNI native method
799        write(fd, charset, CharBuffer.wrap(data));
800    }
801
802    /**
803     * <p>Sends an array of ASCII characters to the serial port/device identified by the given file descriptor.</p>
804     *
805     * @param fd
806     *           The file descriptor of the serial port/device.
807     * @param data
808     *           One or more ASCII characters (or an array) of data to be transmitted. (variable-length-argument)
809     */
810    public synchronized static void write(int fd, char ... data) throws IOException {
811
812        // write the buffer contents to the serial port via JNI native method
813        write(fd, StandardCharsets.US_ASCII, CharBuffer.wrap(data));
814    }
815
816    /**
817     * <p>Sends one or more CharBuffers to the serial port/device identified by the given file descriptor.</p>
818     *
819     * @param fd
820     *           The file descriptor of the serial port/device.
821     * @param charset
822     *           The character set to use for encoding/decoding bytes to/from text characters
823     * @param data
824     *           One or more CharBuffers (or an array) of data to be transmitted. (variable-length-argument)
825     */
826    public synchronized static void write(int fd, Charset charset, CharBuffer ... data) throws IllegalStateException, IOException {
827        for(CharBuffer single : data) {
828            write(fd, charset.encode(single));
829        }
830    }
831
832    /**
833     * <p>Sends one or more ASCII CharBuffers to the serial port/device identified by the given file descriptor.</p>
834     *
835     * @param fd
836     *           The file descriptor of the serial port/device.
837     * @param data
838     *           One or more ASCII CharBuffers (or an array) of data to be transmitted. (variable-length-argument)
839     */
840    public synchronized static void write(int fd, CharBuffer ... data) throws IllegalStateException, IOException {
841        write(fd, StandardCharsets.US_ASCII, data);
842    }
843
844    /**
845     * <p>Sends one or more string objects to the serial port/device identified by the given file descriptor.</p>
846     *
847     * @param fd
848     *           The file descriptor of the serial port/device.
849     * @param charset
850     *           The character set to use for encoding/decoding bytes to/from text characters
851     * @param data
852     *           One or more string objects (or an array) of data to be transmitted. (variable-length-argument)
853     */
854    public synchronized static void write(int fd, Charset charset, CharSequence ... data) throws IllegalStateException, IOException {
855        for(CharSequence single : data) {
856            write(fd, charset.encode(CharBuffer.wrap(single)));
857        }
858    }
859
860    /**
861     * <p>Sends one or more ASCII string objects to the serial port/device identified by the given file descriptor.</p>
862     *
863     * @param fd
864     *           The file descriptor of the serial port/device.
865     * @param data
866     *           One or more ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
867     */
868    public synchronized static void write(int fd, CharSequence ... data) throws IllegalStateException, IOException {
869        write(fd, StandardCharsets.US_ASCII, data);
870    }
871
872
873    /**
874     * <p>Sends a collection of string objects to the serial port/device identified by the given file descriptor.</p>
875     *
876     * @param fd
877     *           The file descriptor of the serial port/device.
878     * @param charset
879     *           The character set to use for encoding/decoding bytes to/from text characters
880     * @param data
881     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
882     */
883    public synchronized static void write(int fd, Charset charset, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
884        for(CharSequence single : data) {
885            write(fd, charset.encode(CharBuffer.wrap(single)));
886        }
887    }
888
889    /**
890     * <p>Sends a collection of ASCII string objects to the serial port/device identified by the given file descriptor.</p>
891     *
892     * @param fd
893     *           The file descriptor of the serial port/device.
894     * @param data
895     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
896     */
897    public synchronized static void write(int fd, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
898        write(fd, StandardCharsets.US_ASCII, data);
899    }
900
901
902    /**
903     * <p>Sends one or more string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
904     *
905     * @param fd
906     *           The file descriptor of the serial port/device.
907     * @param charset
908     *           The character set to use for encoding/decoding bytes to/from text characters
909     * @param data
910     *           One or more string objects (or an array) of data to be transmitted. (variable-length-argument)
911     */
912    public synchronized static void writeln(int fd, Charset charset, CharSequence ... data) throws IllegalStateException, IOException {
913        for(CharSequence single : data) {
914            write(fd, charset.encode(CharBuffer.wrap(single + "\r\n")));
915        }
916    }
917
918    /**
919     * <p>Sends one or more ASCII string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
920     *
921     * @param fd
922     *           The file descriptor of the serial port/device.
923     * @param data
924     *           One or more ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
925     */
926    public synchronized static void writeln(int fd, CharSequence ... data) throws IllegalStateException, IOException {
927        writeln(fd, StandardCharsets.US_ASCII, data);
928    }
929
930    /**
931     * <p>Sends a collection of string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
932     *
933     * @param fd
934     *           The file descriptor of the serial port/device.
935     * @param charset
936     *           The character set to use for encoding/decoding bytes to/from text characters
937     * @param data
938     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
939     */
940    public synchronized static void writeln(int fd, Charset charset, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
941        for(CharSequence single : data) {
942            write(fd, charset.encode(CharBuffer.wrap(single + "\r\n")));
943        }
944    }
945
946    /**
947     * <p>Sends a collection of ASCII string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
948     *
949     * @param fd
950     *           The file descriptor of the serial port/device.
951     * @param data
952     *           A collection of ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
953     */
954    public synchronized static void writeln(int fd, Collection<? extends CharSequence> data) throws IllegalStateException, IOException {
955        writeln(fd, StandardCharsets.US_ASCII, data);
956    }
957
958}