Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2233 - 1
///============================================================================
2
/// MKLiveView 
3
/// Copyright © 2016 Steph
4
/// 
5
///This file is part of MKLiveView.
6
///
7
///MKLiveView is free software: you can redistribute it and/or modify
8
///it under the terms of the GNU General Public License as published by
9
///the Free Software Foundation, either version 3 of the License, or
10
///(at your option) any later version.
11
///
12
///MKLiveView is distributed in the hope that it will be useful,
13
///but WITHOUT ANY WARRANTY; without even the implied warranty of
14
///MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
///GNU General Public License for more details.
16
///
17
///You should have received a copy of the GNU General Public License
18
///along with cssRcon.  If not, see <http://www.gnu.org/licenses/>.
19
///
20
///============================================================================
21
///Credits:
22
///Chootair (http://www.codeproject.com/script/Membership/View.aspx?mid=3941737)
23
///for his "C# Avionic Instrument Controls" (http://www.codeproject.com/Articles/27411/C-Avionic-Instrument-Controls)
24
///I used some of his code for displaying the compass 
25
///
26
///Tom Pyke (http://tom.pycke.be)
27
///for his "Artifical horizon" (http://tom.pycke.be/mav/100/artificial-horizon)
28
///Great job!
29
///
30
/// and last but most of all to JOHN C. MACDONALD at Ira A. Fulton College of Engineering and Technology
31
/// for his MIKROKOPTER SERIAL CONTROL TUTORIAL (http://hdl.lib.byu.edu/1877/2747)
32
/// and the sourcode (http://hdl.lib.byu.edu/1877/2748)
33
/// By his work I finally managed to get the communication with the Mikrokopter controllers to run
34
/// Some of his code was used in this programm like the SimpelSerialPort class (with some changes)
35
/// and the FilghtControllerMessage class
36
/// 
37
///============================================================================
38
 
39
using System;
40
using System.Data;
41
using System.Drawing;
42
using System.Text;
43
using System.Windows.Forms;
44
using System.IO;
45
using System.Threading;
46
using System.Diagnostics;
47
using System.Runtime.InteropServices;
48
 
49
namespace MKLiveView
50
{
51
    public partial class MainForm : Form
52
    {
53
 
54
        [FlagsAttribute]
55
        enum NC_HWError0 : short
56
        {
57
            None = 0,
58
            SPI_RX = 1,
59
            COMPASS_RX = 2,
60
            FC_INCOMPATIBLE = 4,
61
            COMPASS_INCOMPATIBLE = 8,
62
            GPS_RX = 16,
63
            COMPASS_VALUE = 32
64
        };
65
        [FlagsAttribute]
66
        enum FC_HWError0 : short
67
        {
68
            None = 0,
69
            GYRO_NICK = 1,
70
            GYRO_ROLL = 2,
71
            GYRO_YAW = 4,
72
            ACC_NICK = 8,
73
            ACC_ROLL = 16,
74
            ACC_TOP = 32,
75
            PRESSURE = 64,
76
            CAREFREE = 128
77
        };
78
        [FlagsAttribute]
79
        enum FC_HWError1 : short
80
        {
81
            None = 0,
82
            I2C = 1,
83
            BL_MISSING = 2,
84
            SPI_RX = 4,
85
            PPM = 8,
86
            MIXER = 16,
87
            RC_VOLTAGE = 32,
88
            ACC_NOT_CAL = 64,
89
            RES3 = 128
90
        };
91
        public enum LogMsgType { Incoming, Outgoing, Normal, Warning, Error };
92
        // Various colors for logging info
93
        private Color[] LogMsgTypeColor = { Color.FromArgb(43, 145, 175), Color.Green, Color.Black, Color.Orange, Color.Red };
94
 
95
        string[] sAnalogLabel = new string[32];
96
        string[] sAnalogData = new string[32];
97
        bool bReadContinously = false;
98
        bool check_HWError = false;
99
        bool _bCBInit = true;
100
        bool _init = true;
101
        bool _debugDataAutorefresh = true;
102
        bool _navCtrlDataAutorefresh = true;
103
        bool _blctrlDataAutorefresh = true;
104
        bool _OSDAutorefresh = true;
105
        int crcError = 0;
106
        int iLableIndex = 0;
107
        string filePath = Directory.GetCurrentDirectory();
108
        string fileName = "NCLabelTexts.txt";
109
        int _iCtrlAct = 0;
110
        int _iLifeCounter = 0;
111
        int iOSDPage = 0;
112
        int iOSDMax = 0;
113
        /// <summary>
114
        /// interval for sending debugdata (multiplied by 10ms)
115
        /// </summary>
116
        byte debugInterval = 25; //(=> 250ms)
117
        /// <summary>
118
        /// interval for sending BL-CTRL status (multiplied by 10ms)
119
        /// </summary>
120
        byte blctrlInterval = 45;
121
        /// <summary>
122
        /// interval for sending NAV-CTRL status (multiplied by 10ms)
123
        /// </summary>
124
        byte navctrlInterval = 80;
125
        /// <summary>
126
        /// interval for sending OSD page update (multiplied by 10ms)
127
        /// </summary>
128
        byte OSDInterval = 85;
129
        /// <summary>
130
        /// datatable for the debug data array - displayed on settings tabpage in datagridview
131
        /// </summary>
132
        DataTable dtAnalog = new DataTable();
133
        public MainForm()
134
        {
135
            InitializeComponent();
136
            _readIni();
137
            dtAnalog.Columns.Add("ID");
138
            dtAnalog.Columns.Add("Value");
139
            dataGridView1.DataSource = dtAnalog;
140
            simpleSerialPort.PortClosed += SimpleSerialPort_PortClosed;
141
            simpleSerialPort.PortOpened += SimpleSerialPort_PortOpened;
142
            simpleSerialPort.DataReceived += processMessage;
143
            chkbAutoBL.Checked = _blctrlDataAutorefresh;
144
            chkbAutoDbg.Checked = _debugDataAutorefresh;
145
            chkbAutoNav.Checked = _navCtrlDataAutorefresh;
146
            chkbAutoOSD.Checked = _OSDAutorefresh;
147
            labelTimingDebug.Text = (debugInterval * 10).ToString();
148
            labelTimingBLCTRL.Text = (blctrlInterval * 10).ToString();
149
            labelTimingNAV.Text = (navctrlInterval * 10).ToString();
150
            labelTimingOSD.Text = (OSDInterval * 10).ToString();
151
            tabControl1.TabPages.Remove(tabPageTesting);
152
        }
153
        #region events
154
        private void MainForm_Shown(object sender, EventArgs e)
155
        {
156
            _loadLabelNames();
157
            _init = false;
158
        }
159
        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
160
        {
161
            _writeIni();
162
        }
163
        private void SimpleSerialPort_PortOpened()
164
        {
165
            btnConn.Invoke((Action)(() => btnConn.BackColor = Color.FromArgb(192, 255, 192)));
166
            btnConn.Invoke((Action)(() => btnConn.Text = "close" + Environment.NewLine + "serial port"));
167
            _getVersion();
168
            Thread.Sleep(100);
169
            _OSDMenue(0);
170
           // _readCont(true);
171
        }
172
        private void SimpleSerialPort_PortClosed()
173
        {
174
            btnConn.Invoke((Action)(() => btnConn.BackColor = Color.FromArgb(224, 224, 224)));
175
            btnConn.Invoke((Action)(() => btnConn.Text = "open" + Environment.NewLine + "serial port"));
176
            _readCont(false);
177
        }
178
        /// <summary>
179
        /// timer for refreshing subscription of subscribed data
180
        /// query lifecounter for connection failure
181
        /// </summary>
182
        private void timer1_Tick(object sender, EventArgs e)
183
        {
184
            if(bReadContinously)
185
            {
186
                if (_debugDataAutorefresh) { _readDebugData(true); Thread.Sleep(10); }
187
 
188
                if (_blctrlDataAutorefresh && _iCtrlAct == 2) { _readBLCtrl(true); Thread.Sleep(10); }
189
 
190
                if (_navCtrlDataAutorefresh && _iCtrlAct == 2) { _readNavData(true); Thread.Sleep(10); }
191
                check_HWError = true;
192
                _getVersion();
193
                Thread.Sleep(10);
194
                if (_OSDAutorefresh) { _OSDMenueAutoRefresh(); }
195
                if (_iLifeCounter > 0)
196
                {
197
                    lblLifeCounter.BackColor = Color.FromArgb(0, 224, 0);
198
                    _iLifeCounter = 0;
199
                }
200
                else
201
                {
202
                    Log(LogMsgType.Error, "No communication to NC/FC!");
203
                    lblLifeCounter.BackColor = Color.FromArgb(224, 0, 0);
204
                }
205
            }
206
        }
207
        private void cbOSD_SelectedIndexChanged(object sender, EventArgs e)
208
        {
209
            if (!_bCBInit && cbOSD.SelectedIndex > -1)
210
                _OSDMenue(cbOSD.SelectedIndex);
211
        }
212
 
213
        private void chkbAutoDbg_CheckedChanged(object sender, EventArgs e)
214
        {
215
            if(!_init) _debugDataAutorefresh = chkbAutoDbg.Checked;
216
        }
217
        private void chkbAutoNav_CheckedChanged(object sender, EventArgs e)
218
        {
219
            if (!_init) _navCtrlDataAutorefresh = chkbAutoNav.Checked;
220
        }
221
        private void chkbAutoBL_CheckedChanged(object sender, EventArgs e)
222
        {
223
            if (!_init) _blctrlDataAutorefresh = chkbAutoBL.Checked;
224
        }
225
        private void chkbAutoOSD_CheckedChanged(object sender, EventArgs e)
226
        {
227
            if (!_init) _OSDAutorefresh = chkbAutoOSD.Checked;
228
        }
229
 
230
        private void cbTimingDebug_SelectedIndexChanged(object sender, EventArgs e)
231
        {
232
            if (cbTimingDebug.SelectedIndex > -1)
233
            {
234
                debugInterval = (byte)(Convert.ToInt16(cbTimingDebug.SelectedItem) / 10);
235
                labelTimingDebug.Text = (debugInterval * 10).ToString();
236
            }
237
        }
238
        private void cbTimingNAV_SelectedIndexChanged(object sender, EventArgs e)
239
        {
240
            if (cbTimingNAV.SelectedIndex > -1)
241
            {
242
                navctrlInterval = (byte)(Convert.ToInt16(cbTimingNAV.SelectedItem) / 10);
243
                labelTimingNAV.Text = (navctrlInterval * 10).ToString();
244
            }
245
        }
246
        private void cbTimingBLCTRL_SelectedIndexChanged(object sender, EventArgs e)
247
        {
248
            if (cbTimingBLCTRL.SelectedIndex > -1)
249
            {
250
                blctrlInterval = (byte)(Convert.ToInt16(cbTimingBLCTRL.SelectedItem) / 10);
251
                labelTimingBLCTRL.Text = (blctrlInterval * 10).ToString();
252
            }
253
        }
254
        private void cbTimingOSD_SelectedIndexChanged(object sender, EventArgs e)
255
        {
256
            if (cbTimingOSD.SelectedIndex > -1)
257
            {
258
                OSDInterval = (byte)(Convert.ToInt16(cbTimingOSD.SelectedItem) / 10);
259
                labelTimingOSD.Text = (OSDInterval * 10).ToString();
260
            }
261
        }
262
        #endregion events
263
 
264
        /// <summary> Log data to the terminal window. </summary>
265
        /// <param name="msgtype"> The type of message to be written. </param>
266
        /// <param name="msg"> The string containing the message to be shown. </param>
267
        private void Log(LogMsgType msgtype, string msg)
268
        {
269
            rtfTerminal.Invoke(new EventHandler(delegate
270
            {
271
                if (rtfTerminal.Lines.Length >= 1000)   //Wenn Terminal mehr als 1000 Zeilen hat
272
                    rtfTerminal.Select(42, (500 * 129));     //500 löschen
273
                rtfTerminal.Select(rtfTerminal.Text.Length, 0);
274
                rtfTerminal.SelectedText = string.Empty;
275
                rtfTerminal.SelectionFont = new Font(rtfTerminal.SelectionFont, FontStyle.Regular);
276
                rtfTerminal.SelectionColor = LogMsgTypeColor[(int)msgtype];
277
                rtfTerminal.AppendText(msg + Environment.NewLine);
278
                rtfTerminal.ScrollToCaret();
279
            }));
280
        }
281
        /// <summary> display the OSD text in 4 lines à 20 chars </summary>
282
        /// <param name="msgtype"> The type of message to be written. </param>
283
        /// <param name="msg"> The string containing the message to be shown. </param>
284
        private void OSD(LogMsgType msgtype, string msg)
285
        {
286
            rtfOSD.Invoke(new EventHandler(delegate
287
            {
288
                if (rtfOSD.Lines.Length > 4)
289
                    rtfOSD.Clear();
290
                rtfOSD.Select(rtfOSD.Text.Length,0);
291
                rtfOSD.SelectedText = string.Empty;
292
                rtfOSD.SelectionFont = new Font(rtfOSD.SelectionFont, FontStyle.Regular);
293
                rtfOSD.SelectionColor = LogMsgTypeColor[(int)msgtype];
294
                rtfOSD.AppendText(msg + Environment.NewLine);
295
                if (rtfOSD.Text.IndexOf("ERR") > 0)
296
                {
297
                    rtfOSD.Select(rtfOSD.Text.IndexOf("ERR"), 40);
298
                    rtfOSD.SelectionColor = LogMsgTypeColor[(int)LogMsgType.Error];
299
                }
300
            }));
301
        }
302
        private void ErrorLog(LogMsgType msgtype, string msg)
303
        {
304
            rtfError.Invoke(new EventHandler(delegate
305
            {
306
                if (rtfError.Lines.Length > 4)
307
                    rtfError.Clear();
308
                rtfError.Focus();
309
                rtfError.Select(rtfError.Text.Length, 0);
310
                rtfError.SelectedText = string.Empty;
311
                rtfError.SelectionFont = new Font(rtfError.SelectionFont, FontStyle.Regular);
312
                rtfError.SelectionColor = LogMsgTypeColor[(int)msgtype];
313
                rtfError.AppendText(msg + Environment.NewLine);
314
 
315
            }));
316
        }
317
 
318
        #region functions        
319
 
320
        /// <summary> Processing the messages and displaying them in the according form controls </summary>
321
        /// <param name="message"> message bytearray recieved by SimpleSerialPort class </param>
322
        private void processMessage(byte[] message)
323
        {
324
            if (message.Length > 0)
325
            {
326
                _iLifeCounter++;
327
                //Log(LogMsgType.Incoming, BitConverter.ToString(message));
328
                //Log(LogMsgType.Incoming, message.Length.ToString());
329
                string s = new string(ASCIIEncoding.ASCII.GetChars(message, 0, message.Length));
330
                char cmdID;
331
                byte adr;
332
                byte[] data;
333
                if (message[0] != '#')
334
                    Log(LogMsgType.Normal, s.Trim('\0', '\n','\r'));
335
                //Debug.Print(s);
336
                else
337
                {
338
                    FlightControllerMessage.ParseMessage(message, out cmdID, out adr, out data);
339
 
340
                    if (adr == 255) { crcError++; }
341
                    else crcError = 0;
342
                    lblCRCErr.Invoke((Action)(() => lblCRCErr.Text = crcError.ToString()));
343
 
344
                    if (adr > 0 && adr < 3 && adr != _iCtrlAct) //adr < 3: temporary workaround cause when I've connected the FC alone it always switches between mk3mag & FC every second...???
345
                    {
346
                        _iCtrlAct = adr;
347
                        switch (adr)
348
                        {
349
                            case 1:
350
                                lblCtrl.Invoke((Action)(() => lblCtrl.Text = "FC"));
351
                                lblNCCtrl.Invoke((Action)(() => lblNCCtrl.Text = "FC"));
352
                                _setFieldsNA(); //display fields NA for FC 
353
                                break;
354
                            case 2:
355
                                lblCtrl.Invoke((Action)(() => lblCtrl.Text = "NC"));
356
                                lblNCCtrl.Invoke((Action)(() => lblNCCtrl.Text = "NC"));
357
                                break;
358
                            case 3:
359
                                lblCtrl.Invoke((Action)(() => lblCtrl.Text = "MK3MAG"));
360
                                break;
361
                            case 4:
362
                                lblCtrl.Invoke((Action)(() => lblCtrl.Text = "BL-CTRL"));
363
                                break;
364
                            default:
365
                                lblCtrl.Invoke((Action)(() => lblCtrl.Text = "...."));
366
                                break;
367
                        }
368
                        _loadLabelNames();
369
                    }
370
                   // else
371
                   //     Debug.Print("Address == 0?");
372
 
373
                    if (data != null && data.Length > 0)
374
                    {
375
                        s = new string(ASCIIEncoding.ASCII.GetChars(data, 1, data.Length - 1));
376
                        s = s.Trim('\0', '\n');
377
 
378
                        switch (cmdID)
379
                        {
380
                            case 'A':
381
                                if (iLableIndex < 32)
382
                                {
383
                                    sAnalogLabel[iLableIndex] = s;
384
                                    if (dtAnalog.Rows.Count < 32)
385
                                        dtAnalog.Rows.Add(s, "");
386
                                    else
387
                                        dtAnalog.Rows[iLableIndex].SetField(0, s);
388
 
389
                                    _getAnalogLabels(iLableIndex + 1);
390
                                }
391
                                Debug.Print(s);
392
 
393
                                break;
394
                            case 'D':
395
                                if (data.Length == 66)
396
                                {
397
                                    int[] iAnalogData = new int[32];
398
 
399
                                    int index = 0;
400
                                    Int16 i16 = 0;
401
                                    double dTemp = 0;
402
                                    for (int i = 2; i < 66; i += 2)
403
                                    {
404
                                        i16 = data[i + 1];
405
                                        i16 = (Int16)(i16 << 8);
406
                                        iAnalogData[index] = data[i] + i16;
407
                                        sAnalogData[index] = (data[i] + i16).ToString();
408
                                        dtAnalog.Rows[index].SetField(1, sAnalogData[index]);
409
 
410
                                        if (adr == 2) //NC
411
                                        {
412
                                            switch (index)
413
                                            {
414
                                                case 0: //pitch (German: nick)
415
                                                    artificialHorizon1.Invoke((Action)(() => artificialHorizon1.pitch_angle = ((double)iAnalogData[index] / (double)10)));
416
                                                    lblNCPitch.Invoke((Action)(() => lblNCPitch.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0°")));
417
                                                    break;
418
                                                case 1: //roll
419
                                                    artificialHorizon1.Invoke((Action)(() => artificialHorizon1.roll_angle = ((double)iAnalogData[index] / (double)10)));
420
                                                    lblNCRoll.Invoke((Action)(() => lblNCRoll.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0°")));
421
                                                    break;
422
                                                case 4: //altitude
423
                                                    lblNCAlt.Invoke((Action)(() => lblNCAlt.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0 m")));
424
                                                    break;
425
                                                case 7: //Voltage
426
                                                    lblNCVolt.Invoke((Action)(() => lblNCVolt.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0 V")));
427
                                                    break;
428
                                                case 8: // Current
429
                                                    lblNCCur.Invoke((Action)(() => lblNCCur.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0 A")));
430
                                                    break;
431
                                                case 10: //heading
432
                                                    lblNCCompass.Invoke((Action)(() => lblNCCompass.Text = sAnalogData[index] + "°"));
433
                                                    headingIndicator1.Invoke((Action)(() => headingIndicator1.SetHeadingIndicatorParameters(iAnalogData[index])));
434
                                                    break;
435
                                                case 12: // SPI error
436
                                                    lblNCSPI.Invoke((Action)(() => lblNCSPI.Text = sAnalogData[index]));
437
                                                    break;
438
                                                case 14: //i2c error
439
                                                    lblNCI2C.Invoke((Action)(() => lblNCI2C.Text = sAnalogData[index]));
440
                                                    break;
441
                                                case 20: //Earthmagnet field
442
                                                    lblNCMF.Invoke((Action)(() => lblNCMF.Text = sAnalogData[index] + "%"));
443
                                                    break;
444
                                                case 21: //GroundSpeed
445
                                                    lblNCGSpeed.Invoke((Action)(() => lblNCGSpeed.Text = ((double)iAnalogData[index] / (double)100).ToString("0.00 m/s")));
446
                                                    break;
447
                                                case 28: //Distance East from saved home position -> calculate distance with distance N + height
448
                                                    dTemp = Math.Pow((double)iAnalogData[index],2) + Math.Pow((double)iAnalogData[index - 1],2);
449
                                                    dTemp = Math.Sqrt(dTemp)/ (double)10; //'flat' distance from HP with N/E
450
                                                  //  lblNCDist.Invoke((Action)(() => lblNCDist.Text = dTemp.ToString("0.00")));
451
                                                    dTemp = Math.Pow(dTemp, 2) + Math.Pow(((double)iAnalogData[4] / (double)10), 2); //adding 'height' into calculation
452
                                                    dTemp = Math.Sqrt(dTemp);
453
                                                    lblNCDist.Invoke((Action)(() => lblNCDist.Text = dTemp.ToString("0 m")));
454
                                                    break;
455
                                                case 31: //Sats used
456
                                                    lblNCSat.Invoke((Action)(() => lblNCSat.Text = sAnalogData[index]));
457
                                                    break;
458
                                            }
459
                                        }
460
                                        if (adr == 1) //FC
461
                                        {
462
                                            switch (index)
463
                                            {
464
                                                case 0: //pitch (German: nick)
465
                                                    artificialHorizon1.Invoke((Action)(() => artificialHorizon1.pitch_angle = ((double)iAnalogData[index] / (double)10)));
466
                                                    lblNCPitch.Invoke((Action)(() => lblNCPitch.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0°")));
467
                                                    break;
468
                                                case 1: //roll
469
                                                    artificialHorizon1.Invoke((Action)(() => artificialHorizon1.roll_angle = ((double)iAnalogData[index] / (double)10)));
470
                                                    lblNCRoll.Invoke((Action)(() => lblNCRoll.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0°")));
471
                                                    break;
472
                                                case 5: //altitude
473
                                                    lblNCAlt.Invoke((Action)(() => lblNCAlt.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0 m")));
474
                                                    break;
475
                                                case 8: //heading
476
                                                    lblNCCompass.Invoke((Action)(() => lblNCCompass.Text = sAnalogData[index] + "°"));
477
                                                    headingIndicator1.Invoke((Action)(() => headingIndicator1.SetHeadingIndicatorParameters(iAnalogData[index])));
478
                                                    break;
479
                                                case 9: //Voltage
480
                                                    lblNCVolt.Invoke((Action)(() => lblNCVolt.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0 V")));
481
                                                    break;
482
                                                case 10: //Receiver quality
483
                                                    lblNCRC.Invoke((Action)(() => lblNCRC.Text = sAnalogData[index]));
484
                                                    break;
485
                                                case 22: // Current
486
                                                    lblNCCur.Invoke((Action)(() => lblNCCur.Text = ((double)iAnalogData[index] / (double)10).ToString("0.0 A")));
487
                                                    break;
488
                                                case 23: //capacity used
489
                                                    lblNCCap.Invoke((Action)(() => lblNCCap.Text = (iAnalogData[index]).ToString("0 mAh")));
490
                                                    break;
491
                                                case 27: // SPI error
492
                                                    lblNCSPI.Invoke((Action)(() => lblNCSPI.Text = sAnalogData[index]));
493
                                                    break;
494
                                                case 28: //i2c error
495
                                                    lblNCI2C.Invoke((Action)(() => lblNCI2C.Text = sAnalogData[index]));
496
                                                    break;
497
                                            }
498
                                        }
499
                                        index++;
500
                                    }
501
                                }
502
                                else
503
                                    Debug.Print("wrong data-length (66): " + data.Length.ToString());
504
                                break;
505
 
506
                            case 'V':
507
                                if (data.Length == 12)
508
                                {
509
                                    if (!check_HWError)
510
                                    {
511
                                        string[] sVersionStruct = new string[10] { "SWMajor: ", "SWMinor: ", "ProtoMajor: ", "LabelTextCRC: ", "SWPatch: ", "HardwareError 1: ", "HardwareError 2: ", "HWMajor: ", "BL_Firmware: ", "Flags: " };
512
                                        string sVersion = "";
513
                                        //sbyte[] signed = Array.ConvertAll(data, b => unchecked((sbyte)b));
514
                                        Log(LogMsgType.Warning, (adr == 1 ? "FC-" : "NC-") + "Version: ");
515
                                        sVersion = "HW V" + (data[7] / 10).ToString() + "." + (data[7] % 10).ToString();
516
                                        Log(LogMsgType.Incoming, sVersion);
517
                                        sVersion = "SW V" + (data[0]).ToString() + "." + (data[1]).ToString() + ((char)(data[4] + 'a')).ToString();
518
                                        Log(LogMsgType.Incoming, sVersion);
519
                                        Log(LogMsgType.Incoming, "BL-Firmware: V" + (data[8] / 100).ToString() + "." + (data[8] % 100).ToString());
520
                                    }
521
                                    if(data[5] > 0) //error0 
522
                                    {
523
                                        if(adr == 1)
524
                                            ErrorLog(LogMsgType.Error, "FC - HW-Error " + data[5].ToString() + ": " + ((FC_HWError0)data[5]).ToString());
525
                                        if (adr == 2)
526
                                            ErrorLog(LogMsgType.Error, "NC - HW-Error " + data[5].ToString() + ": " + ((NC_HWError0)data[5]).ToString());
527
                                    }
528
                                    if (data[6] > 0) //error1 
529
                                    {
530
                                        if (adr == 1)
531
                                            ErrorLog(LogMsgType.Error, "FC - HW-Error " + data[6].ToString() + ": " + ((FC_HWError1)data[6]).ToString());
532
                                        if (adr == 2)
533
                                            ErrorLog(LogMsgType.Error, "NC - Unknown HW-ERROR: " + data[6].ToString()); //@moment NC has only one error field
534
                                    }
535
 
536
                                }
537
                                check_HWError = false;
538
                                break;
539
 
540
                            case 'K'://BL-CTRL debug data from NC
541
                                if (data.Length == 6 && data[0] < 8)
542
                                {
543
                                    Label lbCur = new Label(), lbTemp = new Label();
544
                                    switch (data[0])
545
                                    {
546
                                        case 0:
547
                                            lbCur = LBLNCM1Cur;
548
                                            lbTemp = LBLNCM1Temp;
549
                                            break;
550
                                        case 1:
551
                                            lbCur = LBLNCM2Cur;
552
                                            lbTemp = LBLNCM2Temp;
553
                                            break;
554
                                        case 2:
555
                                            lbCur = LBLNCM3Cur;
556
                                            lbTemp = LBLNCM3Temp;
557
                                            break;
558
                                        case 3:
559
                                            lbCur = LBLNCM4Cur;
560
                                            lbTemp = LBLNCM4Temp;
561
                                            break;
562
                                        case 4:
563
                                            lbCur = LBLNCM5Cur;
564
                                            lbTemp = LBLNCM5Temp;
565
                                            break;
566
                                        case 5:
567
                                            lbCur = LBLNCM6Cur;
568
                                            lbTemp = LBLNCM6Temp;
569
                                            break;
570
                                        case 6:
571
                                            lbCur = LBLNCM7Cur;
572
                                            lbTemp = LBLNCM7Temp;
573
                                            break;
574
                                        case 7:
575
                                            lbCur = LBLNCM8Cur;
576
                                            lbTemp = LBLNCM8Temp;
577
                                            break;
578
                                    }
579
                                    if (lbCur != null)
580
                                        lbCur.Invoke((Action)(() => lbCur.Text = ((double)data[1] / (double)10).ToString("0.0 A")));
581
                                    if (lbTemp != null)
582
                                        lbTemp.Invoke((Action)(() => lbTemp.Text = data[2].ToString("0 °C")));
583
 
584
                                }
585
 
586
                                break;
587
 
588
                            case 'O': //NC Data
589
                                int i_16,iVal;
590
                                i_16 = data[81];
591
                                i_16 = (Int16)(i_16 << 8);
592
                                iVal = data[80] + i_16;
593
                                lblNCCap.Invoke((Action)(() => lblNCCap.Text = iVal.ToString() + " mAh")); //Capacity used
594
 
595
                                i_16 = data[56];
596
                                i_16 = (Int16)(i_16 << 8);
597
                                iVal = data[55] + i_16;
598
                                TimeSpan t = TimeSpan.FromSeconds(iVal);
599
                                string Text = t.Hours.ToString("D2") + ":" + t.Minutes.ToString("D2") + ":" + t.Seconds.ToString("D2");
600
                                lblNCFlTime.Invoke((Action)(() => lblNCFlTime.Text = Text.ToString())); //Flying time
601
 
602
                                lblNCRC.Invoke((Action)(() => lblNCRC.Text = data[66].ToString())); //RC quality
603
                                lblNCErrNmbr.Invoke((Action)(() => lblNCErrNmbr.Text = data[69].ToString()));   //NC Errornumber
604
                                if (data[69] > 0)
605
                                    _readNCError();
606
                                break;
607
 
608
                            case 'E': //NC error-string
609
                                ErrorLog(LogMsgType.Error, "NC Error: " + s);
610
 
611
                                break;
612
 
613
                            case 'L':
614
                                if(data.Length == 84)
615
                                {
616
                                    string sMessage = "";
617
                                    iOSDPage = data[0];
618
                                    iOSDMax = data[1];
619
                                    if (cbOSD.Items.Count != iOSDMax) _initOSDCB();
620
                                    sMessage = new string(ASCIIEncoding.ASCII.GetChars(data, 2, data.Length - 4));
621
                                    OSD(LogMsgType.Incoming, sMessage.Substring(0,20));
622
                                    OSD(LogMsgType.Incoming, sMessage.Substring(20,20));
623
                                    OSD(LogMsgType.Incoming, sMessage.Substring(40,20));
624
                                    OSD(LogMsgType.Incoming, sMessage.Substring(60,20));
625
                                    lblOSDPageNr.Invoke((Action)(()=>lblOSDPageNr.Text = iOSDPage.ToString("[0]")));
626
 
627
                                }
628
                                else
629
                                    OSD(LogMsgType.Incoming,"Wrong length: " + data.Length + " (should be 84)");
630
                                break;
631
                            case 'H':
632
                                if(data.Length == 81)
633
                                {
634
                                    string sMessage = "";
635
                                    sMessage = new string(ASCIIEncoding.ASCII.GetChars(data, 0, data.Length - 1));
636
                                    OSD(LogMsgType.Incoming, sMessage.Substring(0,20));
637
                                    OSD(LogMsgType.Incoming, sMessage.Substring(20,20));
638
                                    OSD(LogMsgType.Incoming, sMessage.Substring(40,20));
639
                                    OSD(LogMsgType.Incoming, sMessage.Substring(60,20));
640
 
641
                                }
642
                                else
643
                                    OSD(LogMsgType.Incoming, "Wrong length: " + data.Length + " (should be 81)");
644
                                break;
645
 
646
                            //default:
647
                            //    Log(LogMsgType.Incoming, "cmd: " + cmdID.ToString());
648
                            //    Log(LogMsgType.Incoming, BitConverter.ToString(data));
649
                            //    break;
650
                        }
651
                    }
652
                    //else
653
                    //{
654
                    //    Log(LogMsgType.Incoming, "cmd: " + cmdID.ToString());
655
                    //    Log(LogMsgType.Incoming, BitConverter.ToString(data));
656
                    //}
657
                }
658
            }
659
        }
660
 
661
        /// <summary> send message to controller to request data
662
        /// for detailed info see http://wiki.mikrokopter.de/en/SerialProtocol/
663
        /// </summary>
664
        /// <param name="CMDID"> the command ID </param>
665
        /// <param name="address"> the address of the controller: 0-any, 1-FC, 2-NC </param>
666
        private void _sendControllerMessage(char CMDID, byte address)
667
        {
668
            if (simpleSerialPort.Port.IsOpen)
669
            {
670
                Stream serialStream = simpleSerialPort.Port.BaseStream;
671
                byte[] bytes = FlightControllerMessage.CreateMessage(CMDID, address);
672
                serialStream.Write(bytes, 0, bytes.Length);
673
 
674
            }
675
            else
676
                Log(LogMsgType.Error, "NOT CONNECTED!");
677
        }
678
        /// <summary> send message to controller to request data
679
        /// for detailed info see http://wiki.mikrokopter.de/en/SerialProtocol/
680
        /// </summary>
681
        /// <param name="CMDID"> the command ID </param>
682
        /// <param name="address"> the address of the controller: 0-any, 1-FC, 2-NC </param>
683
        /// <param name="data"> additional data for the request</param>
684
        private void _sendControllerMessage(char CMDID, byte address, byte[]data)
685
        {
686
            if (simpleSerialPort.Port.IsOpen)
687
            {
688
                Stream serialStream = simpleSerialPort.Port.BaseStream;
689
                byte[] bytes = FlightControllerMessage.CreateMessage(CMDID, address,data);
690
                serialStream.Write(bytes, 0, bytes.Length);
691
 
692
            }
693
            else
694
                Log(LogMsgType.Error, "NOT CONNECTED!");
695
        }
696
 
697
        /// <summary>
698
        /// read the analog-label names for the actual controller
699
        /// and load it into listbox
700
        /// </summary>
701
        void _loadLabelNames()
702
        {
703
            if (_iCtrlAct > 0 && _iCtrlAct < 3)
704
            {
705
                switch (_iCtrlAct)
706
                {
707
                    case 1:
708
                        sAnalogLabel = Properties.Resources.FCLabelTexts.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
709
                        break;
710
                    case 2:
711
                        sAnalogLabel = Properties.Resources.NCLabelTexts.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
712
                        break;
713
                }
714
                for (int i = 0; i < 32; i++)
715
                {
716
                    if (dtAnalog.Rows.Count < 32)
717
                        dtAnalog.Rows.Add(sAnalogLabel[i], "");
718
                    else
719
                        dtAnalog.Rows[i].SetField(0, sAnalogLabel[i]);
720
                }
721
                dataGridView1.Invoke((Action)(()=>dataGridView1.Refresh()));
722
            }
723
        }
724
        /// <summary>
725
        /// no longer used...
726
        /// read the analog-label textfile for the actual controller
727
        /// </summary>
728
         private void _loadLabelFile()
729
        {
730
            switch (_iCtrlAct)
731
            {
732
                case 1:
733
                    fileName = "FCLabelTexts.txt";
734
                    break;
735
                case 2:
736
                    fileName = "NCLabelTexts.txt";
737
                    break;
738
                //default:
739
                //    fileName = "NCLabelTexts.txt";
740
                //    break;
741
            }
742
 
743
            if (File.Exists(filePath + "\\" + fileName))
744
            {
745
                sAnalogLabel.Initialize();
746
                sAnalogLabel = File.ReadAllLines(filePath + "\\" + fileName);
747
                lbLabels.Invoke((Action)(() => lbLabels.Items.Clear()));
748
                lbLabels.Invoke((Action)(() => lbLabels.Update()));
749
                lbLabels.Invoke((Action)(() => lbLabels.Items.AddRange(sAnalogLabel)));
750
                Console.WriteLine("Names loaded from file");
751
                lblFileName.Invoke((Action)(() => lblFileName.Text = fileName));
752
            }
753
            else
754
            {
755
                _readCont(false);
756
                Log(LogMsgType.Error, "Label-file not found!");
757
                Log(LogMsgType.Error, "Please go to settings-tab and load the label texts from the copter control (FC & NC)");
758
                Log(LogMsgType.Error, "When done, you have to save the label texts with the 'save' button!");
759
            }
760
        }
761
        /// <summary>
762
        /// no longer used...
763
        /// assign the analog-label names from the textfile to the datatable
764
        /// 
765
        /// </summary>
766
        private void _assignLabelNames()
767
        {
768
            if (lbLabels.Items.Count == 32)
769
            {
770
                lbLabels.Items.CopyTo(sAnalogLabel, 0);
771
                for (int i = 0; i < 32; i++)
772
                {
773
                    if (dtAnalog.Rows.Count < 32)
774
                        dtAnalog.Rows.Add(sAnalogLabel[i], "");
775
                    else
776
                        dtAnalog.Rows[i].SetField(0, sAnalogLabel[i]);
777
 
778
                }
779
            }
780
        }
781
        /// <summary>
782
        /// get the version struct of actual controller
783
        /// </summary>
784
        /// <summary>
785
        /// get the labeltexts for the analog values
786
        /// </summary>
787
        private void _getAnalogLabels()
788
        {
789
            if (simpleSerialPort.Port.IsOpen)
790
            {
791
                iLableIndex = 0;
792
                for (int i = 0; i < 32; i++)
793
                {
794
                    Stream serialStream = simpleSerialPort.Port.BaseStream;
795
                    byte[] bytes = FlightControllerMessage.CreateMessage('a', 0, new byte[1] { (byte)i });
796
                    serialStream.Write(bytes, 0, bytes.Length);
797
                    Thread.Sleep(10);
798
                }
799
            }
800
            else
801
                Log(LogMsgType.Error, "NOT CONNECTED!");
802
        }
803
        /// <summary>
804
        /// get the labeltext for a single label
805
        /// </summary>
806
        /// <param name="iIndex">index of the label</param>
807
        private void _getAnalogLabels(int iIndex)
808
        {
809
            if (simpleSerialPort.Port.IsOpen)
810
            {
811
                if (iIndex < 32)
812
                {
813
                    iLableIndex = iIndex;
814
                    _sendControllerMessage('a', 0, new byte[1] { (byte)iLableIndex });
815
                }
816
            }
817
            else
818
                Log(LogMsgType.Error, "NOT CONNECTED!");
819
        }
820
        private void _getVersion()
821
        {
822
            _sendControllerMessage('v', 0);
823
        }
824
        /// <summary>
825
        /// get FC version struct via NC
826
        /// by sending '1' as data (not documented in wiki...)
827
        /// returns HW error 255 (comment in uart1.c : tells the KopterTool that it is the FC-version)
828
        /// </summary>
829
        /// <param name="ctrl">controller number 1=FC</param> 
830
        private void _getVersion(byte ctrl)
831
        {
832
            _sendControllerMessage('v', 0, new byte[1] {ctrl});
833
        }
834
        /// <summary>
835
        /// Switch back to NC by sending the 'Magic Packet' 0x1B,0x1B,0x55,0xAA,0x00
836
        /// </summary>
837
        private void _switchToNC()
838
        {
839
            if (simpleSerialPort.Port.IsOpen)
840
            {
841
                Stream serialStream = simpleSerialPort.Port.BaseStream;
842
                byte[] bytes = new byte[5] { 0x1B,0x1B,0x55,0xAA,0x00 };
843
                serialStream.Write(bytes, 0, bytes.Length);
844
 
845
                Thread.Sleep(100);
846
                _getVersion();
847
                Thread.Sleep(100);
848
                _OSDMenue(0);
849
            }
850
            else
851
                Log(LogMsgType.Error, "NOT CONNECTED!");
852
        }
853
        /// <summary>
854
        /// switch to FC
855
        /// </summary>
856
        private void _switchToFC()
857
        {
858
            _sendControllerMessage('u', 2, new byte[1] { (byte)0 });
859
            Thread.Sleep(100);
860
            _getVersion();
861
            Thread.Sleep(100);
862
            _OSDMenue(0);
863
        }
864
        /// <summary>
865
        /// send RESET signal to FC
866
        /// </summary>
867
        private void _resetCtrl()
868
        {
869
            _sendControllerMessage('R', 1);
870
        }
871
        /// <summary>
872
        /// poll the debug data (4sec subscription)
873
        /// </summary>
874
        /// <param name="auto"> onetimequery(false) or autoupdate(true) with set timing interval </param>
875
        private void _readDebugData(bool auto)
876
        {
877
            byte interval = auto ? debugInterval : (byte)0;
878
            _sendControllerMessage('d', 0, new byte[1] { debugInterval });
879
        }
880
        /// <summary>
881
        /// poll the BL-CTRL status via NC (4sec subscription)
882
        /// </summary>
883
        /// <param name="auto"> onetimequery(false) or autoupdate(true) with set timing interval </param>
884
        private void _readBLCtrl(bool auto)
885
        {
886
            byte interval = auto ? blctrlInterval : (byte)0;
887
            _sendControllerMessage('k', 0, new byte[1] { interval });
888
        }
889
        /// <summary>
890
        /// poll the NC data struct (4sec subscription)
891
        /// </summary>
892
        /// <param name="auto"> onetimequery(false) or autoupdate(true) with set timing interval </param>
893
        private void _readNavData(bool auto)
894
        {
895
            byte interval = auto ? navctrlInterval : (byte)0;
896
            _sendControllerMessage('o', 2, new byte[1] { interval });
897
        }
898
        /// <summary>
899
        /// get the errortext for pending NC error
900
        /// </summary>
901
        private void _readNCError()
902
        {
903
            _sendControllerMessage('e', 2);
904
        }
905
        /// <summary>
906
        /// start/stop continous polling of controller values
907
        /// </summary>
908
        /// <param name="b">start/stop switch</param>
909
        void _readCont(bool b)
910
        {
911
            bReadContinously = b;
912
            btnReadDebugCont.Invoke((Action)(() => btnReadDebugCont.Text = bReadContinously ? "stop automatic" + Environment.NewLine + "data refresh" : "start automatic" + Environment.NewLine + "data refresh"));
913
            btnReadDebugCont.Invoke((Action)(() => btnReadDebugCont.BackColor = bReadContinously ? Color.FromArgb(192, 255, 192) : Color.FromArgb(224, 224, 224)));
914
            if (bReadContinously)
915
            {
916
                _readDebugData(true);
917
                if (_iCtrlAct == 2) { Thread.Sleep(10); _readBLCtrl(true);}
918
                if (_iCtrlAct == 2) { Thread.Sleep(10); _readNavData(true);}
919
                Thread.Sleep(10);
920
                _OSDMenueAutoRefresh();
921
                lblLifeCounter.Invoke((Action)(() => lblLifeCounter.BackColor = Color.FromArgb(0, 224, 0)));
922
            }
923
            else
924
                lblLifeCounter.Invoke((Action)(() => lblLifeCounter.BackColor = Color.FromArgb(224, 224, 224)));
925
            _iLifeCounter = 0;
926
        }
927
        /// <summary>
928
        /// set fieldtexts to "NA" when not available with FC
929
        /// </summary>
930
        void _setFieldsNA()
931
        {
932
            Thread.Sleep(100);
933
            Label lbCur = new Label(), lbTemp = new Label();
934
            for (int i = 0; i < 8; i++)
935
            {
936
                //BL-Ctrl Temp & Current
937
                switch (i)
938
                {
939
                    case 0:
940
                        lbCur = LBLNCM1Cur;
941
                        lbTemp = LBLNCM1Temp;
942
                        break;
943
                    case 1:
944
                        lbCur = LBLNCM2Cur;
945
                        lbTemp = LBLNCM2Temp;
946
                        break;
947
                    case 2:
948
                        lbCur = LBLNCM3Cur;
949
                        lbTemp = LBLNCM3Temp;
950
                        break;
951
                    case 3:
952
                        lbCur = LBLNCM4Cur;
953
                        lbTemp = LBLNCM4Temp;
954
                        break;
955
                    case 4:
956
                        lbCur = LBLNCM5Cur;
957
                        lbTemp = LBLNCM5Temp;
958
                        break;
959
                    case 5:
960
                        lbCur = LBLNCM6Cur;
961
                        lbTemp = LBLNCM6Temp;
962
                        break;
963
                    case 6:
964
                        lbCur = LBLNCM7Cur;
965
                        lbTemp = LBLNCM7Temp;
966
                        break;
967
                    case 7:
968
                        lbCur = LBLNCM8Cur;
969
                        lbTemp = LBLNCM8Temp;
970
                        break;
971
                }
972
                if (lbCur != null)
973
                    lbCur.Invoke((Action)(() => lbCur.Text = "NA"));
974
                if (lbTemp != null)
975
                    lbTemp.Invoke((Action)(() => lbTemp.Text = "NA"));
976
 
977
            }
978
            lblNCFlTime.Invoke((Action)(() => lblNCFlTime.Text = "NA"));    //FlightTime
979
            lblNCErrNmbr.Invoke((Action)(() => lblNCErrNmbr.Text = "NA")); //NC ErrorNr
980
            lblNCMF.Invoke((Action)(() => lblNCMF.Text = "NA"));           //earth magnet field
981
            lblNCGSpeed.Invoke((Action)(() => lblNCGSpeed.Text = "NA")); //GroundSpeed
982
            lblNCDist.Invoke((Action)(() => lblNCDist.Text = "NA")); //Distance to HP
983
            lblNCSat.Invoke((Action)(() => lblNCSat.Text = "NA"));      //Sats used
984
        }
985
        /// <summary>
986
        /// one time query of the OSD Menue with pagenumber
987
        /// </summary>
988
        /// <param name="iMenue">Menue page</param>
989
        void _OSDMenue(int iMenue)
990
        {
991
            if (simpleSerialPort.Port.IsOpen)
992
            {
993
                if (iMenue > iOSDMax)
994
                    iMenue = 0;
995
                Stream serialStream = simpleSerialPort.Port.BaseStream;
996
                byte[] bytes = FlightControllerMessage.CreateMessage('l', 0, new byte[1] { (byte)iMenue });
997
                serialStream.Write(bytes, 0, bytes.Length);
998
            }
999
            else
1000
                Log(LogMsgType.Error, "NOT CONNECTED!");
1001
 
1002
        }
1003
        /// <summary>
1004
        /// call the OSDMenue and start autorefresh
1005
        ///  usually by sending a menuekey
1006
        /// a bit tricky - but by sending inverted value of 32 (32 = 0010 0000) you can start the OSD menue with autoupdate (abo) without switching the page with the keyvalues (0x1, 0x2)
1007
        /// therefore the value has to be negative (inverted) in order to distinguish from old (2 line) menuestyle
1008
        /// and must not have any bits of the menue keys 0x1 0x2 0x4 0x8 (0x10?) --> 0x20 = -33
1009
        /// </summary>
1010
        void _OSDMenueAutoRefresh()
1011
        {
1012
            _sendControllerMessage('h', 0, new byte[2] { unchecked((byte)(-33)),OSDInterval });
1013
        }
1014
        void _OSDMenueAutoRefresh(byte key)
1015
        {
1016
            _sendControllerMessage('h', 0, new byte[2] { unchecked((byte)~key), OSDInterval });
1017
        }
1018
        /// <summary>
1019
        /// initialize the OSD menue combobox
1020
        /// combox is filled by numbers from 0 to max pagenumber
1021
        /// </summary>
1022
        void _initOSDCB()
1023
        {
1024
            _bCBInit = true;
1025
            if(iOSDMax == 0)
1026
            {
1027
                _OSDMenue(0);
1028
                Thread.Sleep(10);
1029
            }
1030
            cbOSD.Invoke((Action)(()=>cbOSD.Items.Clear()));
1031
            for(int i = 0; i <= iOSDMax;i++)
1032
            {
1033
                cbOSD.Invoke((Action)(() => cbOSD.Items.Add(i)));
1034
            }
1035
            cbOSD.Invoke((Action)(() => cbOSD.SelectedItem = iOSDPage));
1036
            _bCBInit = false;
1037
        }
1038
        void _readIni()
1039
        {
1040
            if (!File.Exists(filePath + "\\MKLiveViewSettings.ini"))
1041
                _writeIni();
1042
            IniFile ini = new IniFile("MKLiveViewSettings.ini");
1043
            ini.path = filePath + "\\MKLiveViewSettings.ini";
1044
 
1045
            string sVal = ini.IniReadValue("default", "AutorefreshDebugData");
1046
            _debugDataAutorefresh = Convert.ToBoolean(sVal);
1047
            sVal = ini.IniReadValue("default", "AutorefreshNavCtrlData");
1048
            _navCtrlDataAutorefresh = Convert.ToBoolean(sVal);
1049
            sVal = ini.IniReadValue("default", "AutorefreshBLCtrlData");
1050
            _blctrlDataAutorefresh = Convert.ToBoolean(sVal);
1051
            sVal = ini.IniReadValue("default", "AutorefreshOSDData");
1052
            _OSDAutorefresh = Convert.ToBoolean(sVal);
1053
 
1054
            sVal = ini.IniReadValue("default", "IntervalDebugData");
1055
            debugInterval = (byte)Convert.ToInt16(sVal);
1056
            sVal = ini.IniReadValue("default", "IntervalNavCtrlData");
1057
            navctrlInterval = (byte)Convert.ToInt16(sVal);
1058
            sVal = ini.IniReadValue("default", "IntervalBLCtrlData");
1059
            blctrlInterval = (byte)Convert.ToInt16(sVal);
1060
            sVal = ini.IniReadValue("default", "IntervalOSDData");
1061
            OSDInterval = (byte)Convert.ToInt16(sVal);
1062
        }
1063
        void _writeIni()
1064
        {
1065
 
1066
            IniFile ini = new IniFile("MKLiveViewSettings.ini");
1067
            ini.path = filePath + "\\MKLiveViewSettings.ini";
1068
 
1069
            ini.IniWriteValue("default", "AutorefreshDebugData", _debugDataAutorefresh ? "true":"false");
1070
            ini.IniWriteValue("default", "AutorefreshNavCtrlData", _navCtrlDataAutorefresh ? "true":"false");
1071
            ini.IniWriteValue("default", "AutorefreshBLCtrlData", _blctrlDataAutorefresh ? "true":"false");
1072
            ini.IniWriteValue("default", "AutorefreshOSDData", _OSDAutorefresh ? "true":"false");
1073
 
1074
            ini.IniWriteValue("default", "IntervalDebugData", debugInterval.ToString());
1075
            ini.IniWriteValue("default", "IntervalNavCtrlData", navctrlInterval.ToString());
1076
            ini.IniWriteValue("default", "IntervalBLCtrlData", blctrlInterval.ToString());
1077
            ini.IniWriteValue("default", "IntervalOSDData", OSDInterval.ToString());
1078
        }
1079
 
1080
        #endregion functions
1081
 
1082
        #region buttons
1083
        private void buttonReset_Click(object sender, EventArgs e)
1084
        {
1085
            _resetCtrl();
1086
        }
1087
        private void btnVersion_Click(object sender, EventArgs e)
1088
        {
1089
            _getVersion();
1090
        }
1091
        private void btnAnalogLabels_Click(object sender, EventArgs e)
1092
        {
1093
            _getAnalogLabels(0);
1094
        }
1095
        private void btnDbgData_Click(object sender, EventArgs e)
1096
        {
1097
            _readDebugData(false); //onetime reading of debug data --> subscription lasts 4sec - this means you will receive data for 4 seconds
1098
        }
1099
        private void btnSaveLabels_Click(object sender, EventArgs e)
1100
        {
1101
            switch (_iCtrlAct)
1102
            {
1103
                case 1:
1104
                    fileName = "FCLabelTexts.txt";
1105
                    break;
1106
                case 2:
1107
                    fileName = "NCLabelTexts.txt";
1108
                    break;
1109
                default:
1110
                    fileName = "NCLabelTexts.txt";
1111
                    break;
1112
            }
1113
            if (sAnalogLabel[0] != null)
1114
            {
1115
                File.WriteAllLines(filePath + "\\" + fileName, sAnalogLabel);
1116
                Console.WriteLine("Names saved to file");
1117
                _loadLabelFile();
1118
            }
1119
            else
1120
                Log(LogMsgType.Warning, "there's no data -> read first from fc/nc!");
1121
        }
1122
        private void btnLoadLabels_Click(object sender, EventArgs e)
1123
        {
1124
            _assignLabelNames();
1125
        }
1126
        private void btnReadLabelFile_Click(object sender, EventArgs e)
1127
        {
1128
            _loadLabelFile();
1129
        }
1130
        private void btnSwitchFC_Click(object sender, EventArgs e)
1131
        {
1132
            _switchToFC();
1133
        }
1134
        private void btnSwitchNC_Click(object sender, EventArgs e)
1135
        {
1136
            _switchToNC();
1137
        }
1138
        private void btnReadDbgCont_Click(object sender, EventArgs e)
1139
        {
1140
            _readCont(!bReadContinously);
1141
        }
1142
        private void btnReadBLCtrl_Click(object sender, EventArgs e)
1143
        {
1144
 
1145
            if (_iCtrlAct == 2) _readBLCtrl(false);
1146
            else Log(LogMsgType.Warning, "only available when connected to NC");
1147
        }
1148
        private void btnGetNaviData_Click(object sender, EventArgs e)
1149
        {
1150
            if (_iCtrlAct == 2) _readNavData(false);
1151
            else Log(LogMsgType.Warning, "only available when connected to NC");
1152
        }
1153
        private void btnConn_Click(object sender, EventArgs e)
1154
        {
1155
            simpleSerialPort.Connect(!simpleSerialPort.Port.IsOpen);
1156
        }
1157
        private void button3_Click(object sender, EventArgs e)
1158
        {
1159
            _getVersion(1);
1160
        }
1161
        private void button4_Click(object sender, EventArgs e)
1162
        {
1163
            _getVersion(2);
1164
        }
1165
        private void btnOSD_Click(object sender, EventArgs e)
1166
        {
1167
            if (iOSDPage > iOSDMax)
1168
                iOSDPage = 0;
1169
            _OSDMenue(iOSDPage);
1170
        }
1171
        private void btnOSDForward_Click(object sender, EventArgs e)
1172
        {
1173
            iOSDPage++;
1174
            if (iOSDPage > iOSDMax)
1175
                iOSDPage = 0;
1176
 
1177
            _OSDMenue(iOSDPage);
1178
        }
1179
        private void btnOSDBackward_Click(object sender, EventArgs e)
1180
        {
1181
            iOSDPage--;
1182
            if (iOSDPage < 0)
1183
                iOSDPage = iOSDMax;
1184
 
1185
            _OSDMenue(iOSDPage);
1186
        }
1187
        private void btnOSDAuto_Click(object sender, EventArgs e)
1188
        {
1189
            _OSDMenueAutoRefresh();
1190
        }
1191
        /// call the OSDMenue with Key 0x8
1192
        private void btnOSDLeave_Click(object sender, EventArgs e)
1193
        {
1194
            _OSDMenueAutoRefresh(8);
1195
        }
1196
        /// call the OSDMenue with Key 0x4
1197
        private void btnOSDEnter_Click(object sender, EventArgs e)
1198
        {
1199
            _OSDMenueAutoRefresh(4);
1200
        }
1201
        #endregion buttons
1202
 
1203
    }
1204
    public class IniFile
1205
    {
1206
        public string path;
1207
 
1208
        [DllImport("kernel32")]
1209
        private static extern long WritePrivateProfileString(string section,
1210
          string key, string val, string filePath);
1211
 
1212
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
1213
        static extern uint GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer,
1214
               uint nSize, string lpFileName);
1215
 
1216
        [DllImport("kernel32")]
1217
        private static extern int GetPrivateProfileString(string section,
1218
          string key, string def, StringBuilder retVal,
1219
          int size, string filePath);
1220
 
1221
        public IniFile(string INIPath)
1222
        {
1223
            path = INIPath;
1224
        }
1225
 
1226
        public void IniWriteValue(string Section, string Key, string Value)
1227
        {
1228
            WritePrivateProfileString(Section, Key, Value, this.path);
1229
        }
1230
 
1231
        public string IniReadValue(string Section, string Key)
1232
        {
1233
            StringBuilder temp = new StringBuilder(255);
1234
            int i = GetPrivateProfileString(Section, Key, "", temp, 255, this.path);
1235
            return temp.ToString();
1236
        }
1237
        //Ini_sections auslesen in String-Array
1238
        public string[] IniSectionNames()
1239
        {
1240
 
1241
            //  uint MAX_BUFFER = 32767;
1242
            uint MAX_BUFFER = 8388608;
1243
            IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER);
1244
            uint bytesReturned = GetPrivateProfileSectionNames(pReturnedString, MAX_BUFFER, this.path);
1245
            if (bytesReturned == 0)
1246
            {
1247
                Marshal.FreeCoTaskMem(pReturnedString);
1248
                return null;
1249
            }
1250
            string local = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned).ToString();
1251
            Marshal.FreeCoTaskMem(pReturnedString);
1252
            //use of Substring below removes terminating null for split
1253
            return local.Substring(0, local.Length - 1).Split('\0');
1254
 
1255
 
1256
        }
1257
    }
1258
    public static class ControlExtensions
1259
    {
1260
        /// <summary> 
1261
        /// Execute a threadsafe operation, when accessing a control via another thread 
1262
        /// action is a lamdaexpression
1263
        /// e.g. comboBox1.ExecuteThreadSafe(() => comboBox1.Enabled = true);
1264
        /// </summary>
1265
        /// <param name="control"> The control </param>
1266
        /// <param name="action"> The 'action' to perform </param>
1267
        public static void ExecuteThreadSafe(this Control control, Action action)
1268
        {
1269
            if (control.InvokeRequired)
1270
            {
1271
                control.BeginInvoke(action); //"BeginInvoke" is an async call -> threadsafety error when called to many times successively -> then take "Invoke"
1272
            }
1273
            else
1274
            {
1275
                action.Invoke();
1276
            }
1277
        }
1278
    }
1279
 
1280
}