001package com.pi4j.jni; 002 003/* 004 * #%L 005 * ********************************************************************** 006 * ORGANIZATION : Pi4J 007 * PROJECT : Pi4J :: Java Library (Core) 008 * FILENAME : SerialInterrupt.java 009 * 010 * This file is part of the Pi4J project. More information about 011 * this project can be found here: http://www.pi4j.com/ 012 * ********************************************************************** 013 * %% 014 * Copyright (C) 2012 - 2016 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 032 033import com.pi4j.util.NativeLibraryLoader; 034 035import java.util.Map; 036import java.util.concurrent.ConcurrentHashMap; 037 038/** 039 * <p> 040 * This class provides static methods to configure the native Pi4J library to listen to serial 041 * interrupts and invoke callbacks into this class. Additionally, this class provides a listener 042 * registration allowing Java consumers to subscribe to serial data receive events. 043 * </p> 044 * 045 * @see <a href="http://www.pi4j.com/">http://www.pi4j.com/</a> 046 * @author Robert Savage (<a 047 * href="http://www.savagehomeautomation.com">http://www.savagehomeautomation.com</a>) 048 */ 049public class SerialInterrupt { 050 051 private static Map<Integer, SerialInterruptListener> listeners = new ConcurrentHashMap<Integer, SerialInterruptListener>(); 052 053 // private constructor 054 private SerialInterrupt() { 055 // forbid object construction 056 } 057 058 static { 059 // Load the platform library 060 NativeLibraryLoader.load("libpi4j.so"); 061 } 062 063 /** 064 * <p> 065 * This method is used to instruct the native code to setup a monitoring thread to monitor 066 * interrupts that represent changes to the selected serial port. 067 * </p> 068 * 069 * @param fileDescriptor the serial file descriptor/handle 070 * @return A return value of a negative number represents an error. A return value of '0' 071 * represents success and that the serial port is already being monitored. A return value 072 * of '1' represents success and that a new monitoring thread was created to handle the 073 * requested serial port. 074 */ 075 public static native int enableSerialDataReceiveCallback(int fileDescriptor); 076 077 /** 078 * <p> 079 * This method is used to instruct the native code to stop the monitoring thread monitoring 080 * interrupts on the selected serial port. 081 * </p> 082 * 083 * @param fileDescriptor the serial file descriptor/handle 084 085 * @return A return value of a negative number represents an error. A return value of '0' 086 * represents success and that no existing monitor was previously running. A return 087 * value of '1' represents success and that an existing monitoring thread was stopped 088 * for the requested serial port. 089 */ 090 public static native int disableSerialDataReceiveCallback(int fileDescriptor); 091 092 /** 093 * <p> 094 * This method is provided as the callback handler for the Pi4J native library to invoke when a 095 * GPIO interrupt is detected. This method should not be called from any Java consumers. (Thus 096 * is is marked as a private method.) 097 * </p> 098 * 099 * @param fileDescriptor the serial file descriptor/handle 100 * //@param data byte array of data received on this event from the serial receive buffer 101 */ 102 @SuppressWarnings("unchecked") 103 private static void onDataReceiveCallback(int fileDescriptor, byte[] data) { 104 105 // notify event listeners 106 if(listeners.containsKey(fileDescriptor)){ 107 SerialInterruptListener listener = listeners.get(fileDescriptor); 108 if(listener != null) { 109 SerialInterruptEvent event = new SerialInterruptEvent(listener, fileDescriptor, data); 110 listener.onDataReceive(event); 111 } 112 } 113 114 //System.out.println("SERIAL PORT [" + fileDescriptor + "] DATA LENGTH = " + data.length + " / " + new String(data)); 115 } 116 117 /** 118 * <p> 119 * Java consumer code can all this method to register itself as a listener for pin state 120 * changes. 121 * </p> 122 * 123 * @see com.pi4j.jni.SerialInterruptListener 124 * @see com.pi4j.jni.SerialInterruptEvent 125 * 126 * @param fileDescriptor the serial file descriptor/handle 127 * @param listener A class instance that implements the GpioInterruptListener interface. 128 */ 129 public static synchronized void addListener(int fileDescriptor, SerialInterruptListener listener) { 130 if (!listeners.containsKey(fileDescriptor)) { 131 listeners.put(fileDescriptor, listener); 132 enableSerialDataReceiveCallback(fileDescriptor); 133 } 134 } 135 136 /** 137 * <p> 138 * Java consumer code can all this method to unregister itself as a listener for pin state 139 * changes. 140 * </p> 141 * 142 * @see com.pi4j.jni.SerialInterruptListener 143 * @see com.pi4j.jni.SerialInterruptEvent 144 * 145 * @param fileDescriptor the serial file descriptor/handle 146 */ 147 public static synchronized void removeListener(int fileDescriptor) { 148 if (listeners.containsKey(fileDescriptor)) { 149 listeners.remove(fileDescriptor); 150 disableSerialDataReceiveCallback(fileDescriptor); 151 } 152 } 153 154 155 /** 156 * <p> 157 * Returns true if the listener is already registered for event callbacks. 158 * </p> 159 * 160 * @see com.pi4j.jni.SerialInterruptListener 161 * @see com.pi4j.jni.SerialInterruptEvent 162 * 163 * @param fileDescriptor the serial file descriptor/handle 164 */ 165 public static synchronized boolean hasListener(int fileDescriptor) { 166 return listeners.containsKey(fileDescriptor); 167 } 168}