<commit_before>/**
 * Copyright (c) 2010-2015, openHAB.org and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.openhab.binding.zwave.internal.protocol.serialmessage;

import org.openhab.binding.zwave.internal.protocol.SerialMessage;
import org.openhab.binding.zwave.internal.protocol.TransmissionState;
import org.openhab.binding.zwave.internal.protocol.ZWaveController;
import org.openhab.binding.zwave.internal.protocol.ZWaveNode;
import org.openhab.binding.zwave.internal.protocol.SerialMessage.SerialMessagePriority;
import org.openhab.binding.zwave.internal.protocol.ZWaveNodeState;
import org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveWakeUpCommandClass;
import org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass.CommandClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class processes a serial message from the zwave controller
 * 
 * @author <NAME>
 * @since 1.5.0
 */
public class SendDataMessageClass extends ZWaveCommandProcessor {
	private static final Logger logger = LoggerFactory.getLogger(SendDataMessageClass.class);

	@Override
	public boolean handleResponse(ZWaveController zController, SerialMessage lastSentMessage,
			SerialMessage incomingMessage) {
		logger.trace("Handle Message Send Data Response");
		if (incomingMessage.getMessagePayloadByte(0) != 0x00) {
			logger.debug("NODE {}: Sent Data successfully placed on stack.", lastSentMessage.getMessageNode());
		}
		else {
			// This is an error. This means that the transaction is complete!
			// Set the flag, and return false.
			logger.error("NODE {}: Sent Data was not placed on stack due to error {}.", lastSentMessage.getMessageNode(), 
					incomingMessage.getMessagePayloadByte(0));
			
			// We ought to cancel the transaction
			lastSentMessage.setTransactionCanceled();

			return false;
		}

		return true;
	}

	@Override
	public boolean handleRequest(ZWaveController zController, SerialMessage lastSentMessage,
			SerialMessage incomingMessage) {
		logger.trace("Handle Message Send Data Request");

		int callbackId = incomingMessage.getMessagePayloadByte(0);
		TransmissionState status = TransmissionState.getTransmissionState(incomingMessage.getMessagePayloadByte(1));

		if (status == null) {
			logger.warn("Transmission state not found, ignoring.");
			return false;
		}

		ZWaveNode node = zController.getNode(lastSentMessage.getMessageNode());
		if(node == null) {
			logger.warn("Node not found!");
			return false;
		}

		logger.debug("NODE {}: SendData Request. CallBack ID = {}, Status = {}({})", node.getNodeId(), callbackId, status.getLabel(), status.getKey());

		if (lastSentMessage == null || lastSentMessage.getCallbackId() != callbackId) {
			logger.warn("NODE {}: Already processed another send data request for this callback Id, ignoring.", node.getNodeId());
			return false;
		}

		// This response is our controller ACK
		lastSentMessage.setAckRecieved();
		
		switch (status) {
		case COMPLETE_OK:
			// Consider this as a received frame since the controller did receive an ACK from the device.
			node.incrementReceiveCount();

			// If the node is DEAD, but we've just received an ACK from it, then it's not dead!
			if(node.isDead()) {
				node.setNodeState(ZWaveNodeState.ALIVE);;
			}
			else {
				node.resetResendCount();
			}
			checkTransactionComplete(lastSentMessage, incomingMessage);
			return true;
		case COMPLETE_NO_ACK:
			// timeOutCount.incrementAndGet();
		case COMPLETE_FAIL:
		case COMPLETE_NOT_IDLE:
		case COMPLETE_NOROUTE:
			try {
				handleFailedSendDataRequest(zController, lastSentMessage);
			} finally {
				transactionComplete = true;
			}
			break;
		default:
			break;
		}

		return false;
	}

	public boolean handleFailedSendDataRequest(ZWaveController zController, SerialMessage originalMessage) {

		ZWaveNode node = zController.getNode(originalMessage.getMessageNode());

		logger.trace("NODE {}: Handling failed message.", node.getNodeId());

		// Increment the resend count.
		// This will set the node to DEAD if we've exceeded the retries.
		node.incrementResendCount();

		// No retries if the node is DEAD or FAILED
		if (node.isDead()) {
			logger.error("NODE {}: Node is DEAD. Dropping message.", node.getNodeId());
			return false;
		}

		// High priority messages get requeued, low priority get dropped
		if (!node.isListening() && !node.isFrequentlyListening()
				&& originalMessage.getPriority() != SerialMessagePriority.Low) {
			ZWaveWakeUpCommandClass wakeUpCommandClass = (ZWaveWakeUpCommandClass) node
					.getCommandClass(CommandClass.WAKE_UP);

			if (wakeUpCommandClass != null) {
				// It's a battery operated device, place in wake-up queue.
				wakeUpCommandClass.setAwake(false);
				wakeUpCommandClass.processOutgoingWakeupMessage(originalMessage);
				return false;
			}
		} else if (!node.isListening() && !node.isFrequentlyListening()
				&& originalMessage.getPriority() == SerialMessagePriority.Low) {
			return false;
		}

		logger.error("NODE {}: Got an error while sending data. Resending message.", node.getNodeId());
		zController.sendData(originalMessage);
		return true;
	}
}<commit_msg>Consolidate transmission state since it's only required by SendData message<commit_after>/**
 * Copyright (c) 2010-2015, openHAB.org and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.openhab.binding.zwave.internal.protocol.serialmessage;

import java.util.HashMap;
import java.util.Map;

import org.openhab.binding.zwave.internal.protocol.SerialMessage;
import org.openhab.binding.zwave.internal.protocol.ZWaveController;
import org.openhab.binding.zwave.internal.protocol.ZWaveNode;
import org.openhab.binding.zwave.internal.protocol.SerialMessage.SerialMessagePriority;
import org.openhab.binding.zwave.internal.protocol.ZWaveNodeState;
import org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveWakeUpCommandClass;
import org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveCommandClass.CommandClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class processes a serial message from the zwave controller
 * 
 * @author <NAME>
 * @since 1.5.0
 */
public class SendDataMessageClass extends ZWaveCommandProcessor {
	private static final Logger logger = LoggerFactory.getLogger(SendDataMessageClass.class);

	@Override
	public boolean handleResponse(ZWaveController zController, SerialMessage lastSentMessage,
			SerialMessage incomingMessage) {
		logger.trace("Handle Message Send Data Response");
		if (incomingMessage.getMessagePayloadByte(0) != 0x00) {
			logger.debug("NODE {}: Sent Data successfully placed on stack.", lastSentMessage.getMessageNode());
		}
		else {
			// This is an error. This means that the transaction is complete!
			// Set the flag, and return false.
			logger.error("NODE {}: Sent Data was not placed on stack due to error {}.", lastSentMessage.getMessageNode(), 
					incomingMessage.getMessagePayloadByte(0));
			
			// We ought to cancel the transaction
			lastSentMessage.setTransactionCanceled();

			return false;
		}

		return true;
	}

	@Override
	public boolean handleRequest(ZWaveController zController, SerialMessage lastSentMessage,
			SerialMessage incomingMessage) {
		logger.trace("Handle Message Send Data Request");

		int callbackId = incomingMessage.getMessagePayloadByte(0);
		TransmissionState status = TransmissionState.getTransmissionState(incomingMessage.getMessagePayloadByte(1));

		if (status == null) {
			logger.warn("Transmission state not found, ignoring.");
			return false;
		}

		ZWaveNode node = zController.getNode(lastSentMessage.getMessageNode());
		if(node == null) {
			logger.warn("Node not found!");
			return false;
		}

		logger.debug("NODE {}: SendData Request. CallBack ID = {}, Status = {}({})", node.getNodeId(), callbackId, status.getLabel(), status.getKey());

		if (lastSentMessage == null || lastSentMessage.getCallbackId() != callbackId) {
			logger.warn("NODE {}: Already processed another send data request for this callback Id, ignoring.", node.getNodeId());
			return false;
		}

		// This response is our controller ACK
		lastSentMessage.setAckRecieved();
		
		switch (status) {
		case COMPLETE_OK:
			// Consider this as a received frame since the controller did receive an ACK from the device.
			node.incrementReceiveCount();

			// If the node is DEAD, but we've just received an ACK from it, then it's not dead!
			if(node.isDead()) {
				node.setNodeState(ZWaveNodeState.ALIVE);;
			}
			else {
				node.resetResendCount();
			}
			checkTransactionComplete(lastSentMessage, incomingMessage);
			return true;
		case COMPLETE_NO_ACK:
			// timeOutCount.incrementAndGet();
		case COMPLETE_FAIL:
		case COMPLETE_NOT_IDLE:
		case COMPLETE_NOROUTE:
			try {
				handleFailedSendDataRequest(zController, lastSentMessage);
			} finally {
				transactionComplete = true;
			}
			break;
		default:
			break;
		}

		return false;
	}

	public boolean handleFailedSendDataRequest(ZWaveController zController, SerialMessage originalMessage) {

		ZWaveNode node = zController.getNode(originalMessage.getMessageNode());

		logger.trace("NODE {}: Handling failed message.", node.getNodeId());

		// Increment the resend count.
		// This will set the node to DEAD if we've exceeded the retries.
		node.incrementResendCount();

		// No retries if the node is DEAD or FAILED
		if (node.isDead()) {
			logger.error("NODE {}: Node is DEAD. Dropping message.", node.getNodeId());
			return false;
		}

		// High priority messages get requeued, low priority get dropped
		if (!node.isListening() && !node.isFrequentlyListening()
				&& originalMessage.getPriority() != SerialMessagePriority.Low) {
			ZWaveWakeUpCommandClass wakeUpCommandClass = (ZWaveWakeUpCommandClass) node
					.getCommandClass(CommandClass.WAKE_UP);

			if (wakeUpCommandClass != null) {
				// It's a battery operated device, place in wake-up queue.
				wakeUpCommandClass.setAwake(false);
				wakeUpCommandClass.processOutgoingWakeupMessage(originalMessage);
				return false;
			}
		} else if (!node.isListening() && !node.isFrequentlyListening()
				&& originalMessage.getPriority() == SerialMessagePriority.Low) {
			return false;
		}

		logger.error("NODE {}: Got an error while sending data. Resending message.", node.getNodeId());
		zController.sendData(originalMessage);
		return true;
	}
	
	/**
	 * Transmission state enumeration. Indicates the
	 * transmission state of the message to the node.
	 * @author <NAME>
	 * @ since 1.3.0
	 */
	public enum TransmissionState {
		COMPLETE_OK(0x00, "Transmission complete and ACK received"),
		COMPLETE_NO_ACK(0x01, "Transmission complete, no ACK received"),
		COMPLETE_FAIL(0x02, "Transmission failed"),
		COMPLETE_NOT_IDLE(0x03, "Transmission failed, network busy"),
		COMPLETE_NOROUTE(0x04, "Tranmission complete, no return route");
		
		/**
		 * A mapping between the integer code and its corresponding transmission state
		 * class to facilitate lookup by code.
		 */
		private static Map<Integer, TransmissionState> codeToTransmissionStateMapping;

		private int key;
		private String label;

		private TransmissionState(int key, String label) {
			this.key = key;
			this.label = label;
		}

		private static void initMapping() {
			codeToTransmissionStateMapping = new HashMap<Integer, TransmissionState>();
			for (TransmissionState s : values()) {
				codeToTransmissionStateMapping.put(s.key, s);
			}
		}

		/**
		 * Lookup function based on the transmission state code.
		 * Returns null when there is no transmission state with code i.
		 * @param i the code to lookup
		 * @return enumeration value of the transmission state.
		 */
		public static TransmissionState getTransmissionState(int i) {
			if (codeToTransmissionStateMapping == null) {
				initMapping();
			}
			
			return codeToTransmissionStateMapping.get(i);
		}

		/**
		 * @return the key
		 */
		public int getKey() {
			return key;
		}

		/**
		 * @return the label
		 */
		public String getLabel() {
			return label;
		}
	}
}
{'fraction_non_alphanumeric': 0.10268359312228828, 'fraction_numerical': 0.005302908565000803, 'mean_word_length': 4.383650519031142, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3963319', 'n_tokens_mistral': 4047, 'n_tokens_neox': 3550, 'n_words': 969}