001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.transport.serial;
021
022import gnu.io.CommPortIdentifier;
023import gnu.io.PortInUseException;
024import gnu.io.SerialPort;
025import gnu.io.UnsupportedCommOperationException;
026
027import java.io.IOException;
028import java.net.SocketAddress;
029import java.util.Enumeration;
030import java.util.TooManyListenersException;
031import java.util.concurrent.Executor;
032
033import org.apache.mina.core.future.ConnectFuture;
034import org.apache.mina.core.future.DefaultConnectFuture;
035import org.apache.mina.core.service.AbstractIoConnector;
036import org.apache.mina.core.service.IoConnector;
037import org.apache.mina.core.service.TransportMetadata;
038import org.apache.mina.core.session.IdleStatusChecker;
039import org.apache.mina.core.session.IoSessionConfig;
040import org.apache.mina.core.session.IoSessionInitializer;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044/**
045 * {@link IoConnector} for serial communication transport.
046 *
047 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
048 */
049public final class SerialConnector extends AbstractIoConnector {
050    private final Logger log;
051
052    private IdleStatusChecker idleChecker;
053
054    public SerialConnector() {
055        this(null);
056    }
057
058    public SerialConnector(Executor executor) {
059        super(new DefaultSerialSessionConfig(), executor);
060        log = LoggerFactory.getLogger(SerialConnector.class);
061
062        idleChecker = new IdleStatusChecker();
063        // we schedule the idle status checking task in this service exceutor
064        // it will be woke up every seconds
065        executeWorker(idleChecker.getNotifyingTask(), "idleStatusChecker");
066
067    }
068
069    @Override
070    protected synchronized ConnectFuture connect0(SocketAddress remoteAddress, SocketAddress localAddress,
071            IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
072
073        CommPortIdentifier portId;
074        Enumeration<?> portList = CommPortIdentifier.getPortIdentifiers();
075
076        SerialAddress portAddress = (SerialAddress) remoteAddress;
077
078        // looping around found ports
079        while (portList.hasMoreElements()) {
080            portId = (CommPortIdentifier) portList.nextElement();
081            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
082                if (log.isDebugEnabled()) {
083                    log.debug("Serial port discovered : " + portId.getName());
084                }
085                if (portId.getName().equals(portAddress.getName())) {
086                    try {
087                        if (log.isDebugEnabled()) {
088                            log.debug("Serial port found : " + portId.getName());
089                        }
090
091                        SerialPort serialPort = initializePort("Apache MINA", portId, portAddress);
092
093                        ConnectFuture future = new DefaultConnectFuture();
094                        SerialSessionImpl session = new SerialSessionImpl(this, getListeners(), portAddress, serialPort);
095                        initSession(session, future, sessionInitializer);
096                        session.start();
097                        return future;
098                    } catch (PortInUseException e) {
099                        if (log.isDebugEnabled()) {
100                            log.debug("Port In Use Exception : ", e);
101                        }
102                        return DefaultConnectFuture.newFailedFuture(e);
103                    } catch (UnsupportedCommOperationException e) {
104                        if (log.isDebugEnabled()) {
105                            log.debug("Comm Exception : ", e);
106                        }
107                        return DefaultConnectFuture.newFailedFuture(e);
108                    } catch (IOException e) {
109                        if (log.isDebugEnabled()) {
110                            log.debug("IOException : ", e);
111                        }
112                        return DefaultConnectFuture.newFailedFuture(e);
113                    } catch (TooManyListenersException e) {
114                        if (log.isDebugEnabled()) {
115                            log.debug("TooManyListenersException : ", e);
116                        }
117                        return DefaultConnectFuture.newFailedFuture(e);
118                    }
119                }
120            }
121        }
122
123        return DefaultConnectFuture.newFailedFuture(new SerialPortUnavailableException("Serial port not found"));
124    }
125
126    @Override
127    protected void dispose0() throws Exception {
128        // stop the idle checking task
129        idleChecker.getNotifyingTask().cancel();
130    }
131
132    public TransportMetadata getTransportMetadata() {
133        return SerialSessionImpl.METADATA;
134    }
135
136    private SerialPort initializePort(String user, CommPortIdentifier portId, SerialAddress portAddress)
137            throws UnsupportedCommOperationException, PortInUseException {
138
139        SerialSessionConfig config = (SerialSessionConfig) getSessionConfig();
140
141        long connectTimeout = getConnectTimeoutMillis();
142        if (connectTimeout > Integer.MAX_VALUE) {
143            connectTimeout = Integer.MAX_VALUE;
144        }
145
146        SerialPort serialPort = (SerialPort) portId.open(user, (int) connectTimeout);
147
148        serialPort.setSerialPortParams(portAddress.getBauds(), portAddress.getDataBitsForRXTX(),
149                portAddress.getStopBitsForRXTX(), portAddress.getParityForRXTX());
150
151        serialPort.setFlowControlMode(portAddress.getFLowControlForRXTX());
152
153        serialPort.notifyOnDataAvailable(true);
154
155        if (config.isLowLatency()) {
156            serialPort.setLowLatency();
157        }
158
159        serialPort.setInputBufferSize(config.getInputBufferSize());
160        serialPort.setOutputBufferSize(config.getOutputBufferSize());
161
162        if (config.getReceiveThreshold() >= 0) {
163            serialPort.enableReceiveThreshold(config.getReceiveThreshold());
164        } else {
165            serialPort.disableReceiveThreshold();
166        }
167
168        return serialPort;
169    }
170
171    IdleStatusChecker getIdleStatusChecker0() {
172        return idleChecker;
173    }
174
175    public IoSessionConfig getSessionConfig() {
176        return sessionConfig;
177    }
178}