# THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
# APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
# HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
# OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
# IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
# ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
# THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
# GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
# USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
# DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
# PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
# EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGES.

# Copyright (c) 2018 Dr. Oliver Barth <info@drb-electronic.de>
# Provides a OPC UA server for all hardware interfaces

import opcua

#
class OpcUaServer():

	#
	def __init__(self, hwmng):
		self.hwmng = hwmng
		self.active = hwmng.getSettings().getOPCUAConfig()
		if(self.active == 1):
			self.can = hwmng.getCAN()
			
			self.server = opcua.Server()
			self.server.set_endpoint("opc.tcp://192.168.2.111:4840/freeopcua/server/")
			uri = "http://drb_electronic.de"
			idx = self.server.register_namespace(uri)
			objects = self.server.get_objects_node()
			
			rootObj = objects.add_object(idx, "DRB_OIPC_888_CAN")
			
			self.din = rootObj.add_variable(idx, "digital_in", 0)
			self.expIo = rootObj.add_variable(idx, "expio_in", 0)
			self.anInArr = rootObj.add_variable(idx, "analog_in", [0, 0, 0, 0, 0, 0, 0, 0])

			self.sTime = rootObj.add_variable(idx, "time", "")
			self.methSetOutput = rootObj.add_method(idx, "set_output", self.setDout, [opcua.ua.VariantType.Byte], [opcua.ua.VariantType.Boolean])

			self.canObj = rootObj.add_object(idx, "CAN")
			self.canBaudrate = self.canObj.add_property(idx, "baudrate", "500000")
			
			self.canTxMsg = self.canObj.add_object(idx, "transmit message")
			self.canTxMsgId = self.canTxMsg.add_property(idx, "id", "128")
			self.canTxMsgId.set_writable()
			self.canTxMsgDlc = self.canTxMsg.add_property(idx, "data length code", "8")
			self.canTxMsgDlc.set_writable()
			self.canTxMsgData = self.canTxMsg.add_variable(idx, "data", opcua.ua.Variant([0, 0, 0, 0, 0, 0, 0, 0], opcua.ua.VariantType.Byte))
			self.canTxMsgSend = self.canTxMsg.add_method(idx, "send message", self.txCanMsg,
				[opcua.ua.VariantType.Byte, opcua.ua.VariantType.Byte, opcua.ua.VariantType.Byte, opcua.ua.VariantType.Byte,
				opcua.ua.VariantType.Byte, opcua.ua.VariantType.Byte, opcua.ua.VariantType.Byte, opcua.ua.VariantType.Byte], [opcua.ua.VariantType.Boolean])
			self.canTxMsgState = self.canTxMsg.add_property(idx, "state", "idle")
			
			self.canRxMsg = self.canObj.add_object(idx, "receive message")
			self.canRxMsgId = self.canRxMsg.add_property(idx, "id", "128")
			self.canRxMsgDlc = self.canRxMsg.add_property(idx, "data length code", "8")
			self.canRxMsgData = self.canRxMsg.add_variable(idx, "data", opcua.ua.Variant([0, 0, 0, 0, 0, 0, 0, 0], opcua.ua.VariantType.Byte))
			print 'OPC UA server started'
		else:
			print 'OPC UA not active'

	#
	def start(self):
		if(self.active == 1):
			self.server.start()

	#
	def stop(self):
		if(self.active == 1):
			self.server.stop()

	#
	def setDout(self, parent, num):
		if(self.active == 1):
			print 'value:' + str(num.Value)
		return [opcua.ua.Variant(True, opcua.ua.VariantType.Boolean)]

	#
	def txCanMsg(self, parent, b0, b1, b2, b3, b4, b5, b6, b7):
		if(self.active == 1):
			msg = [(int)(b0.Value), (int)(b1.Value), (int)(b2.Value), (int)(b3.Value), (int)(b4.Value), (int)(b5.Value), (int)(b6.Value), (int)(b7.Value)]
			self.can.addToTransmitQueue((int)(self.canTxMsgId.get_value()), (int)(self.canTxMsgDlc.get_value()), msg)
		return [opcua.ua.Variant(True, opcua.ua.VariantType.Boolean)]

	# callback from can module
	def canMsgReceived(self, rxmsg):
		if(self.active == 1):
			self.canRxMsgId.set_data_value(rxmsg[0])
			self.canRxMsgDlc.set_data_value(rxmsg[1])
			self.canRxMsgData.set_data_value([rxmsg[2], rxmsg[3], rxmsg[4], rxmsg[5], rxmsg[6], rxmsg[7], rxmsg[8], rxmsg[9]])

	#
	def update(self):
		if(self.active == 1):
			self.din.set_data_value(self.hwmng.getDIO().getInputAsByte())
			self.expIo.set_data_value(self.hwmng.getIOEXP0().getInputAsInt())
			self.anInArr.set_value(self.hwmng.getADC().getADValues())
			self.sTime.set_value(self.hwmng.getRTC().getSDateTime())
