All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.sputnikdev.bluetooth.manager.impl.CharacteristicGovernorImpl Maven / Gradle / Ivy
package org.sputnikdev.bluetooth.manager.impl;
/*-
* #%L
* org.sputnikdev:bluetooth-manager
* %%
* Copyright (C) 2017 Sputnik Dev
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sputnikdev.bluetooth.URL;
import org.sputnikdev.bluetooth.manager.BluetoothObjectType;
import org.sputnikdev.bluetooth.manager.BluetoothObjectVisitor;
import org.sputnikdev.bluetooth.manager.CharacteristicGovernor;
import org.sputnikdev.bluetooth.manager.NotReadyException;
import org.sputnikdev.bluetooth.manager.ValueListener;
import org.sputnikdev.bluetooth.manager.transport.Characteristic;
import org.sputnikdev.bluetooth.manager.transport.CharacteristicAccessType;
import org.sputnikdev.bluetooth.manager.transport.Notification;
import java.time.Instant;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
*
* @author Vlad Kolotov
*/
class CharacteristicGovernorImpl extends AbstractBluetoothObjectGovernor
implements CharacteristicGovernor {
private Logger logger = LoggerFactory.getLogger(CharacteristicGovernorImpl.class);
private List valueListeners = new CopyOnWriteArrayList<>();
private ValueNotification valueNotification;
private boolean canNotify;
private Instant lastNotified;
CharacteristicGovernorImpl(BluetoothManagerImpl bluetoothManager, URL url) {
super(bluetoothManager, url);
}
@Override
void init(Characteristic characteristic) {
logger.debug("Initializing characteristic governor: {}", url);
canNotify = canNotify(characteristic);
logger.trace("Characteristic governor initialization performed: {} : {}", url, canNotify);
}
@Override
void update(Characteristic characteristic) {
logger.trace("Updating characteristic governor: {}", url);
if (canNotify) {
boolean notifying = characteristic.isNotifying();
logger.trace("Updating characteristic governor notifications state: {} : {} / {} / {}",
url, valueListeners.isEmpty(), notifying, valueNotification == null);
if (!valueListeners.isEmpty() && (!notifying || valueNotification == null)) {
enableNotification(characteristic);
} else if (valueListeners.isEmpty() && notifying) {
disableNotification(characteristic);
}
}
}
@Override
void reset(Characteristic characteristic) {
logger.debug("Resetting characteristic governor: {}", url);
valueNotification = null;
try {
if (canNotify && characteristic.isNotifying()) {
characteristic.disableValueNotifications();
}
} catch (Exception ex) {
logger.debug("Error occurred while resetting characteristic: {} : {} ", url, ex.getMessage());
}
}
@Override
public void dispose() {
super.dispose();
logger.debug("Disposing characteristic governor: {}", url);
valueListeners.clear();
logger.trace("Characteristic governor disposed: {}", url);
}
@Override
public void addValueListener(ValueListener valueListener) {
valueListeners.add(valueListener);
}
@Override
public void removeValueListener(ValueListener valueListener) {
valueListeners.remove(valueListener);
}
@Override
public Set getFlags() throws NotReadyException {
return interact("getFlags", Characteristic::getFlags);
}
@Override
public boolean isNotifiable() throws NotReadyException {
Set flgs = getFlags();
return flgs.contains(CharacteristicAccessType.NOTIFY) || flgs.contains(CharacteristicAccessType.INDICATE);
}
@Override
public boolean isNotifying() throws NotReadyException {
return isReady() && interact("isNotifying", Characteristic::isNotifying);
}
@Override
public boolean isWritable() throws NotReadyException {
Set flgs = getFlags();
return flgs.contains(CharacteristicAccessType.WRITE)
|| flgs.contains(CharacteristicAccessType.WRITE_WITHOUT_RESPONSE);
}
@Override
public boolean isReadable() throws NotReadyException {
return getFlags().contains(CharacteristicAccessType.READ);
}
@Override
public byte[] read() throws NotReadyException {
if (!isReadable()) {
throw new IllegalStateException("Characteristic is not readable: {}" + url);
}
return interact("read", Characteristic::readValue, true);
}
@Override
public boolean write(byte[] data) throws NotReadyException {
if (!isWritable()) {
throw new IllegalStateException("Characteristic is not writable: {}" + url);
}
return interact("write", characteristic -> characteristic.writeValue(data), true);
}
@Override
public String toString() {
return "[Characteristic] " + getURL();
}
@Override
public BluetoothObjectType getType() {
return BluetoothObjectType.CHARACTERISTIC;
}
@Override
public void accept(BluetoothObjectVisitor visitor) throws Exception {
visitor.visit(this);
}
@Override
public Instant getLastNotified() {
return lastNotified;
}
@Override
void notifyLastChanged() {
notifyLastChanged(BluetoothManagerUtils.max(getLastInteracted(), lastNotified));
}
private void updateLastNotified() {
lastNotified = Instant.now();
}
private void enableNotification(Characteristic characteristic) {
logger.debug("Enabling characteristic notifications: {} : {} / {}",
getURL(), valueNotification == null, canNotify);
if (valueNotification == null && canNotify) {
ValueNotification notification = new ValueNotification();
characteristic.enableValueNotifications(notification);
valueNotification = notification;
}
}
private void disableNotification(Characteristic characteristic) {
logger.debug("Disabling characteristic notifications: {} : {} / {}",
getURL(), valueNotification == null, canNotify);
ValueNotification notification = valueNotification;
valueNotification = null;
if (notification != null && canNotify) {
characteristic.disableValueNotifications();
}
}
private static boolean canNotify(Characteristic characteristic) {
Set flgs = characteristic.getFlags();
return flgs.contains(CharacteristicAccessType.NOTIFY) || flgs.contains(CharacteristicAccessType.INDICATE);
}
private class ValueNotification implements Notification {
@Override
public void notify(byte[] data) {
logger.trace("Characteristic value changed (notification): {}", url);
updateLastInteracted();
updateLastNotified();
BluetoothManagerUtils.forEachSilently(valueListeners, ValueListener::changed, data, logger,
"Execution error of a characteristic listener");
}
}
}