aflexCommunicationClass.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*********************************************************************
  2. *
  3. * Afag Telnet C# Integration Sample Header
  4. *
  5. *********************************************************************
  6. * FileName: aflexCommunicationClass.cs
  7. * Dependencies: aflex_CSharp_Integration_Sample
  8. * Company: ima-tec GmbH
  9. *
  10. * Software License Agreement
  11. *
  12. *
  13. * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
  14. * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
  15. * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
  16. * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  17. * AFAG BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
  18. * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
  19. * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
  20. * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
  21. * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
  22. * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
  23. * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
  24. *
  25. *
  26. ********************************************************************/
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Linq;
  30. using System.Net;
  31. using System.Text;
  32. using System.Threading;
  33. using System.Threading.Tasks;
  34. namespace aflex_CSharp_Integration_Sample {
  35. class aflexCommunicationClass {
  36. //the target Values are the aflex Input values
  37. private UInt16 pr_target_direction;
  38. private UInt16 pr_target_intensity;
  39. private UInt16 pr_target_auxPowerOut;
  40. private Byte pr_target_ConfigNumber;
  41. private Byte pr_target_GeneralRelease;
  42. private Byte pr_target_ControllerRestart;
  43. //The actual device Values are the aflex Output values
  44. private UInt16 pr_actual_direction;
  45. private UInt16 pr_actual_intensity;
  46. private UInt16 pr_actual_auxPowerOut;
  47. private Byte pr_actual_ConfigNumber;
  48. private Byte pr_actual_AutoMode;
  49. private Byte pr_actual_GeneralRelease;
  50. private Byte pr_actual_ControllerRestart;
  51. //Bitoffset of the Values
  52. private const Byte pr_BitOff_direction = 48;
  53. private const Byte pr_BitOff_intensity = 64;
  54. private const Byte pr_BitOff_auxPowerOut = 8;
  55. private const Byte pr_BitOff_ConfigNumber = 0;
  56. private const Byte pr_BitOff_AutoMode = 32;
  57. private const Byte pr_BitOff_GeneralRelease = 40;
  58. private const Byte pr_BitOff_ControllerRestart = 24;
  59. //The aflex ControlUnit TelnetServer doesn't transmit a new package each time a value changed.
  60. //So the Client has to poll the aflex Outputs to detect the changes. For this the following TimeSpan are used.
  61. private TimeSpan pr_sync_direction= new TimeSpan();
  62. private TimeSpan pr_sync_intensity = new TimeSpan();
  63. private TimeSpan pr_sync_auxPowerOut = new TimeSpan();
  64. private TimeSpan pr_sync_ConfigNumber= new TimeSpan();
  65. private TimeSpan pr_sync_AutoMode = new TimeSpan();
  66. private TimeSpan pr_sync_GeneralRelease = new TimeSpan();
  67. private TimeSpan pr_sync_ControllerRestart = new TimeSpan();
  68. private const int TimerPeriod = 10; //fixed timer period in Milliseconds. Adjust that value due the Application requirements
  69. private TimeSpan tick = new TimeSpan(0, 0, 0, 0, TimerPeriod); //Timespan to Add each Timer tick
  70. private TimeSpan pr_MaxSync = new TimeSpan(0,0,0,0,100); //Timespan for polling the aflex Outputs. Adjust that value due the Application requirements, max value "ticks" * 7!
  71. private Timer objSyncTimer; //Timer for polling
  72. public TCPCommunicationClass objTelnetConnection; //connection interface
  73. private bool pr_b_LoggedIn; //Telnet Client logged in
  74. private bool pr_b_HBT; //Heartbeat state of the Telnet Server
  75. /// <summary>
  76. /// Occurs when a aflex value is recieved. Transmit the PropertyName as string.
  77. /// </summary>
  78. public event EventHandler aflexValueChanged;
  79. /// <summary>
  80. /// This Timer is used for cyclic polling the aflex outputs. TimerPeriod should be adjust due the Application requirements.
  81. /// </summary>
  82. /// <param name="state"></param>
  83. private void objSyncTimer_Tick(object state) {
  84. if (pr_b_LoggedIn) {
  85. pr_sync_direction = pr_sync_direction.Add(tick);
  86. pr_sync_intensity= pr_sync_intensity.Add(tick);
  87. pr_sync_auxPowerOut = pr_sync_auxPowerOut.Add(tick);
  88. pr_sync_ConfigNumber = pr_sync_ConfigNumber.Add(tick);
  89. pr_sync_AutoMode = pr_sync_AutoMode.Add(tick);
  90. pr_sync_GeneralRelease = pr_sync_GeneralRelease.Add(tick);
  91. pr_sync_ControllerRestart =pr_sync_ControllerRestart.Add(tick);
  92. //only send one "GO" command each tick --> return. The pr_sync_XXXX Timespan is reset when reading the "RO" input command from the Server.
  93. //So take care that the pr_MaxSync greater than "tick" * 7.
  94. if (pr_sync_AutoMode > pr_MaxSync) {
  95. objTelnetConnection.SendCommand("GO " + pr_BitOff_AutoMode);
  96. return; //only send one Command each Tick
  97. }
  98. if (pr_sync_GeneralRelease > pr_MaxSync) {
  99. objTelnetConnection.SendCommand("GO " + pr_BitOff_GeneralRelease);
  100. return; //only send one Command each Tick
  101. }
  102. if(pr_sync_intensity > pr_MaxSync) {
  103. objTelnetConnection.SendCommand("GO " + pr_BitOff_intensity);
  104. return; //only send one Command each Tick
  105. }
  106. if (pr_sync_auxPowerOut > pr_MaxSync) {
  107. objTelnetConnection.SendCommand("GO " + pr_BitOff_auxPowerOut);
  108. return; //only send one Command each Tick
  109. }
  110. if (pr_sync_ConfigNumber > pr_MaxSync) {
  111. objTelnetConnection.SendCommand("GO " + pr_BitOff_ConfigNumber);
  112. return; //only send one Command each Tick
  113. }
  114. if (pr_sync_ControllerRestart > pr_MaxSync) {
  115. objTelnetConnection.SendCommand("GO " + pr_BitOff_ControllerRestart);
  116. return; //only send one Command each Tick
  117. }
  118. if (pr_sync_direction > pr_MaxSync) {
  119. objTelnetConnection.SendCommand("GO " + pr_BitOff_direction);
  120. return; //only send one Command each Tick
  121. }
  122. }
  123. }
  124. public aflexCommunicationClass() {
  125. objSyncTimer = new Timer(objSyncTimer_Tick, null, TimerPeriod, TimerPeriod);
  126. objTelnetConnection = new TCPCommunicationClass();
  127. objTelnetConnection.ResultReceived += ObjTelnetConnection_ResultReceived;
  128. objTelnetConnection.ConnectionAbort += ObjTelnetConnection_ConnectionAbort;
  129. }
  130. private void ObjTelnetConnection_ConnectionAbort(object sender, EventArgs e) {
  131. this.pr_b_LoggedIn = false;
  132. if (aflexValueChanged != null) aflexValueChanged("LoggedIn", new EventArgs());
  133. }
  134. /// <summary>
  135. /// check the RX string for valid commands
  136. /// </summary>
  137. /// <param name="Result">input string</param>
  138. private void ObjTelnetConnection_ResultReceived(string Result) {
  139. if (Result != null) {
  140. string[] array_result = Result.Split(' '); //split with separator "space"
  141. string str_PropertyName = String.Empty;
  142. if (Result.Contains("\r\nTU")) { //Welcome String of Telnet server
  143. objTelnetConnection.SendCommand("admin");
  144. } else {
  145. if (array_result.Length == 1) { //TU & TP are the only commands with Lengt == 1
  146. switch (array_result[0]) { //after the TCP/IP connection is established the client has to log in on the Server. This is request by the server with the commands "TU" and "TP".
  147. case "TU": //Type User to login to TelnetServer
  148. objTelnetConnection.SendCommand("admin");
  149. break;
  150. case "TP": //Type Password of TelnetServer
  151. objTelnetConnection.SendCommand("TelnetServer");
  152. break;
  153. }
  154. } else if (array_result.Length > 1) { //all other Commands Length > 1
  155. switch (array_result[0]) {
  156. case "RO": //Read Output
  157. str_PropertyName = readRxValue(array_result);
  158. break;
  159. case "AK": //ACK from Set Input Command
  160. str_PropertyName = readRxValue(array_result);
  161. break;
  162. case "ER": //Errorcode
  163. str_PropertyName = "ER:" + array_result[1];
  164. break;
  165. case "LI": //Login/Logout response
  166. if (Convert.ToByte(array_result[1]) == 1) {
  167. pr_b_LoggedIn = true; //Now we can transfer aflex commands to the server
  168. } else {
  169. pr_b_LoggedIn = false;
  170. }
  171. str_PropertyName = "LoggedIn";
  172. break;
  173. case "HBT": //Heartbeat only for visualisation
  174. pr_b_HBT = array_result[1] == "1" ? true : false;
  175. str_PropertyName = "HBT";
  176. break;
  177. }
  178. }
  179. }
  180. if (aflexValueChanged != null) aflexValueChanged(str_PropertyName, new EventArgs());
  181. }
  182. }
  183. /// <summary>
  184. /// detect the RX commands and get the values
  185. /// </summary>
  186. /// <param name="Input">Rx input string array</param>
  187. /// <returns>PropertyName as string</returns>
  188. private string readRxValue(string[] Input) {
  189. if (Input.Length >= 2) {
  190. switch (Convert.ToByte(Input[1])) {
  191. case pr_BitOff_AutoMode:
  192. pr_actual_AutoMode = Convert.ToByte(Input[2]);
  193. pr_sync_AutoMode = pr_sync_AutoMode.Subtract(pr_sync_AutoMode); //Reset Sync Timespan
  194. return "AutoMode";
  195. case pr_BitOff_auxPowerOut:
  196. pr_actual_auxPowerOut = Convert.ToUInt16(Input[2]);
  197. pr_sync_auxPowerOut = pr_sync_auxPowerOut.Subtract(pr_sync_auxPowerOut); //Reset Sync Timespan
  198. return "AuxPowerOut";
  199. case pr_BitOff_ConfigNumber:
  200. pr_actual_ConfigNumber = Convert.ToByte(Input[2]);
  201. pr_sync_ConfigNumber = pr_sync_ConfigNumber.Subtract(pr_sync_ConfigNumber); //Reset Sync Timespan
  202. return "ConfigNumber";
  203. case pr_BitOff_ControllerRestart:
  204. pr_actual_ControllerRestart = Convert.ToByte(Input[2]);
  205. pr_sync_ControllerRestart = pr_sync_ControllerRestart.Subtract(pr_sync_ControllerRestart); //Reset Sync Timespan
  206. if (pr_actual_ControllerRestart != 0 && pr_target_ControllerRestart != 0) {
  207. pr_target_ControllerRestart = 0;
  208. objTelnetConnection.SendCommand("SI " + pr_BitOff_ControllerRestart + " " + pr_target_ControllerRestart); //After setting ControllerRestart, reset the Command to start the Restart.
  209. }
  210. return "ControllerRestart";
  211. case pr_BitOff_direction:
  212. pr_actual_direction = Convert.ToUInt16(Input[2]);
  213. pr_sync_direction = pr_sync_direction.Subtract(pr_sync_direction); //Reset Sync Timespan
  214. return "Direction";
  215. case pr_BitOff_GeneralRelease:
  216. pr_actual_GeneralRelease = Convert.ToByte(Input[2]);
  217. pr_sync_GeneralRelease = pr_sync_GeneralRelease.Subtract(pr_sync_GeneralRelease); //Reset Sync Timespan
  218. return "GeneralRelease";
  219. case pr_BitOff_intensity:
  220. pr_actual_intensity = Convert.ToUInt16(Input[2]);
  221. pr_sync_intensity = pr_sync_intensity.Subtract(pr_sync_intensity); //Reset Sync Timespan
  222. return "Intensity";
  223. }
  224. }
  225. return String.Empty;
  226. }
  227. #region Commands
  228. /// <summary>
  229. /// Establish the connetion to the Telnet Server
  230. /// </summary>
  231. /// <param name="IPAdress">IP Adress of the ControlUnit</param>
  232. /// <param name="Port">Port that is configured in the ControlUnit (default Port 23) </param>
  233. public bool Connect(IPAddress IPAdress,int Port) {
  234. return this.objTelnetConnection.Connect(IPAdress, Port);
  235. }
  236. /// <summary>
  237. /// disconnects from Telnet Server
  238. /// </summary>
  239. public void Disconnect() {
  240. this.pr_b_LoggedIn = false;
  241. this.objTelnetConnection.Disconnect();
  242. }
  243. /// <summary>
  244. /// Calculates the target direction and transmits the value to the aflex
  245. /// </summary>
  246. /// <param name="Degree">Direction [°]: 0-360 allowed</param>
  247. public void SetDirection (double Degree) {
  248. //Direction Value = (MaxValue / 360) * target dircetion (user manual 6.6.1)
  249. //MaxValue (16Bit) = 65535
  250. if (pr_b_LoggedIn) {
  251. //Calculate UINT16 Value 7
  252. if (Degree <= 360.0 && Degree >= 0.0) {
  253. pr_target_direction = (UInt16)((UInt16.MaxValue / 360.0) * Degree);
  254. objTelnetConnection.SendCommand("SI " + pr_BitOff_direction + " " + pr_target_direction);
  255. }
  256. }
  257. }
  258. /// <summary>
  259. /// Calculates the target intensity and transmit value to the aflex
  260. /// </summary>
  261. /// <param name="Intensity">Intensity [%]: 0-100 allowed</param>
  262. public void SetIntensity(double Intensity) {
  263. //Intensity Value = (MaxValue / 100%) * target direction[%] (user manual 6.6.1)
  264. //MaxValue (16Bit) = 65535
  265. if (pr_b_LoggedIn) {
  266. if (Intensity <= 100.0 && Intensity >= 0.0) {
  267. pr_target_intensity = (UInt16)((UInt16.MaxValue / 100.0) * Intensity);
  268. objTelnetConnection.SendCommand("SI " + pr_BitOff_intensity + " " + pr_target_intensity);
  269. }
  270. }
  271. }
  272. /// <summary>
  273. /// Set the general release of the ControlUnit
  274. /// </summary>
  275. /// <param name="Value">true = release | false = inhibit</param>
  276. public void SetGeneralRelease (bool Value) {
  277. if (pr_b_LoggedIn) {
  278. if (Value) pr_target_GeneralRelease = Byte.MaxValue;
  279. else pr_target_GeneralRelease = 0;
  280. objTelnetConnection.SendCommand("SI " + pr_BitOff_GeneralRelease + " " + pr_target_GeneralRelease);
  281. }
  282. }
  283. /// <summary>
  284. /// Calculates the target AuxPowerOutput of the ControlUnit and transmitt it. (AuxPowerOut --> Backlight)
  285. /// </summary>
  286. /// <param name="Intensity">Intensity [%]: 0-100 allowed</param>
  287. public void SetAuxPowerOut(double Intensity) {
  288. //Intensity Value = (MaxValue / 100%) * target direction[%] (user manual 6.6.1)
  289. //MaxValue (16Bit) = 65535
  290. if (pr_b_LoggedIn) {
  291. if (Intensity <= 100.0 && Intensity >= 0.0) {
  292. pr_target_auxPowerOut = (UInt16)((UInt16.MaxValue / 100.0) * Intensity);
  293. objTelnetConnection.SendCommand("SI " + pr_BitOff_auxPowerOut + " " + pr_target_auxPowerOut);
  294. }
  295. }
  296. }
  297. /// <summary>
  298. /// Load a aflexConfiguration
  299. /// </summary>
  300. /// <param name="ConfigNumber">Config number to load. 1-49 allowed</param>
  301. public void LoadConfiguration(byte ConfigNumber) {
  302. if (pr_b_LoggedIn) {
  303. if (ConfigNumber < 50 && ConfigNumber > 0) {
  304. pr_target_ConfigNumber = ConfigNumber;
  305. objTelnetConnection.SendCommand("SI " + pr_BitOff_ConfigNumber + " " + pr_target_ConfigNumber);
  306. }
  307. }
  308. }
  309. /// <summary>
  310. /// restart the ControlUnit. Telnet connection will be lost. Manual reconnect required.
  311. /// </summary>
  312. public void RestartController() {
  313. if (pr_b_LoggedIn) {
  314. pr_target_ControllerRestart = Byte.MaxValue;
  315. objTelnetConnection.SendCommand("SI " + pr_BitOff_ControllerRestart + " " + pr_target_ControllerRestart);
  316. }
  317. }
  318. #endregion
  319. #region Get/Set
  320. /// <summary>
  321. /// Client logged in on the Telnet Server
  322. /// </summary>
  323. public bool LoggedIn {
  324. get {
  325. return pr_b_LoggedIn;
  326. }
  327. }
  328. /// <summary>
  329. /// actual state of the Telnet Hearbeat. Toggles if connection established
  330. /// </summary>
  331. public bool HeartbeatState {
  332. get {
  333. return pr_b_HBT;
  334. }
  335. }
  336. /// <summary>
  337. /// actual aflex intensity as double [%] 0-100%
  338. /// </summary>
  339. public double actual_intensity {
  340. get {
  341. return (double)((pr_actual_intensity * 100.0 / UInt16.MaxValue));
  342. }
  343. }
  344. /// <summary>
  345. /// actual aflex direction as double [°] 0-360°
  346. /// </summary>
  347. public double actual_direction {
  348. get {
  349. return (double)((pr_actual_direction * 360.0 / UInt16.MaxValue)); //Convert uint16 value to double [°]
  350. }
  351. }
  352. /// <summary>
  353. /// actual ControlUnit auxPowerOutput as double [%] 0-100%
  354. /// </summary>
  355. public double actual_auxPowerOut {
  356. get {
  357. return (double)((pr_actual_auxPowerOut * 100.0 / UInt16.MaxValue));
  358. }
  359. }
  360. /// <summary>
  361. /// actual aflex Configuration Number as byte.
  362. /// </summary>
  363. public byte actual_ConfigNumber {
  364. get {
  365. return pr_actual_ConfigNumber;
  366. }
  367. }
  368. /// <summary>
  369. /// actual ControlUnit AutoMode. False - Manual | True - Automatic
  370. /// </summary>
  371. public bool actual_AutoMode {
  372. get {
  373. return pr_actual_AutoMode > 0 ? true : false;
  374. }
  375. }
  376. /// <summary>
  377. /// actual ControlUnit General Release. False - inhibit | True - released (if inhibit all power outputs are blocked)
  378. /// </summary>
  379. public bool actual_GeneralRelease {
  380. get {
  381. return pr_actual_GeneralRelease > 0 ? true : false;
  382. }
  383. }
  384. /// <summary>
  385. /// actual ControlUnit Restart bool
  386. /// </summary>
  387. public bool actual_ControllerRestart {
  388. get {
  389. return pr_actual_ControllerRestart > 0 ? true : false;
  390. }
  391. }
  392. #endregion
  393. }
  394. }