001package com.pi4j.io.serial.impl;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  AbstractSerialDataWriter.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.io.serial.SerialDataWriter;
033
034import java.io.ByteArrayOutputStream;
035import java.io.IOException;
036import java.io.InputStream;
037import java.nio.ByteBuffer;
038import java.nio.CharBuffer;
039import java.nio.charset.Charset;
040import java.nio.charset.StandardCharsets;
041import java.util.Collection;
042
043public abstract class AbstractSerialDataWriter implements SerialDataWriter {
044
045    // ----------------------------------------
046    // WRITE OPERATIONS
047    // ----------------------------------------
048
049    /**
050     * <p>Sends an array of bytes to the serial port/device identified by the given file descriptor.</p>
051     *
052     * @param data
053     *            A ByteBuffer of data to be transmitted.
054     * @param offset
055     *            The starting index (inclusive) in the array to send from.
056     * @param length
057     *            The number of bytes from the byte array to transmit to the serial port.
058     */
059    public abstract void write(byte[] data, int offset, int length) throws IllegalStateException, IOException;
060
061    /**
062     * <p>Sends one of more bytes to the serial device identified by the given file descriptor.</p>
063     *
064     * @param data
065     *            One or more bytes (or an array) of data to be transmitted. (variable-length-argument)
066     */
067    public void write(byte ... data) throws IllegalStateException, IOException{
068        write(data, 0, data.length);
069    }
070
071    /**
072     * <p>Sends one of more bytes arrays to the serial device identified by the given file descriptor.</p>
073     *
074     * @param data
075     *            One or more byte arrays of data to be transmitted. (variable-length-argument)
076     */
077    public void write(byte[] ... data) throws IllegalStateException, IOException{
078        for(byte[] single : data) {
079            write(single);
080        }
081    }
082
083    /**
084     * Read the content of byte buffer and write the data to the serial port transmit buffer.
085     * (The buffer is read from the current position up to the 'limit' value, not the 'capacity'.  You may need to
086     * rewind() or flip() the byte buffer if you have just written to it.)
087     *
088     * @param data
089     *            A ByteBuffer of data to be transmitted.
090     */
091    public void write(ByteBuffer... data) throws IllegalStateException, IOException{
092        // write each byte buffer to the serial port
093        for(ByteBuffer single : data) {
094
095            // read the byte buffer from the current position up to the limit
096            byte[] payload = new byte[single.remaining()];
097            single.get(payload);
098
099            write(payload);
100        }
101    }
102
103    /**
104     * Read content from an input stream of data and write it to the serial port transmit buffer.
105     *
106     * @param input
107     *          An InputStream of data to be transmitted
108     */
109    public void write(InputStream input) throws IllegalStateException, IOException{
110        // ensure bytes are available
111        if(input.available() <= 0){
112            throw new IOException("No available bytes in input stream to write to serial port.");
113        }
114
115        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
116        int length;
117        byte[] data = new byte[1024];
118        while ((length = input.read(data, 0, data.length)) != -1) {
119            buffer.write(data, 0, length);
120        }
121        buffer.flush();
122
123        write(buffer.toByteArray());
124    }
125
126    /**
127     * <p>Sends an array of characters to the serial port/device identified by the given file descriptor.</p>
128     *
129     * @param charset
130     *           The character set to use for encoding/decoding bytes to/from text characters
131     * @param data
132     *           An array of chars to be decoded into bytes and transmitted.
133     * @param offset
134     *           The starting index (inclusive) in the array to send from.
135     * @param length
136     *           The number of characters from the char array to transmit to the serial port.
137     */
138    public void write(Charset charset, char[] data, int offset, int length) throws IllegalStateException, IOException{
139        write(charset, CharBuffer.wrap(data, offset, length));
140    }
141
142    /**
143     * <p>Sends an array of characters to the serial port/device identified by the given file descriptor.</p>
144     *
145     * @param charset
146     *           The character set to use for encoding/decoding bytes to/from text characters
147     * @param data
148     *           One or more characters (or an array) of data to be transmitted. (variable-length-argument)
149     */
150    public void write(Charset charset, char ... data) throws IllegalStateException, IOException{
151        write(charset, CharBuffer.wrap(data));
152    }
153
154    /**
155     * <p>Sends an array of ASCII characters to the serial port/device identified by the given file descriptor.</p>
156     *
157     * @param data
158     *           One or more ASCII characters (or an array) of data to be transmitted. (variable-length-argument)
159     */
160    public void write(char ... data) throws IllegalStateException, IOException{
161        write(StandardCharsets.US_ASCII, CharBuffer.wrap(data));
162    }
163
164    /**
165     * <p>Sends one or more CharBuffers to the serial port/device identified by the given file descriptor.</p>
166     *
167     * @param charset
168     *           The character set to use for encoding/decoding bytes to/from text characters
169     * @param data
170     *           One or more CharBuffers (or an array) of data to be transmitted. (variable-length-argument)
171     */
172    public void write(Charset charset, CharBuffer... data) throws IllegalStateException, IOException{
173        for(CharBuffer single : data) {
174            write(charset.encode(single));
175        }
176    }
177
178    /**
179     * <p>Sends one or more ASCII CharBuffers to the serial port/device identified by the given file descriptor.</p>
180     *
181     * @param data
182     *           One or more ASCII CharBuffers (or an array) of data to be transmitted. (variable-length-argument)
183     */
184    public void write(CharBuffer ... data) throws IllegalStateException, IOException{
185        write(StandardCharsets.US_ASCII, data);
186    }
187
188    /**
189     * <p>Sends one or more string objects to the serial port/device identified by the given file descriptor.</p>
190     *
191     * @param charset
192     *           The character set to use for encoding/decoding bytes to/from text characters
193     * @param data
194     *           One or more string objects (or an array) of data to be transmitted. (variable-length-argument)
195     */
196    public void write(Charset charset, CharSequence ... data) throws IllegalStateException, IOException{
197        for(CharSequence single : data) {
198            write(charset.encode(CharBuffer.wrap(single)));
199        }
200    }
201
202    /**
203     * <p>Sends one or more ASCII string objects to the serial port/device identified by the given file descriptor.</p>
204     *
205     * @param data
206     *           One or more ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
207     */
208    public void write(CharSequence ... data) throws IllegalStateException, IOException{
209        write(StandardCharsets.US_ASCII, data);
210    }
211
212    /**
213     * <p>Sends a collection of string objects to the serial port/device identified by the given file descriptor.</p>
214     *
215     * @param charset
216     *           The character set to use for encoding/decoding bytes to/from text characters
217     * @param data
218     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
219     */
220    public void write(Charset charset, Collection<? extends CharSequence> data) throws IllegalStateException, IOException{
221        for(CharSequence single : data) {
222            write(charset.encode(CharBuffer.wrap(single)));
223        }
224    }
225
226    /**
227     * <p>Sends a collection of ASCII string objects to the serial port/device identified by the given file descriptor.</p>
228     *
229     * @param data
230     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
231     */
232    public void write(Collection<? extends CharSequence> data) throws IllegalStateException, IOException{
233        write(StandardCharsets.US_ASCII, data);
234    }
235
236    protected CharSequence appendNewLine(CharSequence data){
237        String separator = System.getProperty("line.separator");
238        return data + separator;
239    }
240
241    /**
242     * <p>Sends one or more string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
243     *
244     * @param charset
245     *           The character set to use for encoding/decoding bytes to/from text characters
246     * @param data
247     *           One or more string objects (or an array) of data to be transmitted. (variable-length-argument)
248     */
249    public void writeln(Charset charset, CharSequence ... data) throws IllegalStateException, IOException{
250        for(CharSequence single : data) {
251            write(charset.encode(CharBuffer.wrap(appendNewLine(single))));
252        }
253    }
254
255    /**
256     * <p>Sends one or more ASCII string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
257     *
258     * @param data
259     *           One or more ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
260     */
261    public void writeln(CharSequence ... data) throws IllegalStateException, IOException{
262        writeln(StandardCharsets.US_ASCII, data);
263    }
264
265    /**
266     * <p>Sends a collection of string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
267     *
268     * @param charset
269     *           The character set to use for encoding/decoding bytes to/from text characters
270     * @param data
271     *           A collection of string objects (or an array) of data to be transmitted. (variable-length-argument)
272     */
273    public void writeln(Charset charset, Collection<? extends CharSequence> data) throws IllegalStateException, IOException{
274        for(CharSequence single : data) {
275            write(charset.encode(CharBuffer.wrap(appendNewLine(single))));
276        }
277    }
278
279    /**
280     * <p>Sends a collection of ASCII string objects each appended with a line terminator (CR+LF) to the serial port/device.</p>
281     *
282     * @param data
283     *           A collection of ASCII string objects (or an array) of data to be transmitted. (variable-length-argument)
284     */
285    public void writeln(Collection<? extends CharSequence> data) throws IllegalStateException, IOException{
286        writeln(StandardCharsets.US_ASCII, data);
287    }
288
289}