//This file was generated by the LASAL2 CodeGenerator  -- 
//Please, do not edit this file (it might be overwritten by the next generator run)

//{{LSL_DEFINES
#define DEVICE_ID_AI043 1045

#define AI043_ADDR_CYC_WRITE        16#000
#define AI043_ADDR_CYC_READ         16#080
#define AI043_ADDR_CFG_FIRMWARE     16#100
#define AI043_ADDR_STATE_FIRMWARE   16#180

#define AI043_SDO_RESPONSE_TIMEOUT  SDIAS_SDO_TIMEOUT * 2

#define AI043_KTY84_RAW_VALUES_FW_VER_AVAILABLE  16#110
#define AI043_AMOUNT_OF_VALID_CFG   25
#define AI043_AMOUNT_OF_VALID_CFGS_BEFORE_KTY84_ADDED 23

#define AI043_NUMBER_OF_ANALOG_IN   4
#define AI043_INVALID_VALUE         16#80000010$DINT
#define AI043_CABLE_BREAK_MASK      16#0F  //4 BITS

#define AI043_FIRMWARE_MIN          0
#define AI043_FIRMWARE_MAX_CFG12    2500
#define AI043_FIRMWARE_MAX_CFG13    5000
#define AI043_FIRMWARE_MAX_CFG14    10000
#define AI043_FIRMWARE_MAX_CFG15    25000
#define AI043_FIRMWARE_MAX_CFG16    50000


//}}LSL_DEFINES

//{{LSL_DECLARATION

(*!
<Class
	Name               = "AI043"
	Revision           = "1.20"
	GUID               = "{60F7777C-F3F3-4B20-915B-C8F9D4BBCA83}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\s-dias.ico"
	SharedCommandTable = "true"
	Objectsize         = "(626,120)"
	Comment            = "Class for AI043 hardware module (4x analog inputs)">
	<Channels>
		<Server Name="AI1" GUID="{08A3C829-FE79-4197-9D60-296278BDCF8C}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Analog input 1 or temperature input. Status query over read().&#13;&#10;The invalid value in case of cable break or short circuit is 16#80000010.&#13;&#10;Values in 1/10 °C or 1/10 Ohm when type is potentiometer or 1/100°C if AI1Config is 25)"/>
		<Server Name="AI2" GUID="{817A5181-F870-4D7B-9002-7D4F5BFA549C}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Analog input 2 or temperature input. Status query over read().&#13;&#10;The invalid value in case of cable break or short circuit is 16#80000010.&#13;&#10;Values in 1/10 °C or 1/10 Ohm when type is potentiometer or 1/100°C if AI2Config is 25)"/>
		<Server Name="AI3" GUID="{44E8C4DB-7B34-4FD5-8156-6B50F5973B3F}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Analog input 3 or temperature input. Status query over read().&#13;&#10;The invalid value in case of cable break or short circuit is 16#80000010.&#13;&#10;Values in 1/10 °C or 1/10 Ohm when type is potentiometer or 1/100°C if AI3Config is 25)"/>
		<Server Name="AI4" GUID="{43267F4F-D9E0-4E74-9848-858B75487729}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Analog input 4 or temperature input. Status query over read().&#13;&#10;The invalid value in case of cable break or short circuit is 16#80000010.&#13;&#10;Values in 1/10 °C or 1/10 Ohm when type is potentiometer or 1/100°C if AI4Config is 25)"/>
		<Server Name="CableBreak" GUID="{6F75EDE5-C8E1-4005-8AC7-1E9CB7F299CC}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Cable break detection:&#13;&#10;Bit0...Cable break on AI1&#13;&#10;Bit1...Cable break on AI2&#13;&#10;Bit2...Cable break on AI3&#13;&#10;Bit3...Cable break on AI4&#13;&#10;"/>
		<Server Name="FirmwareVersion" GUID="{74ABB48A-A01C-4856-BC0B-2268E5981932}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Version of the used firmware&#13;&#10;&#13;&#10;e.g. 16#100 means v1.0"/>
		<Server Name="FWErrorBits" GUID="{52BC0A9C-D330-4475-A685-12337C1BD543}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Firmware Status:&#13;&#10;Bit0...DC not Ok&#13;&#10;Bit1...No Sync&#13;&#10;Bit2...Flash data CRC error&#13;&#10;Bit3...Ram data CRC error&#13;&#10;Bit4...No valid EEPROM Version&#13;&#10;Bit5...Flash Unsafe&#13;&#10;Bit6...Bus Time not supported"/>
		<Server Name="Range" GUID="{C1B4CA0B-3900-40A9-9A71-DD5374B97B08}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Range Detection of inputs.&#13;&#10;Bit 0 ... Upper Threshold value of input 1 exceeded.&#13;&#10;Bit 1 ... Upper Threshold value of input 2 exceeded.&#13;&#10;Bit 2 ... Upper Threshold value of input 3 exceeded.&#13;&#10;Bit 3 ... Upper Threshold value of input 4 exceeded.&#13;&#10;&#13;&#10;Bit 4 ... Value of input 1 fall below lower Threshold value.&#13;&#10;Bit 5 ... Value of input 2 fall below lower Threshold value.&#13;&#10;Bit 6 ... Value of input 3 fall below lower Threshold value.&#13;&#10;Bit 7 ... Value of input 4 fall below lower Threshold value.&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;"/>
		<Client Name="AI1_Active" Required="false" Internal="false" DefValue="1" Comment="The channel can be activated/ deactived with this client.&#13;&#10;&#13;&#10;0 = Channel is deactivated. &#13;&#10;Channel LED is off at cable break.  &#13;&#10;&#13;&#10;1 = Channel is activated. &#13;&#10;Channel LED is flashing at cable break."/>
		<Client Name="AI1_Config" Required="false" Internal="false" Comment="With this client the sensor and its range can be selected.&#13;&#10; 0 = PT100  (Range: -200...+150°C)&#13;&#10; 1 = PT100  (Range: -200...+850°C)&#13;&#10; 2 = PT200  (Range: -200...+150°C)&#13;&#10; 3 = PT200  (Range: -200...+850°C)&#13;&#10; 4 = PT500  (Range: -200...+150°C)&#13;&#10; 5 = PT500  (Range: -200...+850°C)&#13;&#10; 6 = PT1000 (Range: -200...+150°C)&#13;&#10; 7 = PT1000 (Range: -200...+850°C)&#13;&#10; 8 = NI100  (Range: -60 ...+150°C)&#13;&#10; 9 = NI100  (Range: -60 ...+250°C)&#13;&#10;10 = NI1000 (Range: -60 ...+150°C)&#13;&#10;11 = NI1000 (Range: -60 ...+250°C)&#13;&#10;12 = Potentiometer (Range: 0 ... 250 Ohm)&#13;&#10;13 = Potentiometer (Range: 0 ... 500 Ohm)&#13;&#10;14 = Potentiometer (Range: 0 ...1000 Ohm)&#13;&#10;15 = Potentiometer (Range: 0 ...2500 Ohm)&#13;&#10;16 = Potentiometer (Range: 0 ...5000 Ohm)&#13;&#10;17 = KTY11-62  (Range: -50 ... 150°C)&#13;&#10;18 = KTY81-110 (Range: -55 ... 150°C)&#13;&#10;19 = KTY81-120 (Range: -55 ... 150°C)&#13;&#10;20 = KTY81-121 (Range: -55 ... 150°C)&#13;&#10;21 = KTY81-122 (Range: -55 ... 150°C)&#13;&#10;22 = KTY81-150 (Range: -55 ... 150°C)&#13;&#10;----------- Since FW version 1.10 -----------&#13;&#10;23 = KTY84-130 (Range: -40 ... 300°C)&#13;&#10;24 = KTY84-150 (Range: -40 ... 300°C)&#13;&#10;25 = PT100 (Range: -200 ... 150°C) in 1/100° Resolution"/>
		<Client Name="AI1_FilterFreq" Required="false" Internal="false" Comment="Cut off frequency for low pass filter&#13;&#10;0 ... 100 Hz&#13;&#10;1 ...  50 Hz&#13;&#10;2 ...  25 Hz&#13;&#10;3 ...  10 Hz&#13;&#10;4 ... Filter off.&#13;&#10;5 ...    1 Hz&#13;&#10;"/>
		<Client Name="AI1_Max" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI1_MeasureMethod" Required="false" Internal="false" Comment="0 = 2 wire measure method&#13;&#10;1 = 3 wire measure method"/>
		<Client Name="AI1_Min" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI2_Active" Required="false" Internal="false" DefValue="1" Comment="The channel can be activated/ deactived with this client.&#13;&#10;&#13;&#10;0 = Channel is deactivated. &#13;&#10;Channel LED is off at cable break.  &#13;&#10;&#13;&#10;1 = Channel is activated. &#13;&#10;Channel LED is flashing at cable break."/>
		<Client Name="AI2_Config" Required="false" Internal="false" Comment="With this client the sensor and its range can be selected.&#13;&#10; 0 = PT100  (Range: -200...+150°C)&#13;&#10; 1 = PT100  (Range: -200...+850°C)&#13;&#10; 2 = PT200  (Range: -200...+150°C)&#13;&#10; 3 = PT200  (Range: -200...+850°C)&#13;&#10; 4 = PT500  (Range: -200...+150°C)&#13;&#10; 5 = PT500  (Range: -200...+850°C)&#13;&#10; 6 = PT1000 (Range: -200...+150°C)&#13;&#10; 7 = PT1000 (Range: -200...+850°C)&#13;&#10; 8 = NI100  (Range: -60 ...+150°C)&#13;&#10; 9 = NI100  (Range: -60 ...+250°C)&#13;&#10;10 = NI1000 (Range: -60 ...+150°C)&#13;&#10;11 = NI1000 (Range: -60 ...+250°C)&#13;&#10;12 = Potentiometer (Range: 0 ... 250 Ohm)&#13;&#10;13 = Potentiometer (Range: 0 ... 500 Ohm)&#13;&#10;14 = Potentiometer (Range: 0 ...1000 Ohm)&#13;&#10;15 = Potentiometer (Range: 0 ...2500 Ohm)&#13;&#10;16 = Potentiometer (Range: 0 ...5000 Ohm)&#13;&#10;17 = KTY11-62  (Range: -50 ... 150°C)&#13;&#10;18 = KTY81-110 (Range: -55 ... 150°C)&#13;&#10;19 = KTY81-120 (Range: -55 ... 150°C)&#13;&#10;20 = KTY81-121 (Range: -55 ... 150°C)&#13;&#10;21 = KTY81-122 (Range: -55 ... 150°C)&#13;&#10;22 = KTY81-150 (Range: -55 ... 150°C)&#13;&#10;----------- Since FW version 1.10 -----------&#13;&#10;23 = KTY84-130 (Range: -40 ... 300°C)&#13;&#10;24 = KTY84-150 (Range: -40 ... 300°C)&#13;&#10;25 = PT100 (Range: -200 ... 150°C) in 1/100° Resolution"/>
		<Client Name="AI2_FilterFreq" Required="false" Internal="false" Comment="Cut off frequency for low pass filter&#13;&#10;0 ... 100 Hz&#13;&#10;1 ...  50 Hz&#13;&#10;2 ...  25 Hz&#13;&#10;3 ...  10 Hz&#13;&#10;4 ... Filter off.&#13;&#10;5 ...    1 Hz&#13;&#10;"/>
		<Client Name="AI2_Max" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI2_MeasureMethod" Required="false" Internal="false" Comment="0 = 2 wire measure method&#13;&#10;1 = 3 wire measure method"/>
		<Client Name="AI2_Min" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI3_Active" Required="false" Internal="false" DefValue="1" Comment="The channel can be activated/ deactived with this client.&#13;&#10;&#13;&#10;0 = Channel is deactivated. &#13;&#10;Channel LED is off at cable break.  &#13;&#10;&#13;&#10;1 = Channel is activated. &#13;&#10;Channel LED is flashing at cable break."/>
		<Client Name="AI3_Config" Required="false" Internal="false" Comment="With this client the sensor and its range can be selected.&#13;&#10; 0 = PT100  (Range: -200...+150°C)&#13;&#10; 1 = PT100  (Range: -200...+850°C)&#13;&#10; 2 = PT200  (Range: -200...+150°C)&#13;&#10; 3 = PT200  (Range: -200...+850°C)&#13;&#10; 4 = PT500  (Range: -200...+150°C)&#13;&#10; 5 = PT500  (Range: -200...+850°C)&#13;&#10; 6 = PT1000 (Range: -200...+150°C)&#13;&#10; 7 = PT1000 (Range: -200...+850°C)&#13;&#10; 8 = NI100  (Range: -60 ...+150°C)&#13;&#10; 9 = NI100  (Range: -60 ...+250°C)&#13;&#10;10 = NI1000 (Range: -60 ...+150°C)&#13;&#10;11 = NI1000 (Range: -60 ...+250°C)&#13;&#10;12 = Potentiometer (Range: 0 ... 250 Ohm)&#13;&#10;13 = Potentiometer (Range: 0 ... 500 Ohm)&#13;&#10;14 = Potentiometer (Range: 0 ...1000 Ohm)&#13;&#10;15 = Potentiometer (Range: 0 ...2500 Ohm)&#13;&#10;16 = Potentiometer (Range: 0 ...5000 Ohm)&#13;&#10;17 = KTY11-62  (Range: -50 ... 150°C)&#13;&#10;18 = KTY81-110 (Range: -55 ... 150°C)&#13;&#10;19 = KTY81-120 (Range: -55 ... 150°C)&#13;&#10;20 = KTY81-121 (Range: -55 ... 150°C)&#13;&#10;21 = KTY81-122 (Range: -55 ... 150°C)&#13;&#10;22 = KTY81-150 (Range: -55 ... 150°C)&#13;&#10;----------- Since FW version 1.10 -----------&#13;&#10;23 = KTY84-130 (Range: -40 ... 300°C)&#13;&#10;24 = KTY84-150 (Range: -40 ... 300°C)&#13;&#10;25 = PT100 (Range: -200 ... 150°C) in 1/100° Resolution"/>
		<Client Name="AI3_FilterFreq" Required="false" Internal="false" Comment="Cut off frequency for low pass filter&#13;&#10;0 ... 100 Hz&#13;&#10;1 ...  50 Hz&#13;&#10;2 ...  25 Hz&#13;&#10;3 ...  10 Hz&#13;&#10;4 ... Filter off.&#13;&#10;5 ...    1 Hz&#13;&#10;"/>
		<Client Name="AI3_Max" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI3_MeasureMethod" Required="false" Internal="false" Comment="0 = 2 wire measure method&#13;&#10;1 = 3 wire measure method"/>
		<Client Name="AI3_Min" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI4_Active" Required="false" Internal="false" DefValue="1" Comment="The channel can be activated/ deactived with this client.&#13;&#10;&#13;&#10;0 = Channel is deactivated. &#13;&#10;Channel LED is off at cable break.  &#13;&#10;&#13;&#10;1 = Channel is activated. &#13;&#10;Channel LED is flashing at cable break."/>
		<Client Name="AI4_Config" Required="false" Internal="false" Comment="With this client the sensor and its range can be selected.&#13;&#10; 0 = PT100  (Range: -200...+150°C)&#13;&#10; 1 = PT100  (Range: -200...+850°C)&#13;&#10; 2 = PT200  (Range: -200...+150°C)&#13;&#10; 3 = PT200  (Range: -200...+850°C)&#13;&#10; 4 = PT500  (Range: -200...+150°C)&#13;&#10; 5 = PT500  (Range: -200...+850°C)&#13;&#10; 6 = PT1000 (Range: -200...+150°C)&#13;&#10; 7 = PT1000 (Range: -200...+850°C)&#13;&#10; 8 = NI100  (Range: -60 ...+150°C)&#13;&#10; 9 = NI100  (Range: -60 ...+250°C)&#13;&#10;10 = NI1000 (Range: -60 ...+150°C)&#13;&#10;11 = NI1000 (Range: -60 ...+250°C)&#13;&#10;12 = Potentiometer (Range: 0 ... 250 Ohm)&#13;&#10;13 = Potentiometer (Range: 0 ... 500 Ohm)&#13;&#10;14 = Potentiometer (Range: 0 ...1000 Ohm)&#13;&#10;15 = Potentiometer (Range: 0 ...2500 Ohm)&#13;&#10;16 = Potentiometer (Range: 0 ...5000 Ohm)&#13;&#10;17 = KTY11-62  (Range: -50 ... 150°C)&#13;&#10;18 = KTY81-110 (Range: -55 ... 150°C)&#13;&#10;19 = KTY81-120 (Range: -55 ... 150°C)&#13;&#10;20 = KTY81-121 (Range: -55 ... 150°C)&#13;&#10;21 = KTY81-122 (Range: -55 ... 150°C)&#13;&#10;22 = KTY81-150 (Range: -55 ... 150°C)&#13;&#10;----------- Since FW version 1.10 -----------&#13;&#10;23 = KTY84-130 (Range: -40 ... 300°C)&#13;&#10;24 = KTY84-150 (Range: -40 ... 300°C)&#13;&#10;25 = PT100 (Range: -200 ... 150°C) in 1/100° Resolution"/>
		<Client Name="AI4_FilterFreq" Required="false" Internal="false" Comment="Cut off frequency for low pass filter&#13;&#10;0 ... 100 Hz&#13;&#10;1 ...  50 Hz&#13;&#10;2 ...  25 Hz&#13;&#10;3 ...  10 Hz&#13;&#10;4 ... Filter off.&#13;&#10;5 ...    1 Hz&#13;&#10;"/>
		<Client Name="AI4_Max" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
		<Client Name="AI4_MeasureMethod" Required="false" Internal="false" Comment="0 = 2 wire measure method&#13;&#10;1 = 3 wire measure method"/>
		<Client Name="AI4_Min" Required="false" Internal="false" Comment="The scale of the analog input can be selected by this client as initvalue!&#13;&#10;&#13;&#10;Only available at potentiometer measurements&#13;&#10;When both limits are zero, the scale is deactivated."/>
	</Channels>
	<RevDoku>
		<Owner Company="Sigmatek" Author="EisMic"/>
		<Dokumentation Revision="1.20" Date="30.09.2019" Author="LazJos" Company="Sigmatek" Description="Added support for HWAlarms."/>
		<Dokumentation Revision="1.19" Date="02.09.2019" Author="LanSte" Company="Sigmatek" Description="Added support for low pass filter with cut off frequency 1Hz."/>
		<Dokumentation Revision="1.18" Date="09.01.2019" Author="FurDom" Company="Sigmatek" Description="Added function for Spi Write in SdiasBase class."/>
		<Dokumentation Revision="1.17" Date="08.06.2018" Author="RamAnd" Company="Sigmatek" Description="LASAL Hardware Description (.lhd) file has been updated."/>
		<Dokumentation Revision="1.16" Date="14.03.2018" Author="FurDom" Company="Sigmatek" Description="Corrected query whether scaling is required for analog value AI1 or not."/>
		<Dokumentation Revision="1.15" Date="23.01.2018" Author="RamAnd" Company="Sigmatek" Description="Log messages have been standardized for easier maintenance, easier use in any class and to allow spam filtering. Code for the logging functions is now only located in HwControl."/>
		<Dokumentation Revision="1.14" Date="11.10.2017" Author="FurDom" Company="Sigmatek" Description="Added Flag &quot;PotiConfig&quot; for check if the AIx is in potentiometer mode&#13;&#10;Added Flag &quot;ScaleAIx&quot; for check if a new calculation is necessary for AI1-6 -&gt; Realtime optimization. &#13;&#10;New calculation if Client AI_Min or AI_Max is not default.&#13;&#10;delet function &quot;CalcValue&quot; -&gt; value is calculated in realtime task"/>
		<Dokumentation Revision="1.13" Date="16.05.2017" Author="RamAnd" Company="Sigmatek" Description="When adding an SDO (i.e. via ReadSPIData) from background priority it was possible that the adding process got interrupted by receiving the answer to this SDO which is handled in cyclic priority. In the error case the answer was unexpected and therefore ignored. Then the class signals a timeout while waiting for the answer, which already arrived before waiting for it. Added mutex and changed instruction order to prevent this error."/>
		<Dokumentation Revision="1.12" Date="12.07.2016" Author="SeiChr" Company="Sigmatek" Description="Added Values for the total Current calculation. SA 31571"/>
		<Dokumentation Revision="1.11" Date="01.03.2016" Author="EisMic" Company="Sigmatek" Description="Corrected BoundExceed Error in base class at Write method of LEDControl Server when Place = LSL_DEACTIVATED."/>
		<Dokumentation Revision="1.10" Date="23.02.2016" Author="PieSte" Company="Sigmatek" Description="Add support for min range greater max range."/>
		<Dokumentation Revision="1.9" Date="18.06.2015" Author="EisMic" Company="Sigmatek" Description="The servers FPGAVersion, SerialNo, Device ID and status and input servers are now not reset anymore when the module is disconnected."/>
		<Dokumentation Revision="1.8" Date="17.06.2015" Author="EisMic" Company="Sigmatek" Description="Added Support for 3 new sensor types  (requires firmwareversion 1.10 or higher)."/>
		<Dokumentation Revision="1.7" Date="08.06.2015" Author="PieSte" Company="Sigmatek" Description="Changes at Lhd-file for &quot;TypeId&quot; were not taken over."/>
		<Dokumentation Revision="1.6" Date="21.05.2015" Author="PieSte" Company="Sigmatek" Description="Corrected spelling attribute &quot;TypeId&quot; at lhd-file."/>
		<Dokumentation Revision="1.5" Date="16.04.2015" Author="EisMic&#13;&#10;LanSte" Company="Sigmatek" Description="Added support for visualisation in graphical hardware editor.&#13;&#10;Added support for calculating resources for graphical hardware editor."/>
		<Dokumentation Revision="1.4" Date="17.03.2015" Author="RamAnd" Company="Sigmatek" Description="Added HW Version for sdias clients."/>
		<Dokumentation Revision="1.3" Date="11.02.2015" Author="PieSte" Company="Sigmatek" Description="Corrected read spi data for hardwaretree in methode GetSPIDataFromID from baseclass.&#13;&#10;Added exit condition for spi access from baseclass in methode ReceiveSDOResponse."/>
		<Dokumentation Revision="1.2" Date="18.11.2014" Author="PieSte" Company="Sigmatek" Description="Added possibility  to read more data from spi flash then one sdo access.&#13;&#10;Set methode GetDeviceID to global.&#13;&#10;Add methode to calculate checksum of spi flash."/>
		<Dokumentation Revision="1.1" Date="04.07.2014" Author="EisMic" Company="Sigmatek" Description="Added support for reading hardware diagnosis and hardwaretree entry."/>
		<Dokumentation Revision="1.0" Date="02.07.2014" Author="EisMic" Company="Sigmatek" Description="First library version."/>
	</RevDoku>
	<Network Name="AI043">
		<!-- List of Components in this network -->
		<Components>
			<Object
				Name       = "_base"
				GUID       = "{6154EFA7-C251-4781-B984-6F75854A10A7}"
				Class      = "SdiasBase"
				Position   = "(218,120)"
				Visualized = "true">
				<Channels>
					<Server Name="ClassState"/>
					<Server Name="DeviceID"/>
					<Server Name="FPGAVersion"/>
					<Server Name="HwVersion"/>
					<Server Name="LEDControl" Value="0"/>
					<Server Name="RetryCounter"/>
					<Server Name="SDOState"/>
					<Server Name="SerialNo"/>
					<Client Name="Place" Value="0"/>
					<Client Name="Required" Value="1"/>
					<Client Name="SdiasIn"/>
					<Client Name="ToStdLib"/>
				</Channels>
			</Object>
		</Components>
		<Comments>
		</Comments>
		<!-- List of Connections in this network -->
		<Connections>
			<Connection Source="this.ClassState" Destination="_base.ClassState" Vertices="(804,210),(632,210),"/>
			<Connection Source="this.DeviceID" Destination="_base.DeviceID" Vertices="(804,270),(632,270),"/>
			<Connection Source="this.FPGAVersion" Destination="_base.FPGAVersion" Vertices="(804,330),(632,330),"/>
			<Connection Source="this.SerialNo" Destination="_base.SerialNo" Vertices="(804,450),(632,450),"/>
			<Connection Source="this.RetryCounter" Destination="_base.RetryCounter" Vertices="(804,510),(632,510),"/>
			<Connection Source="this.LEDControl" Destination="_base.LEDControl" Vertices="(804,570),(632,570),"/>
			<Connection Source="_base.Place" Destination="this.Place" Vertices="(218,270),(38,270),"/>
			<Connection Source="_base.SdiasIn" Destination="this.SdiasIn" Vertices="(218,210),(38,210),"/>
			<Connection Source="_base.Required" Destination="this.Required" Vertices="(218,330),(38,330),"/>
			<Connection Source="this.HwVersion" Destination="_base.HwVersion" Vertices="(804,390),(632,390),"/>
		</Connections>
		<!-- Headerfiles -->
		<Options>
		</Options>
	</Network>
</Class>
*)
#pragma using SdiasBase

AI043 : CLASS
: SdiasBase
	TYPE
#pragma pack(push, 1)
	  t_AccessReadData : STRUCT
	    pStateByte : t_SDIAS_pStateByte;
	    pControlByte : t_SDIAS_pControlByte;
	    AccessHandle : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_Cablebreak : BSINT
	  [
	    1 CableBreakAI1,
	    2 CableBreakAI2,
	    3 CableBreakAI3,
	    4 CableBreakAI4,
	  ];
	  t_SpecialPurpose : BSINT
	  [
	    1 PmbModus,
	    2 BootloaderUpdateRequest,
	  ];
#pragma pack(push, 1)
	  t_Selection : STRUCT
	    Ch1_Conf : SINT;
	    Ch2_Conf : SINT;
	    Ch3_Conf : SINT;
	    Ch4_Conf : SINT;
	    Ch_Measuremethod : BSINT
	    [
	      1 Ch1_Measuremethod,
	      2 Ch2_Measuremethod,
	      3 Ch3_Measuremethod,
	      4 Ch4_Measuremethod,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_StandardModus : STRUCT
	    Selection : t_Selection;
	    AI1_FilterFreq : UINT;
	    AI2_FilterFreq : UINT;
	    AI3_FilterFreq : UINT;
	    AI4_FilterFreq : UINT;
	    ChannelActive : BSINT
	    [
	      1 Active_AI1,
	      2 Active_AI2,
	      3 Active_AI3,
	      4 Active_AI4,
	    ];
	    ByteCounter : SINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_CfgFirmware : STRUCT
	    CRC : UINT;
	    DataLength : UINT;
	    Info : t_SpecialPurpose;
	    Reserved : UINT;
	    StandardModus : t_StandardModus;
	  END_STRUCT;
#pragma pack(pop)
	  t_InitSSW :
	  (
	    _InitVariables,
	    _ConfigModule,
	    _Finish,
	    _ReadState,
	    _InitError
	  )$UDINT;
	  t_Range : BSINT
	  [
	    1 OverRangeAI1,
	    2 OverRangeAI2,
	    3 OverRangeAI3,
	    4 OverRangeAI4,
	    5 UnderRangeAI1,
	    6 UnderRangeAI2,
	    7 UnderRangeAI3,
	    8 UnderRangeAI4,
	  ];
#pragma pack(push, 1)
	  t_ReadData : STRUCT
	    Status : t_b_SdiasFWState;
	    AnalogIn1 : INT;
	    AnalogIn2 : INT;
	    AnalogIn3 : INT;
	    AnalogIn4 : INT;
	    CableBreak : t_Cablebreak;
	    Range : t_Range;
	    RawValueAnalogIn1 : UINT;
	    RawValueAnalogIn2 : UINT;
	    RawValueAnalogIn3 : UINT;
	    RawValueAnalogIn4 : UINT;
	    RawValueAnalogIn5 : UINT;
	    RawValueAnalogIn6 : UINT;
	    RawValueAnalogIn7 : UINT;
	    RawValueAnalogIn8 : UINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_ResponseState :
	  (
	    _idle,
	    _wait,
	    _valid
	  )$UDINT;
#pragma pack(push, 1)
	  t_StateFirmware : STRUCT
	    CRC : UINT;
	    DataLength : UINT;
	    FirmwareVersion : UINT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	FirmwareVersion 	: SvrCh_HDINT;
	FWErrorBits 	: SvrCh_t_s_SdiasFWStateStandard_PTofCls_SdiasBase;
	AI1 	: SvrCh_DINT;
	AI2 	: SvrCh_DINT;
	AI3 	: SvrCh_DINT;
	AI4 	: SvrCh_DINT;
	CableBreak 	: SvrCh_BDINT;
	Range 	: SvrCh_BDINT;
  //Clients:
	AI1_Config 	: CltCh_DINT;
	AI1_Active 	: CltCh_DINT;
	AI1_MeasureMethod 	: CltCh_DINT;
	AI1_FilterFreq 	: CltCh_UDINT;
	AI1_Min 	: CltCh_DINT;
	AI1_Max 	: CltCh_DINT;
	AI2_Config 	: CltCh_DINT;
	AI2_Active 	: CltCh_DINT;
	AI2_MeasureMethod 	: CltCh_DINT;
	AI2_FilterFreq 	: CltCh_UDINT;
	AI2_Min 	: CltCh_DINT;
	AI2_Max 	: CltCh_DINT;
	AI3_Config 	: CltCh_DINT;
	AI3_Active 	: CltCh_DINT;
	AI3_MeasureMethod 	: CltCh_DINT;
	AI3_FilterFreq 	: CltCh_UDINT;
	AI3_Min 	: CltCh_DINT;
	AI3_Max 	: CltCh_DINT;
	AI4_Config 	: CltCh_DINT;
	AI4_Active 	: CltCh_DINT;
	AI4_MeasureMethod 	: CltCh_DINT;
	AI4_FilterFreq 	: CltCh_UDINT;
	AI4_Min 	: CltCh_DINT;
	AI4_Max 	: CltCh_DINT;
  //Variables:
		aAIRange : ARRAY [0..AI043_NUMBER_OF_ANALOG_IN-1] OF DINT;

		udSDOTimeout 	: UDINT;
		pReadData 	: ^t_ReadData;
		eInitSSW 	: t_InitSSW;
		eResponseState 	: t_ResponseState;
		sCfgFirmware 	: t_CfgFirmware;
		eInitSSWErrorStep 	: t_InitSSW;
		sStateFirmware 	: t_StateFirmware;
		bsInvalidConfig : BSINT
		[
		  1 AI1Invalid,
		  2 AI2Invalid,
		  3 AI3Invalid,
		  4 AI4Invalid,
		];

		ScaleAI1 	: BOOL;
		ScaleAI2 	: BOOL;
		ScaleAI3 	: BOOL;
		ScaleAI4 	: BOOL;
		PotiConfigAI1 	: BOOL;
		PotiConfigAI2 	: BOOL;
		PotiConfigAI3 	: BOOL;
		PotiConfigAI4 	: BOOL;
		ScaleMax_AI1 	: DINT;
		ScaleMax_AI2 	: DINT;
		ScaleMax_AI3 	: DINT;
		ScaleMax_AI4 	: DINT;
  //Functions:
	
	FUNCTION AI043
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
				//! <Function Comment="Realtime Update Methode which runs in PreScan." Name="UpdateRt"/>
	FUNCTION VIRTUAL GLOBAL UpdateRt;
				//! <Function Comment="Methode is called if this Module gets connected." Name="ConnectEvent"/>
	FUNCTION VIRTUAL GLOBAL ConnectEvent;
				//! <Function Comment="Methode should be used to run a Statemachine to Initialize the Module." Name="InitModule"/>
	FUNCTION VIRTUAL GLOBAL InitModule
		VAR_OUTPUT
			eModuleInitState 	: iprStates;			//! <Variable Comment="Return BUSY until the Initialisation is finished." Name="InitModule.eModuleInitState"/>
		END_VAR;
				//! <Function Comment="This Methode should be used, to check the DeviceID of the Module." Name="CheckDeviceID"/>
	FUNCTION VIRTUAL GLOBAL CheckDeviceID
		VAR_INPUT
			udID2Check 	: UDINT;			//! <Variable Comment="Device ID of connected Module." Name="CheckDeviceID.udID2Check"/>
		END_VAR
		VAR_OUTPUT
			bIsOK 	: BOOL;			//! <Variable Comment="FALSE = Wrong DeviceID for Module&#13;&#10;TRUE  = DeviceID of Module is correct" Name="CheckDeviceID.bIsOK"/>
		END_VAR;
				//! <Function Comment="Methode to receive the Response in case of SDO-Communication." Name="ReceiveSDOResponse"/>
	FUNCTION VIRTUAL ReceiveSDOResponse
		VAR_INPUT
			eCommand 	: t_SDIAS_SDO_Cmd;			//! <Variable Comment="Type of SDO-Command" Name="ReceiveSDOResponse.eCommand"/>
			hOffset 	: HINT;			//! <Variable Comment="Address-Offset in Module." Name="ReceiveSDOResponse.hOffset"/>
			usLength 	: USINT;			//! <Variable Comment="Length of Data." Name="ReceiveSDOResponse.usLength"/>
			eResult 	: iprStates;			//! <Variable Comment="State of SDO-Communication." Name="ReceiveSDOResponse.eResult"/>
			pResponseBuffer 	: ^USINT;			//! <Variable Comment="Pointer of ResponseBuffer, where the SDO-Data is located." Name="ReceiveSDOResponse.pResponseBuffer"/>
			ResponseLength 	: USINT;			//! <Variable Comment="Size of the ResponseBuffer." Name="ReceiveSDOResponse.ResponseLength"/>
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;			//! <Variable Comment="Indicates if the Methode was successful." Name="ReceiveSDOResponse.ret_code"/>
		END_VAR;
	
	FUNCTION VIRTUAL GetTaskCfg
		VAR_OUTPUT
			TaskCfg 	: BDINT;			//! <Variable Comment="Select which tasks will be available for this module:&#13;&#10;Bit0..Realtime PreScan&#13;&#10;Bit1..Realtime PostScan&#13;&#10;Bit2..Cyclic&#13;&#10;&#13;&#10;e.g. if only realtime postscan is needed:&#13;&#10;2#010" Name="GetTaskCfg.TaskCfg"/>
		END_VAR;
	
	FUNCTION VIRTUAL GetDeviceID
		VAR_OUTPUT
			output 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetFWVersion
		VAR_INPUT
			pData 	: ^CHAR;
			Length 	: UDINT;
		END_VAR;
				//! <Function Comment="Lookup-Methode to get the Frequency-Setting for the uC." Name="SetFrequency"/>
	FUNCTION SetFrequency
		VAR_INPUT
			ClientValue 	: UDINT;
		END_VAR
		VAR_OUTPUT
			Frequency 	: UINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

//}}LSL_DECLARATION


FUNCTION GLOBAL TAB AI043::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_AI043
1$UINT, 20$UINT, (SIZEOF(::AI043))$UINT, 
8$UINT, 24$UINT, 0$UINT, 
TO_UDINT(1698489890), "AI043", //Class
TO_UDINT(3175101883), "SdiasBase", 1$UINT, 60$UINT, //Baseclass
//Servers:
(::AI043.FirmwareVersion.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(389440282), "FirmwareVersion", 
(::AI043.FWErrorBits.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3888132073), "FWErrorBits", 
(::AI043.AI1.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4269591187), "AI1", 
(::AI043.AI2.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1735760681), "AI2", 
(::AI043.AI3.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(275950527), "AI3", 
(::AI043.AI4.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2383822364), "AI4", 
(::AI043.CableBreak.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3580028836), "CableBreak", 
(::AI043.Range.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1691588857), "Range", 
//Clients:
(::AI043.AI1_Config.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3918082640), "AI1_Config", 
(::AI043.AI1_Active.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1981669678), "AI1_Active", 
(::AI043.AI1_MeasureMethod.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3587939892), "AI1_MeasureMethod", 
(::AI043.AI1_FilterFreq.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1182883678), "AI1_FilterFreq", 
(::AI043.AI1_Min.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2432037533), "AI1_Min", 
(::AI043.AI1_Max.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2901986756), "AI1_Max", 
(::AI043.AI2_Config.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1728460211), "AI2_Config", 
(::AI043.AI2_Active.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(4170376909), "AI2_Active", 
(::AI043.AI2_MeasureMethod.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3299275853), "AI2_MeasureMethod", 
(::AI043.AI2_FilterFreq.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(824151470), "AI2_FilterFreq", 
(::AI043.AI2_Min.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3612706893), "AI2_Min", 
(::AI043.AI2_Max.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3948459796), "AI2_Max", 
(::AI043.AI3_Config.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2880189741), "AI3_Config", 
(::AI043.AI3_Active.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(876144211), "AI3_Active", 
(::AI043.AI3_MeasureMethod.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2103259045), "AI3_MeasureMethod", 
(::AI043.AI3_FilterFreq.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2864366017), "AI3_FilterFreq", 
(::AI043.AI3_Min.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3929383421), "AI3_Min", 
(::AI043.AI3_Max.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3594034852), "AI3_Max", 
(::AI043.AI4_Config.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2708028468), "AI4_Config", 
(::AI043.AI4_Active.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1056829258), "AI4_Active", 
(::AI043.AI4_MeasureMethod.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3864797375), "AI4_MeasureMethod", 
(::AI043.AI4_FilterFreq.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3726780494), "AI4_FilterFreq", 
(::AI043.AI4_Min.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1477803501), "AI4_Min", 
(::AI043.AI4_Max.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1679311540), "AI4_Max", 
END_FUNCTION


#define USER_CNT_AI043 25

TYPE
	_LSL_STD_VMETH	: STRUCT
			CmdTable	: CMDMETH;
			UserFcts	: ARRAY[0..USER_CNT_AI043] OF ^Void;
	END_STRUCT;
END_TYPE

FUNCTION AI043::@STD
	VAR_OUTPUT
		ret_code	: CONFSTATES;
	END_VAR
	VAR
		vmt	: _LSL_STD_VMETH;
		nCmdSize	: UINT;
	END_VAR

	ret_code	:= SdiasBase::@STD();
	IF ret_code <> C_OK THEN
		RETURN;
	END_IF;
	nCmdSize		:= SdiasBase::ClassState.pMeth^.nCmds$UINT*SIZEOF(pVoid) + CMDMETH.Init;

	_memcpy((#vmt.CmdTable)$^USINT, SdiasBase::ClassState.pMeth, nCmdSize);
	vmt.CmdTable.nCmds		:= nSTDCMD + USER_CNT_AI043;
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #UpdateRt();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[5]		:= #ConnectEvent();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[7]		:= #InitModule();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[8]		:= #CheckDeviceID();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[9]		:= #ReceiveSDOResponse();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[13]		:= #GetTaskCfg();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[14]		:= #GetDeviceID();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[15]		:= #GetFWVersion();

#pragma warning (default : 74)
	SdiasBase::ClassState.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF SdiasBase::ClassState.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= AI043();

END_FUNCTION

//{{LSL_IMPLEMENTATION
FUNCTION VIRTUAL GLOBAL AI043::UpdateRt
  VAR
    TempReadData : t_ReadData;
  END_VAR

  TempReadData := pReadData^;

  // set Status
  FWErrorBits.ErrorBits := TempReadData.Status;
  CableBreak  := TempReadData.CableBreak and AI043_CABLE_BREAK_MASK;  //mask Cable break Bits
  Range := TempReadData.Range;
  
 //**********************************************************************************************************************************************************
  if TempReadData.CableBreak.CableBreakAI1 | TempReadData.Range.OverRangeAI1 | TempReadData.Range.UnderRangeAI1 then
    AI1 := AI043_INVALID_VALUE;
  else
    if PotiConfigAI1 then
      if ScaleAI1 then
        AI1 := AI1_Min + ((aAIRange[0] * TempReadData.AnalogIn1$UINT) / (ScaleMax_AI1));
      else
        AI1 := TempReadData.AnalogIn1$UINT;
      end_if;      
    else
      AI1 := TempReadData.AnalogIn1;
    end_if;      
  end_if;
  
//**********************************************************************************************************************************************************
  if TempReadData.CableBreak.CableBreakAI2 | TempReadData.Range.OverRangeAI2 | TempReadData.Range.UnderRangeAI2 then
    AI2 := AI043_INVALID_VALUE;
  else  
    if PotiConfigAI2 then
      if ScaleAI2 then
        AI2 := AI2_Min + ((aAIRange[1] * TempReadData.AnalogIn2$UINT) / (ScaleMax_AI2));
      else
        AI2 := TempReadData.AnalogIn2$UINT;
      end_if;      
    else
      AI2 := TempReadData.AnalogIn2;
    end_if;            
  end_if;
  
//**********************************************************************************************************************************************************
  if TempReadData.CableBreak.CableBreakAI3 | TempReadData.Range.OverRangeAI3 | TempReadData.Range.UnderRangeAI3 then
    AI3 := AI043_INVALID_VALUE;
  else 
    if PotiConfigAI3 then
      if ScaleAI3 then
        AI3 := AI3_Min + ((aAIRange[2] * TempReadData.AnalogIn3$UINT) / (ScaleMax_AI3));
      else
        AI3 := TempReadData.AnalogIn3$UINT;
      end_if;      
    else
      AI3 := TempReadData.AnalogIn3;
    end_if;   
  end_if;
  
//**********************************************************************************************************************************************************
  if TempReadData.CableBreak.CableBreakAI4 | TempReadData.Range.OverRangeAI4 | TempReadData.Range.UnderRangeAI4 then
    AI4 := AI043_INVALID_VALUE;
  else
    if PotiConfigAI4 then
      if ScaleAI4 then
        AI4 := AI4_Min + ((aAIRange[3] * TempReadData.AnalogIn4$UINT) / (ScaleMax_AI4));
      else
        AI4 := TempReadData.AnalogIn4$UINT;
      end_if;      
    else
      AI4 := TempReadData.AnalogIn4;
    end_if;      
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL AI043::ConnectEvent
  
 //  start the accesses on the SDIAS (initialize the control byte in the DPRAM)
  if DefaultAccesses.ReadAccess.pControlByte then
    pReadData := DefaultAccesses.ReadAccess.pData$^t_ReadData;

    DefaultAccesses.ReadAccess.pControlByte^.EnableDO := TRUE;
  else
    eInitState := _DOHandleInvalid;
    return;
  end_if;

  eInitSSW := _InitVariables;
  eResponseState := _idle;
  eInitState    := _NotInitialized;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL AI043::InitModule
	VAR_OUTPUT
		eModuleInitState 	: iprStates;
	END_VAR
  VAR
    TmpRetcode      : iprStates;
  END_VAR
  
  eModuleInitState := BUSY;

  case eInitSSW of
//**********************************************************************************************************************************************************
    _InitVariables:
    
      //Read Clients
      AI1_Config := AI1_Config.Read();
      AI2_Config := AI2_Config.Read();
      AI3_Config := AI3_Config.Read();
      AI4_Config := AI4_Config.Read();
      
      AI1_Active := AI1_Active.Read();
      AI2_Active := AI2_Active.Read();
      AI3_Active := AI3_Active.Read();
      AI4_Active := AI4_Active.Read();
      
      AI1_MeasureMethod := AI1_MeasureMethod.Read();
      AI2_MeasureMethod := AI2_MeasureMethod.Read();
      AI3_MeasureMethod := AI3_MeasureMethod.Read();
      AI4_MeasureMethod := AI4_MeasureMethod.Read(); 
      
      AI1_FilterFreq := AI1_FilterFreq.Read();
      AI2_FilterFreq := AI2_FilterFreq.Read();
      AI3_FilterFreq := AI3_FilterFreq.Read();
      AI4_FilterFreq := AI4_FilterFreq.Read();
      
      AI1_Min := AI1_Min.Read();
      AI1_Max := AI1_Max.Read();
      AI2_Min := AI2_Min.Read();
      AI2_Max := AI2_Max.Read();
      AI3_Min := AI3_Min.Read();
      AI3_Max := AI3_Max.Read();
      AI4_Min := AI4_Min.Read();
      AI4_Max := AI4_Max.Read();
      
      //check if calculation is necessary
      if ((AI1_Config = 12) & ((AI1_Max <> AI043_FIRMWARE_MAX_CFG12) | (AI1_Min <> AI043_FIRMWARE_MIN)))
      | ((AI1_Config = 13) & ((AI1_Max <> AI043_FIRMWARE_MAX_CFG13) | (AI1_Min <> AI043_FIRMWARE_MIN)))
      | ((AI1_Config = 14) & ((AI1_Max <> AI043_FIRMWARE_MAX_CFG14) | (AI1_Min <> AI043_FIRMWARE_MIN)))
      | ((AI1_Config = 15) & ((AI1_Max <> AI043_FIRMWARE_MAX_CFG15) | (AI1_Min <> AI043_FIRMWARE_MIN)))
      | ((AI1_Config = 16) & ((AI1_Max <> AI043_FIRMWARE_MAX_CFG16) | (AI1_Min <> AI043_FIRMWARE_MIN))) then
        if AI1_Min = 0 & AI1_Max = 0 then
          //no scale
          ScaleAI1 := FALSE;         
        else
          ScaleAI1 := TRUE;        
        end_if;     
      end_if;

      if ((AI2_Config = 12) & ((AI2_Max <> AI043_FIRMWARE_MAX_CFG12) | (AI2_Min <> AI043_FIRMWARE_MIN)))
      | ((AI2_Config = 13) & ((AI2_Max <> AI043_FIRMWARE_MAX_CFG13) | (AI2_Min <> AI043_FIRMWARE_MIN)))
      | ((AI2_Config = 14) & ((AI2_Max <> AI043_FIRMWARE_MAX_CFG14) | (AI2_Min <> AI043_FIRMWARE_MIN)))
      | ((AI2_Config = 15) & ((AI2_Max <> AI043_FIRMWARE_MAX_CFG15) | (AI2_Min <> AI043_FIRMWARE_MIN)))
      | ((AI2_Config = 16) & ((AI2_Max <> AI043_FIRMWARE_MAX_CFG16) | (AI2_Min <> AI043_FIRMWARE_MIN))) then
        if AI2_Min = 0 & AI2_Max = 0 then
          //no scale
          ScaleAI2 := FALSE;           
        else
          ScaleAI2 := TRUE;         
        end_if;     
      end_if;

      if ((AI3_Config = 12) & ((AI3_Max <> AI043_FIRMWARE_MAX_CFG12) | (AI3_Min <> AI043_FIRMWARE_MIN)))
      | ((AI3_Config = 13) & ((AI3_Max <> AI043_FIRMWARE_MAX_CFG13) | (AI3_Min <> AI043_FIRMWARE_MIN)))
      | ((AI3_Config = 14) & ((AI3_Max <> AI043_FIRMWARE_MAX_CFG14) | (AI3_Min <> AI043_FIRMWARE_MIN)))
      | ((AI3_Config = 15) & ((AI3_Max <> AI043_FIRMWARE_MAX_CFG15) | (AI3_Min <> AI043_FIRMWARE_MIN)))
      | ((AI3_Config = 16) & ((AI3_Max <> AI043_FIRMWARE_MAX_CFG16) | (AI3_Min <> AI043_FIRMWARE_MIN))) then
        if AI3_Min = 0 & AI3_Max = 0 then
          //no scale
          ScaleAI3 := FALSE;        
        else
          ScaleAI3 := TRUE;        
        end_if;      
      end_if;
      
      if ((AI4_Config = 12) & ((AI4_Max <> AI043_FIRMWARE_MAX_CFG12) | (AI4_Min <> AI043_FIRMWARE_MIN)))
      | ((AI4_Config = 13) & ((AI4_Max <> AI043_FIRMWARE_MAX_CFG13) | (AI4_Min <> AI043_FIRMWARE_MIN)))
      | ((AI4_Config = 14) & ((AI4_Max <> AI043_FIRMWARE_MAX_CFG14) | (AI4_Min <> AI043_FIRMWARE_MIN)))
      | ((AI4_Config = 15) & ((AI4_Max <> AI043_FIRMWARE_MAX_CFG15) | (AI4_Min <> AI043_FIRMWARE_MIN)))
      | ((AI4_Config = 16) & ((AI4_Max <> AI043_FIRMWARE_MAX_CFG16) | (AI4_Min <> AI043_FIRMWARE_MIN))) then
        if AI4_Min = 0 & AI4_Max = 0 then
          //no scale
          ScaleAI4 := FALSE;
        else
          ScaleAI4 := TRUE;         
        end_if;     
      end_if;      
      
      //check sensor config      
      case AI1_Config of      
        12: 
          ScaleMax_AI1 := AI043_FIRMWARE_MAX_CFG12;
          PotiConfigAI1 := TRUE;
        13:
          ScaleMax_AI1 := AI043_FIRMWARE_MAX_CFG13;
          PotiConfigAI1 := TRUE;
        14:
          ScaleMax_AI1 := AI043_FIRMWARE_MAX_CFG14;
          PotiConfigAI1 := TRUE;
        15:
          ScaleMax_AI1 := AI043_FIRMWARE_MAX_CFG15;
          PotiConfigAI1 := TRUE;
        16: 
          ScaleMax_AI1 := AI043_FIRMWARE_MAX_CFG16;
          PotiConfigAI1 := TRUE;
        else
          PotiConfigAI1 := FALSE;        
      end_case;
      
      case AI2_Config of      
        12: 
          ScaleMax_AI2 := AI043_FIRMWARE_MAX_CFG12;
          PotiConfigAI2 := TRUE;
        13:
          ScaleMax_AI2 := AI043_FIRMWARE_MAX_CFG13;
          PotiConfigAI2 := TRUE;
        14:
          ScaleMax_AI2 := AI043_FIRMWARE_MAX_CFG14;
          PotiConfigAI2 := TRUE;
        15:
          ScaleMax_AI2 := AI043_FIRMWARE_MAX_CFG15;
          PotiConfigAI2 := TRUE;
        16: 
          ScaleMax_AI2 := AI043_FIRMWARE_MAX_CFG16;
          PotiConfigAI2 := TRUE;
        else
          PotiConfigAI2 := FALSE;
      end_case;       

      case AI3_Config of      
        12: 
          ScaleMax_AI3 := AI043_FIRMWARE_MAX_CFG12;
          PotiConfigAI3 := TRUE;
        13:
          ScaleMax_AI3 := AI043_FIRMWARE_MAX_CFG13;
          PotiConfigAI3 := TRUE;
        14:
          ScaleMax_AI3 := AI043_FIRMWARE_MAX_CFG14;
          PotiConfigAI3 := TRUE;
        15:
          ScaleMax_AI3 := AI043_FIRMWARE_MAX_CFG15;
          PotiConfigAI3 := TRUE;
        16: 
          ScaleMax_AI3 := AI043_FIRMWARE_MAX_CFG16;
          PotiConfigAI3 := TRUE;
        else
          PotiConfigAI3 := FALSE;
      end_case;

      case AI4_Config of      
        12: 
          ScaleMax_AI4 := AI043_FIRMWARE_MAX_CFG12;
          PotiConfigAI4 := TRUE;
        13:
          ScaleMax_AI4 := AI043_FIRMWARE_MAX_CFG13;
          PotiConfigAI4 := TRUE;
        14:
          ScaleMax_AI4 := AI043_FIRMWARE_MAX_CFG14;
          PotiConfigAI4 := TRUE;
        15:
          ScaleMax_AI4 := AI043_FIRMWARE_MAX_CFG15;
          PotiConfigAI4 := TRUE;
        16: 
          ScaleMax_AI4 := AI043_FIRMWARE_MAX_CFG16;
          PotiConfigAI4 := TRUE;
        else
          PotiConfigAI4 := FALSE;
      end_case;      
      
      //Calculate Range 
      aAIRange[0] := AI1_Max - AI1_Min;
      aAIRange[1] := AI2_Max - AI2_Min;
      aAIRange[2] := AI3_Max - AI3_Min;
      aAIRange[3] := AI4_Max - AI4_Min;
            
      sCfgFirmware.StandardModus.Selection.Ch1_Conf := AI1_Config$SINT;
      sCfgFirmware.StandardModus.Selection.Ch2_Conf := AI2_Config$SINT;
      sCfgFirmware.StandardModus.Selection.Ch3_Conf := AI3_Config$SINT;
      sCfgFirmware.StandardModus.Selection.Ch4_Conf := AI4_Config$SINT;
      
      sCfgFirmware.StandardModus.ChannelActive.Active_AI1 := AI1_Active$BOOL;
      sCfgFirmware.StandardModus.ChannelActive.Active_AI2 := AI2_Active$BOOL;
      sCfgFirmware.StandardModus.ChannelActive.Active_AI3 := AI3_Active$BOOL;
      sCfgFirmware.StandardModus.ChannelActive.Active_AI4 := AI4_Active$BOOL;
      
      sCfgFirmware.StandardModus.Selection.Ch_Measuremethod.Ch1_Measuremethod := AI1_MeasureMethod$BOOL;
      sCfgFirmware.StandardModus.Selection.Ch_Measuremethod.Ch2_Measuremethod := AI2_MeasureMethod$BOOL;
      sCfgFirmware.StandardModus.Selection.Ch_Measuremethod.Ch3_Measuremethod := AI3_MeasureMethod$BOOL;
      sCfgFirmware.StandardModus.Selection.Ch_Measuremethod.Ch4_Measuremethod := AI4_MeasureMethod$BOOL;
      
      //Config Frequency
      sCfgFirmware.StandardModus.AI1_FilterFreq := SetFrequency(AI1_FilterFreq);
      sCfgFirmware.StandardModus.AI2_FilterFreq := SetFrequency(AI2_FilterFreq);
      sCfgFirmware.StandardModus.AI3_FilterFreq := SetFrequency(AI3_FilterFreq);
      sCfgFirmware.StandardModus.AI4_FilterFreq := SetFrequency(AI4_FilterFreq);
            
      sCfgFirmware.Info.PmbModus                      := FALSE;
      sCfgFirmware.Info.BootloaderUpdateRequest       := FALSE;    

      sCfgFirmware.StandardModus.ByteCounter += 1;
      sCfgFirmware.DataLength                         := sizeof(t_CfgFirmware) - sizeof(t_CfgFirmware.CRC) - sizeof(t_CfgFirmware.DataLength);
      sCfgFirmware.CRC                                := CheckSum_16(pData:=(#sCfgFirmware.Info)$^UINT, uiDataLength:=sCfgFirmware.DataLength, uiCrcStart:=16#FFFF);
      
      if (eInitState = _InvalidConfguration) then
        eInitSSW   := _InitError;
      else
        eInitSSW   := _ConfigModule;      
      end_if;
      
//**********************************************************************************************************************************************************
    _ConfigModule:
      case eResponseState of
        _idle:
          TmpRetcode  := StartWriteSDO(hOffset:=AI043_ADDR_CFG_FIRMWARE, usLength:=sizeof(t_CfgFirmware), pWriteBuffer:=(#sCfgFirmware)$^USINT, eCommand:=SDIAS_SDO_CMD_MEM_WRITE);
          if TmpRetcode = READY then
            udSDOTimeout  := ops.tAbsolute;
            eResponseState:= _wait; 
          elsif TmpRetcode = ERROR then
            eModuleInitState := ERROR;
            LogError("@0601 (AI043::InitModule) Failed to add write SDO for firmware configuration");
            eInitState := _NoMem;
          end_if;
          //*****************************************************
        _wait:
          // wait for response
          if ((ops.tAbsolute - udSDOTimeout) > AI043_SDO_RESPONSE_TIMEOUT) then
            LogError("@0602 (AI043::InitModule) SDO Response timeout config module");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW := _InitError;
          end_if;
        //*****************************************************
        _valid:
          eInitSSW        := _ReadState;
          eResponseState  := _idle;
        //*****************************************************
      end_case;
      
//**********************************************************************************************************************************************************
    _ReadState:
      case eResponseState of
        _idle:
          TmpRetcode  := StartReadSDO(hOffset:=AI043_ADDR_STATE_FIRMWARE, usLength:=sizeof(t_StateFirmware), eCommand:=SDIAS_SDO_CMD_MEM_READ);
          if TmpRetcode = READY then
            udSDOTimeout      := ops.tAbsolute;
            eResponseState := _wait; 
          elsif TmpRetcode = ERROR then
            eModuleInitState := ERROR;
            LogError("@0603 (AI043::InitModule) Failed to add read SDO for firmware info");
            eInitState := _NoMem;
          end_if; 
          //*****************************************************
        _wait:
          // wait for response
          if ((ops.tAbsolute - udSDOTimeout) > AI043_SDO_RESPONSE_TIMEOUT) then
            LogError("@0604 (AI043::InitModule) SDO Response timeout read state");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW := _InitError;
          end_if;
        //*****************************************************
        _valid: 
          if sStateFirmware.DataLength = (sizeof(t_StateFirmware) - sizeof(t_StateFirmware.CRC) - sizeof(t_StateFirmware.DataLength)) then
            if (sStateFirmware.CRC = CheckSum_16(pData:= #sStateFirmware.FirmwareVersion, uiDataLength:= sStateFirmware.DataLength, uiCrcStart:=16#FFFF)) then
              FirmwareVersion := (sStateFirmware.FirmwareVersion and 16#0000FFFF)$HDINT;
              eInitSSW         := _Finish;
              eResponseState   := _idle;
              
              if FirmwareVersion < AI043_KTY84_RAW_VALUES_FW_VER_AVAILABLE then
                //Check Client Settings
                if AI1_Config >= AI043_AMOUNT_OF_VALID_CFGS_BEFORE_KTY84_ADDED then
                  bsInvalidConfig.AI1Invalid := TRUE;
                end_if;

                if AI2_Config >= AI043_AMOUNT_OF_VALID_CFGS_BEFORE_KTY84_ADDED then
                  bsInvalidConfig.AI2Invalid := TRUE;
                end_if;
                
                if AI3_Config >= AI043_AMOUNT_OF_VALID_CFGS_BEFORE_KTY84_ADDED then
                  bsInvalidConfig.AI3Invalid := TRUE;
                end_if;
                
                if AI4_Config >= AI043_AMOUNT_OF_VALID_CFGS_BEFORE_KTY84_ADDED then
                  bsInvalidConfig.AI4Invalid := TRUE;
                end_if;               
                
              else
                //We have a newer / equal firmwareversion than 1.10, so user can set config from 23-25
                //Check Client Settings
                if AI1_Config > AI043_AMOUNT_OF_VALID_CFG then
                  bsInvalidConfig.AI1Invalid := TRUE;
                end_if;

                if AI2_Config > AI043_AMOUNT_OF_VALID_CFG then
                  bsInvalidConfig.AI2Invalid := TRUE;
                end_if;
                
                if AI3_Config > AI043_AMOUNT_OF_VALID_CFG then
                  bsInvalidConfig.AI3Invalid := TRUE;
                end_if;
                
                if AI4_Config > AI043_AMOUNT_OF_VALID_CFG then
                  bsInvalidConfig.AI4Invalid := TRUE;
                end_if;                
              end_if;
              
              //Check if we have a valid configuration
              if bsInvalidConfig then
              
                eModuleInitState := ERROR;
                eInitState := _InvalidConfguration;
                
                if bsInvalidConfig.AI1Invalid then
                  LogError("@0606 (AI043::InitModule) Invalid Configuration at AI1_Config.");  
                end_if;
                if bsInvalidConfig.AI2Invalid then
                  LogError("@0606 (AI043::InitModule) Invalid Configuration at AI2_Config.");  
                end_if;
                if bsInvalidConfig.AI3Invalid then
                  LogError("@0606 (AI043::InitModule) Invalid Configuration at AI3_Config.");  
                end_if;
                if bsInvalidConfig.AI4Invalid then
                  LogError("@0606 (AI043::InitModule) Invalid Configuration at AI4_Config.");  
                end_if;
              end_if;
              
            else
              eModuleInitState := ERROR;
              LogError("@0607 (AI043::InitModule) Invalid checksum at firmware info");
              eInitState := _ClientNotready;
            end_if;
          else
            eModuleInitState := ERROR;
            LogError("@0608 (AI043::InitModule) Invalid length at firmware info");
            eInitState := _ClientNotready;
          end_if;
      end_case;    
      
//**********************************************************************************************************************************************************
    _Finish:
      eInitSSW         := _InitVariables;
      eModuleInitState := READY;
      eInitState      := _ClassOk;
      
//**********************************************************************************************************************************************************
    _InitError:
      eModuleInitState := ERROR; 
      if (eInitState <> _InvalidConfguration) then
        eInitState      := _ClientNotready;
      end_if;  
  
  end_case;


END_FUNCTION


FUNCTION VIRTUAL AI043::ReceiveSDOResponse
	VAR_INPUT
		eCommand 	: t_SDIAS_SDO_Cmd;
		hOffset 	: HINT;
		usLength 	: USINT;
		eResult 	: iprStates;
		pResponseBuffer 	: ^USINT;
		ResponseLength 	: USINT;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  
  ret_code := SdiasBase::ReceiveSDOResponse(eCommand, hOffset, usLength, eResult, pResponseBuffer, ResponseLength);

  // spi access from baseclass                                         
  if bSDOResponseHandle = TRUE then
    return;
  end_if;   
  
  if eResult = READY then
    
    case eCommand of
      SDIAS_SDO_CMD_MEM_WRITE:
        case hOffset of
          AI043_ADDR_CFG_FIRMWARE:
            if eResponseState = _wait then
              eResponseState := _valid;
            end_if;           
        end_case;
        
      SDIAS_SDO_CMD_MEM_READ:
        case hOffset of
          AI043_ADDR_STATE_FIRMWARE:
            if eResponseState = _wait then
              eResponseState := _valid;
            end_if;
            sStateFirmware := pResponseBuffer^$t_StateFirmware;
        end_case;
    end_case;
    
    if eResponseState <> _valid then
      LogError("@0609 (AI043::ReceiveSDOResponse) Error in response data of SDO");
      eInitSSW := _InitError;      
    end_if;
  else
    case eCommand of
      SDIAS_SDO_CMD_MEM_WRITE:
        LogError("@060A (AI043::ReceiveSDOResponse) Error while writing the firmware configuration");
      SDIAS_SDO_CMD_MEM_READ:
        LogError("@060B (AI043::ReceiveSDOResponse) Error while waiting for the firmware state");
    end_case;
    eInitSSW := _InitError;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL AI043::CheckDeviceID
	VAR_INPUT
		udID2Check 	: UDINT;
	END_VAR
	VAR_OUTPUT
		bIsOK 	: BOOL;
	END_VAR
  
  //look if it is right hardware
  if ( udID2Check <> DEVICE_ID_AI043 ) then
    bIsOK := FALSE;
  else
    bIsOK := TRUE;
  end_if;

END_FUNCTION


FUNCTION AI043::SetFrequency
	VAR_INPUT
		ClientValue 	: UDINT;
	END_VAR
	VAR_OUTPUT
		Frequency 	: UINT;
	END_VAR
  
  // lookup table for cut off frequency
  case ClientValue of
    5:  Frequency := 1;
    3:  Frequency := 10;
    2:  Frequency := 25;
    1:  Frequency := 50;
    0:  Frequency := 100;
  else 
  //No filter
        Frequency := 0;
  end_case;

END_FUNCTION


FUNCTION VIRTUAL AI043::GetTaskCfg
	VAR_OUTPUT
		TaskCfg 	: BDINT;
	END_VAR
  
  TaskCfg := SDIAS_TASK_MASK_RT_PRE;

END_FUNCTION


FUNCTION AI043::AI043
	VAR_OUTPUT
		ret_code 	: ConfStates;
	END_VAR
  
  ret_code := C_OK;

END_FUNCTION


FUNCTION VIRTUAL AI043::GetDeviceID
	VAR_OUTPUT
		output 	: UDINT;
	END_VAR
  
  output := DEVICE_ID_AI043;

END_FUNCTION


FUNCTION VIRTUAL AI043::GetFWVersion
	VAR_INPUT
		pData 	: ^CHAR;
		Length 	: UDINT;
	END_VAR
  
  //Check pointer
  if pData then
    //Length of Firmwareversion (HDINT) -> 8Byte +1 byte zero termination
    if Length >= 9 then
      _itoa(udNumber:=FirmwareVersion, pString:=pData);  
    else
      pData^ := 0;
    end_if; 
  end_if;
  
END_FUNCTION
