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: 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 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="https://www.pi4j.com/">https://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<>(); 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", "pi4j"); 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 private static void onDataReceiveCallback(int fileDescriptor, byte[] data) { 103 104 // notify event listeners 105 if(listeners.containsKey(fileDescriptor)){ 106 SerialInterruptListener listener = listeners.get(fileDescriptor); 107 if(listener != null) { 108 SerialInterruptEvent event = new SerialInterruptEvent(listener, fileDescriptor, data); 109 listener.onDataReceive(event); 110 } 111 } 112 113 //System.out.println("SERIAL PORT [" + fileDescriptor + "] DATA LENGTH = " + data.length + " / " + new String(data)); 114 } 115 116 /** 117 * <p> 118 * Java consumer code can all this method to register itself as a listener for pin state 119 * changes. 120 * </p> 121 * 122 * @see com.pi4j.jni.SerialInterruptListener 123 * @see com.pi4j.jni.SerialInterruptEvent 124 * 125 * @param fileDescriptor the serial file descriptor/handle 126 * @param listener A class instance that implements the GpioInterruptListener interface. 127 */ 128 public static synchronized void addListener(int fileDescriptor, SerialInterruptListener listener) { 129 if (!listeners.containsKey(fileDescriptor)) { 130 listeners.put(fileDescriptor, listener); 131 enableSerialDataReceiveCallback(fileDescriptor); 132 } 133 } 134 135 /** 136 * <p> 137 * Java consumer code can all this method to unregister itself as a listener for pin state 138 * changes. 139 * </p> 140 * 141 * @see com.pi4j.jni.SerialInterruptListener 142 * @see com.pi4j.jni.SerialInterruptEvent 143 * 144 * @param fileDescriptor the serial file descriptor/handle 145 */ 146 public static synchronized void removeListener(int fileDescriptor) { 147 if (listeners.containsKey(fileDescriptor)) { 148 listeners.remove(fileDescriptor); 149 disableSerialDataReceiveCallback(fileDescriptor); 150 } 151 } 152 153 154 /** 155 * <p> 156 * Returns true if the listener is already registered for event callbacks. 157 * </p> 158 * 159 * @see com.pi4j.jni.SerialInterruptListener 160 * @see com.pi4j.jni.SerialInterruptEvent 161 * 162 * @param fileDescriptor the serial file descriptor/handle 163 */ 164 public static synchronized boolean hasListener(int fileDescriptor) { 165 return listeners.containsKey(fileDescriptor); 166 } 167}