001package jmri.jmrix.lenz.liusbserver;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004import java.nio.charset.StandardCharsets;
005import jmri.jmrix.AbstractMRListener;
006import jmri.jmrix.AbstractMRMessage;
007import jmri.jmrix.lenz.XNetPacketizer;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * This is an extension of the XNetPacketizer to handle the device specific
013 * requirements of the LIUSB Server.
014 * <p>
015 * In particular, LIUSBServerXNetPacketizer counts the number of commands
016 * received.
017 *
018 * @author Paul Bender, Copyright (C) 2009
019 *
020 */
021public class LIUSBServerXNetPacketizer extends XNetPacketizer {
022
023    public LIUSBServerXNetPacketizer(jmri.jmrix.lenz.LenzCommandStation pCommandStation) {
024        super(pCommandStation);
025        log.debug("Loading LIUSB Server Extension to XNetPacketizer");
026    }
027
028    /**
029     * Actually transmits the next message to the port
030     */
031    @SuppressFBWarnings(value = {"UW_UNCOND_WAIT"},
032             justification = "Wait is for external hardware, which doesn't necessarilly respond, to process the data.")
033
034    @Override
035    protected void forwardToPort(AbstractMRMessage m, AbstractMRListener reply) {
036        log.debug("forwardToPort message: [{}]", m);
037        // remember who sent this
038        mLastSender = reply;
039
040        // forward the message to the registered recipients,
041        // which includes the communications monitor, except the sender.
042        // Schedule notification via the Swing event queue to ensure order
043        Runnable r = new XmtNotifier(m, mLastSender, this);
044        javax.swing.SwingUtilities.invokeLater(r);
045
046        // stream the bytes
047        try {
048            if (ostream != null) {
049                while (m.getRetries() >= 0) {
050                    if (portReadyToSend(controller)) {
051                        ostream.write((m + "\n\r").getBytes(StandardCharsets.UTF_8));
052                        ostream.flush();
053                        log.debug("written");
054                        break;
055                    } else if (m.getRetries() >= 0) {
056                        if (log.isDebugEnabled()) {
057                            log.debug("Retry message: {} attempts remaining: {}", m.toString(), m.getRetries());
058                        }
059                        m.setRetries(m.getRetries() - 1);
060                        try {
061                            synchronized (xmtRunnable) {
062                                xmtRunnable.wait(m.getTimeout());
063                            }
064                        } catch (InterruptedException e) {
065                            Thread.currentThread().interrupt(); // retain if needed later
066                            log.error("retry wait interrupted");
067                        }
068                    } else {
069                        log.warn("sendMessage: port not ready for data sending: {}", m.toString());
070                    }
071                }
072            } else {  // ostream is null
073                // no stream connected
074                connectionWarn();
075            }
076        } catch (java.io.IOException e) {
077            // start the recovery process if an exception occurs.
078            portWarn(e);
079            controller.recover();
080        }
081    }
082
083    private static final Logger log = LoggerFactory.getLogger(LIUSBServerXNetPacketizer.class);
084
085}