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

com.oracle.dio.uart.impl.UARTImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2012, 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 com.oracle.dio.uart.impl;

import java.io.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.Buffer;
import java.security.AccessControlException;
import java.security.AccessController;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import com.oracle.dio.impl.EventQueueManager;
import com.oracle.dio.power.impl.PowerManagedBase;
import com.oracle.dio.utils.Configuration;
import com.oracle.dio.utils.Constants;
import com.oracle.dio.utils.ExceptionMessage;
import com.oracle.dio.utils.Logging;
import com.oracle.dio.utils.PrivilegeController;
import com.oracle.dio.utils.PrivilegedAction;

import jdk.dio.*;
import jdk.dio.uart.*;
import jdk.dio.uart.UART;
import jdk.dio.uart.UARTConfig;
import jdk.dio.uart.UARTConfig.Builder;
import jdk.dio.uart.UARTEvent;
import jdk.dio.uart.UARTEventListener;
import jdk.dio.uart.UARTPermission;

import romizer.*;

class UARTImpl extends PowerManagedBase implements UART {
    private boolean isWriting;

    private final Object synchReadLock = new Object();
    private final Object synchWriteLock = new Object();

    private final Queue writeBuffers = new LinkedList();
    private final Queue readBuffers = new LinkedList();

    private InputRoundListener inRoundListener;
    private OutputRoundListener outRoundListener;

    private Hashtable eventListeners;

    private int receiveTriggerLevel;
    private int inputTimeout = Integer.MAX_VALUE;//timeout is disabled


    UARTImpl(DeviceDescriptor dscr, int mode)
                                throws DeviceNotFoundException, InvalidDeviceConfigException, UnsupportedAccessModeException{
        super(dscr, mode);

        byte[] devName; // UTF-8 device name
        //deviceName = uart device prefix + device number
        String deviceName = getSecurityName();
        // in case of such device absence we try to check permission for all devices
        // because non-existing device belongs to all devices set
        UARTPermission permission = new UARTPermission(null != deviceName ? deviceName : "*");
        AccessController.checkPermission(permission);

        if (deviceName == null){
            throw new DeviceNotFoundException(
                ExceptionMessage.format(ExceptionMessage.UART_CANT_GET_PORT_NAME)
            );
        }

        if( mode != DeviceManager.EXCLUSIVE){
            throw new UnsupportedAccessModeException();
        }

        UARTConfig cfg = dscr.getConfiguration();

        try{
            devName = deviceName.getBytes("UTF-8");
        } catch (UnsupportedEncodingException ex) {
            throw new DeviceNotFoundException(
                ExceptionMessage.format(ExceptionMessage.UART_UTF8_UNCONVERTIBLE_DEVNAME)
            );
        }

        openUARTByConfig0(devName, cfg.getBaudRate(), cfg.getStopBits(), cfg.getFlowControlMode(),
                                   cfg.getDataBits(), cfg.getParity(), mode == DeviceManager.EXCLUSIVE);

        isWriting = false;
        eventListeners = new Hashtable();
        initPowerManagement();

        // this is quick update to support RS485 on Linux
        UARTOptionsHandler.processOptions(this, dscr.getProperties());
    }

    private class InternalRoundListener implements  InputRoundListener {

            private final int toRead;

            private InternalRoundListener(int toRead) {
                this.toRead = toRead;
            }

            private void stop() {
                synchronized (synchReadLock) {
                    try {
                        stopReading(true);
                    } catch (IOException e) {
                        // intentionally ignored
                    }
                    synchReadLock.notifyAll();
                }
            }

            @Override
            public void inputRoundCompleted(RoundCompletionEvent event) {
                if (event.getNumber() >= toRead || !event.getBuffer().hasRemaining()) {
                    stop();
                }
            }

            @Override
            public void failed(Throwable ex, UART arg1) {
                stop();
            }
    }


    private boolean isAlphaNumerical(char ch) {
        if ((('a' <= ch && ch <= 'z') ||
             ('A' <= ch && ch <= 'Z') ||
             ('0' <= ch && ch <= '9'))) {
            return true;
        }
        return false;
    }

    private String getSecurityName() {
        UARTConfig cfg = dscr.getConfiguration();
        int devNum = cfg.getControllerNumber();
        String securityName = null;

        if (null != cfg.getControllerName()) {
            securityName = cfg.getControllerName();
            for (int i = 0; i < securityName.length(); i++) {
                if(!isAlphaNumerical(securityName.charAt(i))) {
                    // for security reason to prohibit usage of "../"
                    // and to align with MEEP spec
                    Logging.reportError("Unacceptable device name:", securityName);
                    return null;
                }
            }

        } else {
            if (devNum == DeviceConfig.DEFAULT) {
                devNum = 0;
            }

            // first port in list is DEFAULT port
            try {
                String ports = Configuration.getProperty("microedition.commports");
                if (null != ports) {
                    StringTokenizer t = new StringTokenizer(ports, ",");
                    while(devNum-- > 0 && t.hasMoreTokens()) {
                        t.nextToken();
                    }
                    // if no more tokens - returns null
                    if (t.hasMoreTokens()) {
                        securityName = t.nextToken();
                    }
                }
            } catch (AccessControlException  e) {
                // SE app must not be aware about ME property
            }

        }

        return securityName;
    }

    protected void checkPowerPermission(){
        AccessController.checkPermission(new UARTPermission(getSecurityName(), DevicePermission.POWER_MANAGE));
    }


    private int totalBytesRead;
    @Override
    protected void processNativeEvent(int event, int... data) {
        {
            UARTEventListener listener = eventListeners.get(event);
            if (listener != null){
                try{
                    UARTEvent uartEvent = new UARTEvent(this, event);
                    listener.eventDispatched(uartEvent);
                } catch(Throwable e){
                    //do nothing
                }
            }
        }

        switch(event){
        case UARTEvent.INPUT_DATA_AVAILABLE:
            {
                final InputRoundListener listener = inRoundListener;
                if (listener != null){
                    ByteBuffer buffer = readBuffers.peek();
                    if (null == buffer) {
                        Logging.reportError("[UART] No buffer is ready for read operation");
                        return;
                    }
                    /*
                        read0 is designed to copy available data from the javacall buffer to java buffer,
                        because of that no slice() call is necessary, the following is redundand:

                        int bytesReaden = read0(buffer.slice());

                    */

                    final int bytesRead = read0(buffer);
                    totalBytesRead += bytesRead;
                    shiftBufferPosition(buffer, buffer.position() + bytesRead);

                    final boolean syncRead = (listener instanceof InternalRoundListener);
                    if(!buffer.hasRemaining() || syncRead){

                        RoundCompletionEvent rcEvent =
                            new RoundCompletionEvent(this, buffer, totalBytesRead);

                        //notify user
                        try{
                            listener.inputRoundCompleted(rcEvent);
                        }catch(Exception e){
                            //do nothing, listener should not throw an exception
                            Logging.reportWarning(e.toString());
                        }

                        // sync read operates single buffer -> no need to rearrange the queue or reset total read counter
                        // sync read alsways stops if buffer is full -> no need to resend notification
                        if (!syncRead) {
                            totalBytesRead = 0;
                            // if not stopped
                            if (inRoundListener != null) {
                                // next time use another buffer.
                                // stopRead() cleans readBuffers therefore .read() is moved here
                                readBuffers.remove();
                                if (buffer.hasRemaining()) {
                                    readBuffers.add(buffer);
                                } else {
                                    // post notification
                                    rcEvent = new RoundCompletionEvent(this, buffer, 0);
                                    EventQueueManager.getInstance().postEvent(this, UARTEvent.INPUT_DATA_AVAILABLE, rcEvent);
                                }
                            }
                        }
                    }
                }
            }
            break;
        case UARTEvent.OUTPUT_BUFFER_EMPTY:
            {
                final int bytesProcessed = data[0];
                final OutputRoundListener listener = outRoundListener;
                if (listener != null){
                    ByteBuffer buffer = writeBuffers.poll();
                    if (null == buffer) {
                        Logging.reportError("[UART] No buffer is ready for write operation");
                        return;
                    }
                    // this event is sent if buffer is empty only
                    shiftBufferPosition(buffer, buffer.limit());
                    RoundCompletionEvent rcEvent = new RoundCompletionEvent(this, buffer, bytesProcessed);

                    //notify user
                    try{
                        listener.outputRoundCompleted(rcEvent);
                    }catch(Exception e){
                        //do nothing, listener should not throw an exception
                        Logging.reportWarning(e.toString());
                    }
                    if(isWriting){
                        if (buffer.hasRemaining()) {
                            writeBuffers.add(buffer);
                        } else {
                            // post notification
                            rcEvent = new RoundCompletionEvent(this, buffer, 0);
                            EventQueueManager.getInstance().postEvent(this, UARTEvent.OUTPUT_BUFFER_EMPTY, rcEvent);
                        }
                        buffer = writeBuffers.peek();
                        if (null != buffer){
                            writeAsynch0(buffer);
                        }
                    }
                }//if (outRoundListener != null)
            }
            break;
        }//switch(event)
    }

    @Override
    protected void processDeviceEvent(int eventType, DeviceEvent event) {
        if (eventType == UARTEvent.OUTPUT_BUFFER_EMPTY) {
            final OutputRoundListener listener = outRoundListener;
            if (listener != null) {
                //notify user
                try{
                    listener.outputRoundCompleted((RoundCompletionEvent)event);
                }catch(Exception e){
                    //do nothing, listener should not throw an exception
                    Logging.reportWarning(e.toString());
                }
                if (isWriting) {
                    final ByteBuffer buffer = ((RoundCompletionEvent)event).getBuffer();
                    if (buffer.hasRemaining()) {
                        // if no write process is ongoing
                        if (writeBuffers.peek() == null) {
                            writeAsynch0(buffer);
                        }
                        // no sync is required since event processing is single thread operation
                        writeBuffers.add(buffer);
                    } else {
                        // send again
                        EventQueueManager.getInstance().postEvent(this, UARTEvent.OUTPUT_BUFFER_EMPTY, event);
                    }
                }
            }
        } else if (eventType == UARTEvent.INPUT_DATA_AVAILABLE) {
            final InputRoundListener listener = inRoundListener;
            if (listener != null) {
                //notify user
                try{
                    listener.inputRoundCompleted((RoundCompletionEvent)event);
                }catch(Exception e){
                    //do nothing, listener should not throw an exception
                    Logging.reportWarning(e.toString());
                }
                // if not stopped
                if (inRoundListener != null) {
                    final ByteBuffer buffer = ((RoundCompletionEvent)event).getBuffer();
                    if (buffer.hasRemaining()) {
                        final ByteBuffer tmp = readBuffers.peek();
                        readBuffers.add(buffer);
                        if (tmp == null) {
                            // by contract next INPUT_DATA_AVAILABLE is suppressed until read0->javacall_uart_read is called.
                            // if previous InputRoundListener doesn't clear provided buffer we may get into situation when
                            // processNativeEvent->readBuffer.peek() returns null and javacall flag is not cleared by read0.
                            // to continue receviving we need to read cached data and clear javacall flags
                            processNativeEvent(UARTEvent.INPUT_DATA_AVAILABLE, 0);
                        }
                    } else {
                        // send again
                        EventQueueManager.getInstance().postEvent(this, UARTEvent.INPUT_DATA_AVAILABLE, event);
                    }
                }
            }
        } else {
            Logging.reportError("UART.processDeviceEvent: unknown event " + eventType);
        }
    }



    /**
     * Gets the current baud rate. If the baud rate was not set previously using {@link #setBaudRate(int)} the
     * peripheral configuration-specific default value is returned.
     *
     * @return the current baud rate.
     */
    @Override
    public synchronized int getBaudRate() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        return getBaudRate0();

    }

    /**
     * Gets the current number of bits per character.
     *
     */
    @Override
    public synchronized int getDataBits() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        return getDataBits0();
    }

    @Override
    public synchronized int getFlowControlMode() throws IOException, UnavailableDeviceException, ClosedDeviceException {
        return getFlowControlMode0();
    }

    /**
     * Gets the current parity.
     *
     */
    @Override
    public synchronized int getParity() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        return getParity0();
    }

    /**
     * Gets the current number of stop bits per character.
     *
     */
    @Override
    public synchronized int getStopBits() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        return getStopBits0();
    }

    /**
     * Sets the baud rate.
     *
     */
    @Override
    public synchronized void setBaudRate(int baudRate) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        new UARTConfig.Builder().setBaudRate(baudRate);
        setBaudRate0( baudRate);
    }

    /**
     * Sets the number of bits per character.
     *
     */
    @Override
    public synchronized void setDataBits(int dataBits) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        new UARTConfig.Builder().setDataBits(dataBits);
        setDataBits0( dataBits);
    }

    /**
     * Registers a {@link UARTEventListener} instance to monitor input data availability, input buffer overrun or
     * empty output buffer conditions. While the listener can be triggered by hardware interrupts, there are no
     * real-time guarantees of when the listener will be called.
     */
    @Override
    public synchronized void setEventListener(int eventId, UARTEventListener listener) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkOpen();

        if (eventId != UARTEvent.INPUT_BUFFER_OVERRUN && eventId != UARTEvent.INPUT_DATA_AVAILABLE &&
            eventId != UARTEvent.OUTPUT_BUFFER_EMPTY && eventId != UARTEvent.BREAK_INTERRUPT &&
            eventId != UARTEvent.PARITY_ERROR &&eventId != UARTEvent.FRAMING_ERROR){
                throw new IllegalArgumentException();
        }
        UARTEventListener registeredListener = eventListeners.get(eventId);

        if (listener != null && registeredListener != null){
            //got listener for the eventId
            throw new IllegalStateException();
        }

        if (listener == null){
            //remove listener for the eventId
             eventListeners.remove(eventId);
             unsubscribe(eventId);
             // remove handlers
        }else{
             eventListeners.put(eventId, listener);
             subscribe(eventId);
        }
    }

    private void subscribe(int eventId){
        EventQueueManager.getInstance().setEventListener(UART.class, eventId, this);
        setEventListener0(eventId);
    }

    private void unsubscribe(int eventId){
        /*
         * 2 listeners work withINPUT_DATA_AVAILABLE :
         * user defined + internal for filling buffers
         */
        if(eventId == UARTEvent.INPUT_DATA_AVAILABLE){
            if(inRoundListener != null || eventListeners.get(eventId) != null){
                return;
            }
        }

        EventQueueManager.getInstance().removeEventListener(UART.class, eventId, this);
        removeEventListener0(eventId);
    }

    @Override
    public synchronized void setFlowControlMode(int flowcontrol) throws IOException, UnavailableDeviceException, ClosedDeviceException {
        checkPowerState();
        new UARTConfig.Builder().setFlowControlMode(flowcontrol);
        setFlowControlMode0(flowcontrol);
    }

    /**
     * Sets the parity.
     */
    @Override
    public synchronized void setParity(int parity) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        new UARTConfig.Builder().setParity(parity);
        setParity0(parity);
    }

    /**
     * Sets the number of stop bits per character.
     *
     */
    @Override
    public synchronized void setStopBits(int stopBits) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        new UARTConfig.Builder().setStopBits(stopBits);
        setStopBits0(stopBits);
    }

    /**
     * Starts asynchronous writing in sucessive rounds - initially writing the data remaining in the provided
     * buffer. Additional rounds are asynchronously fetched by notifying the provided {@link OutputRoundListener}
     * instance once the initial data have been written. The initial data to be written
     * is retrieved from the provided buffer; the data to write during the subsequent rounds is retrieved
     * from that very same buffer upon invocation od the provided {@link OutputRoundListener} instance.
     */
    @Override
    public void startWriting(ByteBuffer src, OutputRoundListener listener) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkBuffer(src);
        Objects.requireNonNull(listener, ExceptionMessage.format(ExceptionMessage.NULL_LISTENER));

        writeAsync(src, null, listener);
    }

    /**
     * Starts asynchronous writing in successive rounds.
     */
    @Override
    public void startWriting(ByteBuffer src1, ByteBuffer src2, OutputRoundListener listener) throws IOException,
        UnavailableDeviceException, ClosedDeviceException{

        checkBuffer(src1);
        checkBuffer(src2);
        Objects.requireNonNull(listener, ExceptionMessage.format(ExceptionMessage.NULL_LISTENER));

        writeAsync(src1, src2, listener);
    }

    private void writeAsync(ByteBuffer src1, ByteBuffer src2, OutputRoundListener listener) throws IOException,
        UnavailableDeviceException, ClosedDeviceException {
        checkPowerState();
        synchronized(synchWriteLock) {
            checkWrite();

            writeBuffers.add(src1);
            if (null != src2) {
                writeBuffers.add(src2);
            }

            outRoundListener = listener;
            subscribe(UARTEvent.OUTPUT_BUFFER_EMPTY);
            writeAsynch0(src1);
            isWriting = true;
        }
    }

    /**
     * Stops (cancels) the currently active writing session.
     */
    @Override
    public void stopWriting() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkOpen();
        synchronized(synchWriteLock) {
            if (isWriting){
                writeBuffers.clear();
                outRoundListener = null;
                unsubscribe(UARTEvent.OUTPUT_BUFFER_EMPTY);
                stopWriting0();
                isWriting = false;
            }
        }
    }

    /**
     * Starts asynchronous reading in sucessive rounds - reading data into the provided
     * buffer.
     */
    @Override
    public void startReading(ByteBuffer src, InputRoundListener listener) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkBuffer(src);
        Objects.requireNonNull(listener, ExceptionMessage.format(ExceptionMessage.NULL_LISTENER));
        readAsync(src, null, listener);
    }

    /**
     * Starts asynchronous reading in sucessive rounds.
     */
    @Override
    public void startReading(ByteBuffer src1, ByteBuffer src2, InputRoundListener listener) throws IOException,
            UnavailableDeviceException, ClosedDeviceException{
        checkBuffer(src1);
        checkBuffer(src2);
        Objects.requireNonNull(listener, ExceptionMessage.format(ExceptionMessage.NULL_LISTENER));
        readAsync(src1, src2, listener);
    }

    private void readAsync(ByteBuffer src1, ByteBuffer src2, InputRoundListener listener)  throws IOException,
            UnavailableDeviceException, ClosedDeviceException {
        checkPowerState();
        synchronized(synchReadLock){
            checkRead();
            totalBytesRead = 0;
            inRoundListener = listener;
            readBuffers.add(src1);
            if (null != src2) {
                readBuffers.add(src2);
            }

            /*
                subscribe calls set_event_listener, in case of INPUT_DATA_AVAILABLE
                the native function checks if data available in the internal
                buffer and generates INPUT_DATA_AVAILABLE event if so.
            */
            subscribe(UARTEvent.INPUT_DATA_AVAILABLE);
        }
    }


    /* stop operation of required type only, e.g. public stopReading() doesn't affect read() */
    private void stopReading(boolean syncVer) throws IOException, UnavailableDeviceException, ClosedDeviceException {
        checkOpen();
        synchronized(synchReadLock) {
            if (null != inRoundListener && syncVer == (inRoundListener instanceof InternalRoundListener) ) {
                readBuffers.clear();
                inRoundListener = null;
                unsubscribe(UARTEvent.INPUT_DATA_AVAILABLE);
                // redundant function, remove later
                stopReading0();
                synchReadLock.notifyAll();
            }
        }
    }

    /**
     * Stops (cancels) the currently active reading session.
      */
    @Override
    public void stopReading() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        stopReading(false);
    }

    /**
     * Generates a break condition for the specified duration.
     */
    @Override
    public synchronized void generateBreak(int duration) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        if(0 > duration){
            throw new IllegalArgumentException(String.valueOf(duration));
        }
        checkPowerState();
        generateBreak0(duration);
    }

    /**
     * Sets the receive trigger level
     */
    @Override
    public synchronized void setReceiveTriggerLevel(int level) throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        if(level < 0){
            throw new IllegalArgumentException();
        }
        receiveTriggerLevel = level;
    }

    /**
     * Gets the current receive trigger level.
     *
     */
    @Override
    public synchronized int getReceiveTriggerLevel() throws IOException, UnavailableDeviceException, ClosedDeviceException{
        checkPowerState();
        return receiveTriggerLevel;
    }

    /**
     * Reads a sequence of bytes from this UART into the given buffer.
     */
    @Override
    public int read(ByteBuffer dst) throws IOException,
            UnavailableDeviceException, ClosedDeviceException{
        int ret;

        if(!dst.hasRemaining()){
            ret = 0;
        }else{
            ret = dst.position();
            synchronized(synchReadLock){

                checkRead();

                /*read all data available*/
                int readRes = read0(dst);
                shiftBufferPosition(dst, ret + readRes);
                if ((0 == receiveTriggerLevel || readRes < receiveTriggerLevel) && dst.hasRemaining()) {
                    if (!EventQueueManager.getInstance().isDispatchThread() && inputTimeout > 0) {
                        /*
                         * the user calls read() from the event callback, or inputTimeout is 0
                         * exit immediatelly,
                         * else read with timeout
                         */
                        startReading(dst, new InternalRoundListener((0 != receiveTriggerLevel) ? receiveTriggerLevel - readRes : dst.remaining()));
                            try{
                                if(inputTimeout == Integer.MAX_VALUE){
                                    //timeout disabled, wait forever or till the buffer is fullfilled
                                    synchReadLock.wait();
                                }else if (inputTimeout > 0) {
                                    synchReadLock.wait(inputTimeout);
                                }
                            }catch(InterruptedException iE){
                                throw new IOException();
                            } finally {
                                stopReading(true);
                            }
                    }
                } // if !event thread
            } // synch
            ret = dst.position() - ret;
        } // if has Remaining

        return ret;
    }

    /**
     * Writes a sequence of bytes to this UART from the given buffer.
     */
    @Override
    public int write(ByteBuffer src) throws IOException,
            UnavailableDeviceException, ClosedDeviceException{

        checkPowerState();

        int ret = 0;

        synchronized(synchWriteLock) {
            checkWrite();
            isWriting = true;
        }

        try {
            /*
             * synchronous write0 returns number of written bytes
             * slice is needed to avoid memory corruption because src buffer modification
             * might happen during write0
             */
            ret = write0(src.slice());
            shiftBufferPosition(src, src.position() + ret);
        } finally {
            isWriting = false;
        }
        return ret;
    }

    @Override
    public void close() throws IOException{
        if (isOpen()) {
            stopWriting();
            // stops EVERY read thread
            stopReading((inRoundListener instanceof InternalRoundListener));
            super.close();
        }
    }

    @Override
    public synchronized int getReceiveTimeout() throws IOException, UnavailableDeviceException, ClosedDeviceException {
        checkPowerState();
        return inputTimeout;
    }

    @Override
    public synchronized void setReceiveTimeout(int timeout) throws IOException, UnavailableDeviceException, ClosedDeviceException {
        checkPowerState();
        if(timeout < 0 ){
            throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.UART_NEGATIVE_TIMEOUT));
        }
        inputTimeout = timeout;
    }


    private void checkRead(){
        if (inRoundListener != null){
            throw new IllegalStateException(
                ExceptionMessage.format(ExceptionMessage.UART_ACTIVE_READ_OPERATION)
            );
        }
    }

    private void checkWrite(){
        if (isWriting){
            throw new IllegalStateException(
                ExceptionMessage.format(ExceptionMessage.UART_ACTIVE_WRITE_OPERATION)
            );
        }
    }


    protected synchronized int getGrpID() {
        return getUartId0();
    }

    @Override
    public synchronized ByteBuffer getInputBuffer() throws ClosedDeviceException,
            IOException {
        throw new java.lang.UnsupportedOperationException();
    }

    @Override
    public synchronized ByteBuffer getOutputBuffer() throws ClosedDeviceException,
            IOException {
        throw new java.lang.UnsupportedOperationException();
    }

    @Override
    public ByteBuffer prepareBuffer(ByteBuffer buffer, int size) throws IOException, ClosedDeviceException {
        return (ByteBuffer)super.prepareBufferInt(buffer,size);
    }


    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void removeEventListener0(int eventId);
    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void setEventListener0(int eventId);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.unlock_func_ptr",
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.Handle.lock_func_ptr",
        "com.oracle.dio.impl.Handle.close_func_ptr",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void openUARTByConfig0(byte[] devName, int baudrate, int stopBits, int flowControl, int bitsPerChar, int parity, boolean exclusive);
    /*
     * write0 does not shift the buffer's position, it only returns bytes wrote, in case of asynch operation it must return 0.
     */
    @Local(DontRemoveFields = {
        "java.nio.Buffer.position",
        "java.nio.Buffer.limit",
        "java.nio.Buffer.data",
        "java.nio.Buffer.arrayOffset",
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int write0(ByteBuffer src);

    /*
     * starts asynch write session
     */
    @Local(DontRemoveFields = {
        "java.nio.Buffer.position",
        "java.nio.Buffer.limit",
        "java.nio.Buffer.data",
        "java.nio.Buffer.arrayOffset",
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void writeAsynch0(ByteBuffer src);
    /*
     * read0 does not shift the buffer's position, it only returns bytes read.
     */
    @Local(DontRemoveFields = {
        "java.nio.Buffer.position",
        "java.nio.Buffer.limit",
        "java.nio.Buffer.data",
        "java.nio.Buffer.arrayOffset",
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int read0(ByteBuffer src);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getBaudRate0();
    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void setBaudRate0(int baudRate);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getDataBits0();
    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void setDataBits0(int dataBits);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getParity0();
    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int setParity0(int parity);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getStopBits0();
    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int setStopBits0(int stopBits);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void stopWriting0();
    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void stopReading0();

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getUartId0();

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int setFlowControlMode0(int flowcontrol);

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getFlowControlMode0();

    @Local(DontRemoveFields = {
        "com.oracle.dio.impl.Handle.native_handle",
        "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int generateBreak0(int duration);

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy