///============================================================================
/// MKLiveView
/// Copyright © 2016 Steph
///
///This file is part of MKLiveView.
///
///MKLiveView is free software: you can redistribute it and/or modify
///it under the terms of the GNU General Public License as published by
///the Free Software Foundation, either version 3 of the License, or
///(at your option) any later version.
///
///MKLiveView is distributed in the hope that it will be useful,
///but WITHOUT ANY WARRANTY; without even the implied warranty of
///MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
///GNU General Public License for more details.
///
///You should have received a copy of the GNU General Public License
///along with cssRcon. If not, see <http://www.gnu.org/licenses/>.
///
///============================================================================
///Credits:
///Chootair (http://www.codeproject.com/script/Membership/View.aspx?mid=3941737)
///for his "C# Avionic Instrument Controls" (http://www.codeproject.com/Articles/27411/C-Avionic-Instrument-Controls)
///I used some of his code for displaying the compass
///
///Tom Pyke (http://tom.pycke.be)
///for his "Artifical horizon" (http://tom.pycke.be/mav/100/artificial-horizon)
///Great job!
///
/// and last but most of all to JOHN C. MACDONALD at Ira A. Fulton College of Engineering and Technology
/// for his MIKROKOPTER SERIAL CONTROL TUTORIAL (http://hdl.lib.byu.edu/1877/2747)
/// and the sourcecode (http://hdl.lib.byu.edu/1877/2748)
/// By his work I finally managed to get the communication with the Mikrokopter controllers to run
/// Some of his code was used in this programm like the SimpelSerialPort class (with some changes)
/// and the FilghtControllerMessage class
///
///============================================================================
/// DISCLAIMER
/// ===========
///
/// I created this software with my best knowledge and belief.
///
/// IN NO EVENT, UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING,
/// SHALL I, OR ANY PERSON BE LIABLE FOR ANY LOSS, EXPENSE OR DAMAGE,
/// OF ANY TYPE OR NATURE ARISING OUT OF THE USE OF,
/// OR INABILITY TO USE THIS SOFTWARE OR PROGRAM,
/// INCLUDING, BUT NOT LIMITED TO, CLAIMS, SUITS OR CAUSES OF ACTION
/// INVOLVING ALLEGED INFRINGEMENT OF COPYRIGHTS,
/// PATENTS, TRADEMARKS, TRADE SECRETS, OR UNFAIR COMPETITION.
///
/// This means: use it & have fun (but @ Your own risk...)
/// ===========================================================================
using System;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace MKLiveView
{
public partial class MainForm
: Form
{
String[] NC_Error
= new string[44]
{
"No Error",
"FC not compatible" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A1_.22FC_not_compatible_.22",
"MK3Mag not compatible" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A2_.22MK3Mag_not_compatible_.22",
"no FC communication" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A3_.22no_FC_communication_.22",
"no compass communication" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A4_.22no_compass_communication_.22",
"no GPS communication" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A5_.22no_GPS_communication_.22",
"bad compass value" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A6_.22bad_compass_value.22",
"RC Signal lost" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A7_.22RC_Signal_lost_.22",
"FC spi rx error" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A8_.22FC_spi_rx_error_.22",
"ERR: no NC communication" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A9:_.22ERR:_no_NC_communication.22",
"ERR: FC Nick Gyro" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A10_.22ERR:_FC_Nick_Gyro.22",
"ERR: FC Roll Gyro" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A11_.22ERR:_FC_Roll_Gyro.22",
"ERR: FC Yaw Gyro" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A12_.22ERR:_FC_Yaw_Gyro.22",
"ERR: FC Nick ACC" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A13_.22ERR:_FC_Nick_ACC.22",
"ERR: FC Roll ACC" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A14_.22ERR:_FC_Roll_ACC.22",
"ERR: FC Z-ACC" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A15_.22ERR:_FC_Z-ACC.22",
"ERR: Pressure sensor" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A16_.22ERR:_Pressure_sensor.22",
"ERR: FC I2C" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A17_.22ERR:_FC_I2C.22",
"ERR: Bl Missing" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A18_.22ERR:_Bl_Missing.22",
"Mixer Error" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A19_.22Mixer_Error.22",
"FC: Carefree Error" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A20_.22FC:_Carefree_Error.22",
"ERR: GPS lost" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A21_.22ERR:_GPS_lost.22",
"ERR: Magnet Error" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A22_.22ERR:_Magnet_Error.22",
"Motor restart" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A23_.22Motor_restart.22",
"BL Limitation" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A24_.22BL_Limitation.22",
"Waypoint range" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A25_.22Waypoint_range.22",
"ERR:No SD-Card" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A26_.22ERR:No_SD-Card.22",
"ERR:SD Logging aborted" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A27_.22ERR:SD_Logging_aborted.22",
"ERR:Flying range!" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A28_.22ERR:Flying_range.21.22",
"ERR:Max Altitude" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A29_.22ERR:Max_Altitude.22",
"No GPS Fix" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A30_.22No_GPS_Fix.22",
"compass not calibrated" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A31_.22compass_not_calibrated.22",
"ERR:BL selftest" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A32_.22ERR:BL_selftest.22",
"no ext. compass" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A33_.22no_ext._compass.22",
"compass sensor" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A34_.22compass_sensor.22",
"FAILSAFE pos.!" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A35_.22FAILSAFE_pos..21__.22",
"ERR:Redundancy" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A36_.22ERR:Redundancy__.22",
"Redundancy test" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A37_.22Redundancy_test_.22",
"GPS Update rate" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A38_.22GPS_Update_rate.22",
"ERR:Canbus" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A39_.22ERR:Canbus.22",
"ERR: 5V RC-Supply" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A40_.22ERR:_5V_RC-Supply.22",
"ERR:Power-Supply" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A41_.22ERR:Power-Supply.22",
"ACC not calibr." + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A42_.22ACC_not_calibr..22",
"ERR:Parachute!" + Environment
.NewLine + "http://wiki.mikrokopter.de/ErrorCodes#A43_.22ERR:Parachute.21.22"
};
[FlagsAttribute
]
enum NC_HWError0
: short
{
None
= 0,
SPI_RX
= 1,
COMPASS_RX
= 2,
FC_INCOMPATIBLE
= 4,
COMPASS_INCOMPATIBLE
= 8,
GPS_RX
= 16,
COMPASS_VALUE
= 32
};
[FlagsAttribute
]
enum FC_HWError0
: short
{
None
= 0,
GYRO_NICK
= 1,
GYRO_ROLL
= 2,
GYRO_YAW
= 4,
ACC_NICK
= 8,
ACC_ROLL
= 16,
ACC_TOP
= 32,
PRESSURE
= 64,
CAREFREE
= 128
};
[FlagsAttribute
]
enum FC_HWError1
: short
{
None
= 0,
I2C
= 1,
BL_MISSING
= 2,
SPI_RX
= 4,
PPM
= 8,
MIXER
= 16,
RC_VOLTAGE
= 32,
ACC_NOT_CAL
= 64,
RES3
= 128
};
public enum LogMsgType
{ Incoming, Outgoing, Normal, Warning, Error
};
// Various colors for logging info
private Color
[] LogMsgTypeColor
= { Color
.FromArgb(43,
145,
175), Color
.Green, Color
.Black, Color
.Orange, Color
.Red };
string[] sAnalogLabel
= new string[32];
string[] sAnalogData
= new string[32];
bool bReadContinously
= false;
bool check_HWError
= false;
bool _bCBInit
= true;
bool _init
= true;
bool _debugDataAutorefresh
= true;
bool _navCtrlDataAutorefresh
= true;
bool _blctrlDataAutorefresh
= true;
bool _OSDAutorefresh
= true;
bool _bErrorLog
= false;
int crcError
= 0;
int iLableIndex
= 0;
string filePath
= Directory
.GetCurrentDirectory();
string fileName
= "NCLabelTexts.txt";
int _iCtrlAct
= 0;
int _iLifeCounter
= 0;
int iOSDPage
= 0;
int iOSDMax
= 0;
int[] serChan
= new int[12] { 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0 };
int[] serChan_sub
= new int[12] { 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0 };
string[] serChanTitle
= new string[12];
/// <summary>
/// interval for sending debugdata (multiplied by 10ms)
/// </summary>
byte debugInterval
= 10; //(=> 100ms)
/// <summary>
/// interval for sending BL-CTRL status (multiplied by 10ms)
/// </summary>
byte blctrlInterval
= 75;
/// <summary>
/// interval for sending NAV-CTRL status (multiplied by 10ms)
/// </summary>
byte navctrlInterval
= 80;
/// <summary>
/// interval for sending OSD page update (multiplied by 10ms)
/// </summary>
byte OSDInterval
= 85;
/// <summary>
/// datatable for the debug data array - displayed on settings tabpage in datagridview
/// </summary>
DataTable dtAnalog
= new DataTable
();
/// <summary>
/// datatable for motordata (current,temp)
/// </summary>
DataTable dtMotors1
= new DataTable
();
DataTable dtMotors2
= new DataTable
();
DataTable dtWaypoints
= new DataTable
();
public MainForm
()
{
InitializeComponent
();
_initForm
();
}
void _initForm
()
{
serChanTitle
.Initialize();
_readIni
();
_dataTablesInit
();
simpleSerialPort
.PortClosed += SimpleSerialPort_PortClosed
;
simpleSerialPort
.PortOpened += SimpleSerialPort_PortOpened
;
simpleSerialPort
.DataReceived += processMessage
;
chkbAutoBL
.Checked = _blctrlDataAutorefresh
;
chkbAutoDbg
.Checked = _debugDataAutorefresh
;
chkbAutoNav
.Checked = _navCtrlDataAutorefresh
;
chkbAutoOSD
.Checked = _OSDAutorefresh
;
labelTimingDebug
.Text = (debugInterval
* 10).ToString();
labelTimingBLCTRL
.Text = (blctrlInterval
* 10).ToString();
labelTimingNAV
.Text = (navctrlInterval
* 10).ToString();
labelTimingOSD
.Text = (OSDInterval
* 10).ToString();
TabControl1
.TabPages.Remove(tabPageTesting
); //a testing page
}
#region events
private void MainForm_Shown
(object sender, EventArgs e
)
{
_loadLabelNames
();
_initSerialCtrl
();
_init
= false;
splitContainer1
.SplitterDistance = 510;
}
private void MainForm_FormClosed
(object sender, FormClosedEventArgs e
)
{
_writeIni
();
// after adding a second language the programm didn't close properly anymore
// so this is kinda workaround...
Dispose
(true);
Environment
.Exit(0);
}
private void SimpleSerialPort_PortOpened
()
{
btnConn
.Invoke((Action
)(() => btnConn
.BackColor = Color
.FromArgb(192,
255,
192)));
if(Thread
.CurrentThread.CurrentUICulture.Name== "")
btnConn
.Invoke((Action
)(() => btnConn
.Text = "close" + Environment
.NewLine + "serial port"));
else
btnConn
.Invoke((Action
)(() => btnConn
.Text = "COM-Port" + Environment
.NewLine + "schliessen"));
_getVersion
();
Thread
.Sleep(100);
_OSDMenue
(0);
Thread
.Sleep(200);
_sendSerialData
();
// _readCont(true);
}
private void SimpleSerialPort_PortClosed
()
{
btnConn
.Invoke((Action
)(() => btnConn
.BackColor = Color
.FromArgb(224,
224,
224)));
if (Thread
.CurrentThread.CurrentUICulture.Name == "")
btnConn
.Invoke((Action
)(() => btnConn
.Text = "open" + Environment
.NewLine + "serial port"));
else
btnConn
.Invoke((Action
)(() => btnConn
.Text = "COM-Port" + Environment
.NewLine + "öffnen"));
_readCont
(false);
}
/// <summary>
/// timer for refreshing subscription of subscribed data
/// query lifecounter for connection failure
/// </summary>
private void timer1_Tick
(object sender, EventArgs e
)
{
if(bReadContinously
)
{
if (_debugDataAutorefresh
) { _readDebugData
(true); Thread
.Sleep(10); }
if (_blctrlDataAutorefresh
) { _readBLCtrl
(true); Thread
.Sleep(10); }
if (_navCtrlDataAutorefresh
&& _iCtrlAct
== 2) { _readNavData
(true); Thread
.Sleep(10); }
check_HWError
= true;
_getVersion
();
Thread
.Sleep(10);
if (_OSDAutorefresh
) { _OSDMenueAutoRefresh
(); }
if (_iLifeCounter
> 0)
{
lblLifeCounter
.BackColor = Color
.FromArgb(0,
224,
0);
_iLifeCounter
= 0;
}
else
{
Log
(LogMsgType
.Error,
"No communication to NC/FC!");
lblLifeCounter
.BackColor = Color
.FromArgb(224,
0,
0);
}
}
}
private void cbOSD_SelectedIndexChanged
(object sender, EventArgs e
)
{
if (!_bCBInit
&& cbOSD
.SelectedIndex > -1)
_OSDMenue
(cbOSD
.SelectedIndex);
}
private void chkbAutoDbg_CheckedChanged
(object sender, EventArgs e
)
{
if(!_init
) _debugDataAutorefresh
= chkbAutoDbg
.Checked;
}
private void chkbAutoNav_CheckedChanged
(object sender, EventArgs e
)
{
if (!_init
) _navCtrlDataAutorefresh
= chkbAutoNav
.Checked;
}
private void chkbAutoBL_CheckedChanged
(object sender, EventArgs e
)
{
if (!_init
) _blctrlDataAutorefresh
= chkbAutoBL
.Checked;
}
private void chkbAutoOSD_CheckedChanged
(object sender, EventArgs e
)
{
if (!_init
) _OSDAutorefresh
= chkbAutoOSD
.Checked;
}
private void cbTimingDebug_SelectedIndexChanged
(object sender, EventArgs e
)
{
if (cbTimingDebug
.SelectedIndex > -1)
{
debugInterval
= (byte)(Convert
.ToInt16(cbTimingDebug
.SelectedItem) / 10);
labelTimingDebug
.Text = (debugInterval
* 10).ToString();
}
}
private void cbTimingNAV_SelectedIndexChanged
(object sender, EventArgs e
)
{
if (cbTimingNAV
.SelectedIndex > -1)
{
navctrlInterval
= (byte)(Convert
.ToInt16(cbTimingNAV
.SelectedItem) / 10);
labelTimingNAV
.Text = (navctrlInterval
* 10).ToString();
}
}
private void cbTimingBLCTRL_SelectedIndexChanged
(object sender, EventArgs e
)
{
if (cbTimingBLCTRL
.SelectedIndex > -1)
{
blctrlInterval
= (byte)(Convert
.ToInt16(cbTimingBLCTRL
.SelectedItem) / 10);
labelTimingBLCTRL
.Text = (blctrlInterval
* 10).ToString();
}
}
private void cbTimingOSD_SelectedIndexChanged
(object sender, EventArgs e
)
{
if (cbTimingOSD
.SelectedIndex > -1)
{
OSDInterval
= (byte)(Convert
.ToInt16(cbTimingOSD
.SelectedItem) / 10);
labelTimingOSD
.Text = (OSDInterval
* 10).ToString();
}
}
private void rtfError_LinkClicked
(object sender, LinkClickedEventArgs e
)
{
System.Diagnostics.Process.Start(e
.LinkText);
}
/// <summary>
/// Combobox for selecting UI language
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cbLanguage_SelectedIndexChanged
(object sender, EventArgs e
)
{
if (cbLanguage
.SelectedIndex == 1)
Thread
.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de-DE");
else
Thread
.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("");
updateStringRessource
();
}
/// <summary>
/// the form has to be recreated when changing the language of the UI
/// </summary>
private void updateStringRessource
()
{
try
{
Point pt
= this.Location;// memorize location of form
Size sz
= this.Size;// memorize size of form
if (simpleSerialPort
.Port.IsOpen)
{
simpleSerialPort
.Port.Close();
Thread
.Sleep(200);
_readCont
(false);
Thread
.Sleep(100);
while (simpleSerialPort
.Port.IsOpen | bReadContinously
)
Thread
.Sleep(100);
}
this.Controls.Clear();// clear all controls of form
components
.Dispose();// dispose all components and release resources
// delete all events to avoid double instances when calling InitializeComponent();
this.Events.Dispose();
if (timer1
!= null)
{
timer1
.Dispose();
timer1
= null;
}
_init
= true;
timer1
= new System.Windows.Forms.Timer();
dtAnalog
= new DataTable
();
dtMotors1
= new DataTable
();
dtMotors2
= new DataTable
();
dtWaypoints
= new DataTable
();
InitializeComponent
(); // reload UI
_dataTablesInit
();
simpleSerialPort
.PortClosed += SimpleSerialPort_PortClosed
;
simpleSerialPort
.PortOpened += SimpleSerialPort_PortOpened
;
simpleSerialPort
.DataReceived += processMessage
;
chkbAutoBL
.Checked = _blctrlDataAutorefresh
;
chkbAutoDbg
.Checked = _debugDataAutorefresh
;
chkbAutoNav
.Checked = _navCtrlDataAutorefresh
;
chkbAutoOSD
.Checked = _OSDAutorefresh
;
labelTimingDebug
.Text = (debugInterval
* 10).ToString();
labelTimingBLCTRL
.Text = (blctrlInterval
* 10).ToString();
labelTimingNAV
.Text = (navctrlInterval
* 10).ToString();
labelTimingOSD
.Text = (OSDInterval
* 10).ToString();
TabControl1
.TabPages.Remove(tabPageTesting
); //a testing page
this.Size = sz
;// set size
this.Location = pt
;// position form
_loadLabelNames
();
_initSerialCtrl
();
_init
= false;
}
catch (Exception ex
)
{
MessageBox
.Show(ex
.Message);
}
}
#endregion events
/// <summary> Log data to the terminal window. </summary>
/// <param name="msgtype"> The type of message to be written. </param>
/// <param name="msg"> The string containing the message to be shown. </param>
private void Log
(LogMsgType msgtype,
string msg
)
{
rtfTerminal
.Invoke(new EventHandler
(delegate
{
if (rtfTerminal
.Lines.Length >= 1000) //Wenn Terminal mehr als 1000 Zeilen hat
rtfTerminal
.Select(42,
(500 * 129)); //500 löschen
rtfTerminal
.Select(rtfTerminal
.Text.Length,
0);
rtfTerminal
.SelectedText = string.Empty;
rtfTerminal
.SelectionFont = new Font
(rtfTerminal
.SelectionFont, FontStyle
.Regular);
rtfTerminal
.SelectionColor = LogMsgTypeColor
[(int)msgtype
];
rtfTerminal
.AppendText(msg
+ Environment
.NewLine);
rtfTerminal
.ScrollToCaret();
}));
}
/// <summary> display the OSD text in 4 lines à 20 chars </summary>
/// <param name="msgtype"> The type of message to be written. </param>
/// <param name="msg"> The string containing the message to be shown. </param>
private void OSD
(LogMsgType msgtype,
string msg
)
{
rtfOSD
.Invoke(new EventHandler
(delegate
{
if (rtfOSD
.Lines.Length > 4)
rtfOSD
.Clear();
rtfOSD
.Select(rtfOSD
.Text.Length,
0);
rtfOSD
.SelectedText = string.Empty;
rtfOSD
.SelectionFont = new Font
(rtfOSD
.SelectionFont, FontStyle
.Regular);
rtfOSD
.SelectionColor = LogMsgTypeColor
[(int)msgtype
];
rtfOSD
.AppendText(msg
+ Environment
.NewLine);
if (rtfOSD
.Text.IndexOf("ERR") > 0)
{
rtfOSD
.Select(rtfOSD
.Text.IndexOf("ERR"),
40);
rtfOSD
.SelectionColor = LogMsgTypeColor
[(int)LogMsgType
.Error];
}
}));
}
private void ErrorLog
(LogMsgType msgtype,
string msg
)
{
rtfError
.Invoke(new EventHandler
(delegate
{
if (rtfError
.Lines.Length > 4)
rtfError
.Clear();
rtfError
.Focus();
rtfError
.Select(rtfError
.Text.Length,
0);
rtfError
.SelectedText = string.Empty;
rtfError
.SelectionFont = new Font
(rtfError
.SelectionFont, FontStyle
.Regular);
rtfError
.SelectionColor = LogMsgTypeColor
[(int)msgtype
];
rtfError
.AppendText(msg
+ Environment
.NewLine);
}));
_bErrorLog
= true;
}
#region functions
#region processing received data
/// <summary> Processing the messages and displaying them in the according form controls
/// function called by simpleSerialPort.DataReceived event
/// </summary>
/// <param name="message"> message bytearray recieved by SimpleSerialPort class </param>
private void processMessage
(byte[] message
)
{
if (message
.Length > 0)
{
_iLifeCounter
++;
//Log(LogMsgType.Incoming, BitConverter.ToString(message));
//Log(LogMsgType.Incoming, message.Length.ToString());
string s
= new string(ASCIIEncoding
.ASCII.GetChars(message,
0, message
.Length));
char cmdID
;
byte adr
;
byte[] data
;
byte[] tmp
= null;
if (message
[0] != '#')
{
int iFound
= -1;
for(int i
=0;i
<message
.Length;i
++) //Sometimes the FC/NC sends strings without termination (like WP messages)
{ //so this is a workaround to not spam the log box
if (message
[i
] == 35)
{
iFound
= i
;
break;
}
}
if(iFound
>0)
{
s
= new string(ASCIIEncoding
.ASCII.GetChars(message,
0,iFound
));
tmp
= new byte[message
.Length - iFound
];
Buffer
.BlockCopy(message, iFound, tmp,
0, message
.Length - iFound
);
}
s
= s
.Trim('\0',
'\n',
'\r');
if(s
.Length > 0)
Log
(LogMsgType
.Normal, s
);
if (tmp
!= null)
{
s
= new string(ASCIIEncoding
.ASCII.GetChars(tmp,
0, tmp
.Length));
processMessage
(tmp
);
}
}
//Debug.Print(s);
else
{
FlightControllerMessage
.ParseMessage(message,
out cmdID,
out adr,
out data
);
if (adr
== 255) { crcError
++; }
else crcError
= 0;
lblCRCErr
.Invoke((Action
)(() => lblCRCErr
.Text = crcError
.ToString()));
//display the active controller (FC / NC)
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...???
{
_iCtrlAct
= adr
;
switch (adr
)
{
case 1:
lblCtrl
.Invoke((Action
)(() => lblCtrl
.Text = "FC"));
lblNCCtrl
.Invoke((Action
)(() => lblNCCtrl
.Text = "FC"));
_setFieldsNA
(); //display fields NA for FC
break;
case 2:
lblCtrl
.Invoke((Action
)(() => lblCtrl
.Text = "NC"));
lblNCCtrl
.Invoke((Action
)(() => lblNCCtrl
.Text = "NC"));
break;
case 3:
lblCtrl
.Invoke((Action
)(() => lblCtrl
.Text = "MK3MAG"));
break;
case 4:
lblCtrl
.Invoke((Action
)(() => lblCtrl
.Text = "BL-CTRL"));
break;
default:
lblCtrl
.Invoke((Action
)(() => lblCtrl
.Text = "...."));
break;
}
_loadLabelNames
();
}
// else
// Debug.Print("Address == 0?");
if (data
!= null && data
.Length > 0)
{
s
= new string(ASCIIEncoding
.ASCII.GetChars(data,
1, data
.Length - 1));
s
= s
.Trim('\0',
'\n');
switch (cmdID
)
{
case 'A': //Label names
_processLabelNames
(s
);
break;
case 'D': //Debug data
_processDebugVals
(adr, data
);
break;
case 'V': //Version
_processVersion
(adr, data
);
break;
case 'K'://BL-CTRL data
_processBLCtrl
(data
);
break;
case 'O': //NC Data
_processNCData
(data
);
break;
case 'E': //NC error-string
ErrorLog
(LogMsgType
.Error,
"NC Error: " + s
);
break;
case 'L': //OSD Menue (called by pagenumber)
_processOSDSingle
(data
);
break;
case 'H': //OSD Menue (with autoupdate - called by Key)
_processOSDAuto
(data
);
break;
case 'X': //Waypoint data
_processWPData
(data
);
break;
//default:
// Log(LogMsgType.Incoming, "cmd: " + cmdID.ToString());
// Log(LogMsgType.Incoming, BitConverter.ToString(data));
// break;
}
}
//else
//{
// Log(LogMsgType.Incoming, "cmd: " + cmdID.ToString());
// Log(LogMsgType.Incoming, BitConverter.ToString(data));
//}
}
}
}
/// <summary>
/// Analog label names 'A'
/// each label name is returned as a single string
/// and added to string array sAnalogLabel[]
/// and the datatable dtAnalog
/// </summary>
/// <param name="s">the label name</param>
void _processLabelNames
(string s
)
{
if (iLableIndex
< 32)
{
sAnalogLabel
[iLableIndex
] = s
;
if (dtAnalog
.Rows.Count < 32)
dtAnalog
.Rows.Add(s,
"");
else
dtAnalog
.Rows[iLableIndex
].SetField(0, s
);
_getAnalogLabels
(iLableIndex
+ 1);
}
Debug
.Print(s
);
}
/// <summary>
/// Debug values 'D'
/// </summary>
/// <param name="adr">adress of the active controller (1-FC, 2-NC)</param>
/// <param name="data">the received byte array to process</param>
void _processDebugVals
(byte adr,
byte[] data
)
{
if (data
.Length == 66)
{
int[] iAnalogData
= new int[32];
int index
= 0;
Int16 i16
= 0;
double dTemp
= 0;
for (int i
= 2; i
< 66; i
+= 2)
{
i16
= data
[i
+ 1];
i16
= (Int16
)(i16
<< 8);
iAnalogData
[index
] = data
[i
] + i16
;
sAnalogData
[index
] = (data
[i
] + i16
).ToString();
dtAnalog
.Rows[index
].SetField(1, sAnalogData
[index
]);
if (adr
== 2) //NC
{
switch (index
)
{
case 0: //pitch (German: nick)
artificialHorizon1
.Invoke((Action
)(() => artificialHorizon1
.pitch_angle = ((double)iAnalogData
[index
] / (double)10)));
lblNCPitch
.Invoke((Action
)(() => lblNCPitch
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0°")));
break;
case 1: //roll
artificialHorizon1
.Invoke((Action
)(() => artificialHorizon1
.roll_angle = ((double)iAnalogData
[index
] / (double)10)));
lblNCRoll
.Invoke((Action
)(() => lblNCRoll
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0°")));
break;
case 4: //altitude
lblNCAlt
.Invoke((Action
)(() => lblNCAlt
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0 m")));
break;
case 7: //Voltage
lblNCVolt
.Invoke((Action
)(() => lblNCVolt
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0 V")));
break;
case 8: // Current
lblNCCur
.Invoke((Action
)(() => lblNCCur
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0 A")));
break;
case 10: //heading
lblNCCompass
.Invoke((Action
)(() => lblNCCompass
.Text = sAnalogData
[index
] + "°"));
headingIndicator1
.Invoke((Action
)(() => headingIndicator1
.SetHeadingIndicatorParameters(iAnalogData
[index
])));
break;
case 12: // SPI error
lblNCSPI
.Invoke((Action
)(() => lblNCSPI
.Text = sAnalogData
[index
]));
break;
case 14: //i2c error
lblNCI2C
.Invoke((Action
)(() => lblNCI2C
.Text = sAnalogData
[index
]));
break;
case 20: //Earthmagnet field
lblNCMF
.Invoke((Action
)(() => lblNCMF
.Text = sAnalogData
[index
] + "%"));
break;
case 21: //GroundSpeed
lblNCGSpeed
.Invoke((Action
)(() => lblNCGSpeed
.Text = ((double)iAnalogData
[index
] / (double)100).ToString("0.00 m/s")));
break;
case 28: //Distance East from saved home position -> calculate distance with distance N + height
dTemp
= Math
.Pow((double)iAnalogData
[index
],
2) + Math
.Pow((double)iAnalogData
[index
- 1],
2);
dTemp
= Math
.Sqrt(dTemp
) / (double)10; //'flat' distance from HP with N/E
// lblNCDist.Invoke((Action)(() => lblNCDist.Text = dTemp.ToString("0.00")));
dTemp
= Math
.Pow(dTemp,
2) + Math
.Pow(((double)iAnalogData
[4] / (double)10),
2); //adding 'height' into calculation
dTemp
= Math
.Sqrt(dTemp
) / (double)10;
lblNCDistHP
.Invoke((Action
)(() => lblNCDistHP
.Text = dTemp
.ToString("0.0 m")));
break;
case 31: //Sats used
lblNCSat
.Invoke((Action
)(() => lblNCSat
.Text = sAnalogData
[index
]));
break;
}
}
if (adr
== 1) //FC
{
switch (index
)
{
case 0: //pitch (German: nick)
artificialHorizon1
.Invoke((Action
)(() => artificialHorizon1
.pitch_angle = ((double)iAnalogData
[index
] / (double)10)));
lblNCPitch
.Invoke((Action
)(() => lblNCPitch
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0°")));
break;
case 1: //roll
artificialHorizon1
.Invoke((Action
)(() => artificialHorizon1
.roll_angle = ((double)iAnalogData
[index
] / (double)10)));
lblNCRoll
.Invoke((Action
)(() => lblNCRoll
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0°")));
break;
case 5: //altitude
lblNCAlt
.Invoke((Action
)(() => lblNCAlt
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0 m")));
break;
case 8: //heading
lblNCCompass
.Invoke((Action
)(() => lblNCCompass
.Text = sAnalogData
[index
] + "°"));
headingIndicator1
.Invoke((Action
)(() => headingIndicator1
.SetHeadingIndicatorParameters(iAnalogData
[index
])));
break;
case 9: //Voltage
lblNCVolt
.Invoke((Action
)(() => lblNCVolt
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0 V")));
break;
case 10: //Receiver quality
lblNCRC
.Invoke((Action
)(() => lblNCRC
.Text = sAnalogData
[index
]));
break;
case 22: // Current
lblNCCur
.Invoke((Action
)(() => lblNCCur
.Text = ((double)iAnalogData
[index
] / (double)10).ToString("0.0 A")));
break;
case 23: //capacity used
lblNCCap
.Invoke((Action
)(() => lblNCCap
.Text = (iAnalogData
[index
]).ToString("0 mAh")));
break;
case 27: // SPI error
lblNCSPI
.Invoke((Action
)(() => lblNCSPI
.Text = sAnalogData
[index
]));
break;
case 28: //i2c error
lblNCI2C
.Invoke((Action
)(() => lblNCI2C
.Text = sAnalogData
[index
]));
break;
}
}
index
++;
}
}
else
Debug
.Print("wrong data-length (66): " + data
.Length.ToString());
}
/// <summary>
/// Version string 'V'
/// </summary>
/// <param name="adr">adress of the active controller (1-FC, 2-NC)</param>
/// <param name="data">the received byte array to process</param>
void _processVersion
(byte adr,
byte[] data
)
{
if (data
.Length == 12)
{
if (!check_HWError
)
{
string[] sVersionStruct
= new string[10] { "SWMajor: ",
"SWMinor: ",
"ProtoMajor: ",
"LabelTextCRC: ",
"SWPatch: ",
"HardwareError 1: ",
"HardwareError 2: ",
"HWMajor: ",
"BL_Firmware: ",
"Flags: " };
string sVersion
= "";
//sbyte[] signed = Array.ConvertAll(data, b => unchecked((sbyte)b));
Log
(LogMsgType
.Warning,
(adr
== 1 ? "FC-" : "NC-") + "Version: ");
sVersion
= "HW V" + (data
[7] / 10).ToString() + "." + (data
[7] % 10).ToString();
Log
(LogMsgType
.Incoming, sVersion
);
sVersion
= "SW V" + (data
[0]).ToString() + "." + (data
[1]).ToString() + ((char)(data
[4] + 'a')).ToString();
Log
(LogMsgType
.Incoming, sVersion
);
Log
(LogMsgType
.Incoming,
"BL-Firmware: V" + (data
[8] / 100).ToString() + "." + (data
[8] % 100).ToString());
}
if (data
[5] > 0) //error0
{
if (adr
== 1)
ErrorLog
(LogMsgType
.Error,
"FC - HW-Error " + data
[5].ToString() + ": " + ((FC_HWError0
)data
[5]).ToString());
if (adr
== 2)
ErrorLog
(LogMsgType
.Error,
"NC - HW-Error " + data
[5].ToString() + ": " + ((NC_HWError0
)data
[5]).ToString());
}
if (data
[6] > 0) //error1
{
if (adr
== 1)
ErrorLog
(LogMsgType
.Error,
"FC - HW-Error " + data
[6].ToString() + ": " + ((FC_HWError1
)data
[6]).ToString());
if (adr
== 2)
ErrorLog
(LogMsgType
.Error,
"NC - Unknown HW-ERROR: " + data
[6].ToString()); //@moment NC has only one error field
}
if((data
[5] + data
[6] == 0) && _bErrorLog
)
_clearErrorLog
(adr
==1 ? "FC - HW-Error" : "FC - HW-Error");
}
check_HWError
= false;
}
/// <summary>
/// BL-Ctrl data 'K'
/// for FC you have to use a customized firmware
/// </summary>
/// <param name="data">the received byte array to process</param>
void _processBLCtrl
(byte[] data
)
{
if (data
.Length % 6 == 0) //data.Length up to 96 (16 motors x 6 byte data) --> new datastruct in FC -> not standard!
{
bool bAvailable
= false;
for (int i
= 0; i
< data
.Length && data
[i
] < 8; i
+= 6) // data[i] < 8 --> at moment there are 8 display fields for motors
{
if ((data
[i
+ 4] & 128) == 128) //Status bit at pos 7 = 128 dec -- if true, motor is available
bAvailable
= true;
else
bAvailable
= false;
if (data
[i
] < 4)
{
if (bAvailable
)
{
dtMotors1
.Rows[data
[i
]].SetField(1,
((double)data
[i
+ 1] / (double)10).ToString("0.0 A"));
dtMotors1
.Rows[data
[i
]].SetField(2, data
[i
+ 2].ToString("0 °C"));
}
else
{
dtMotors1
.Rows[data
[i
]].SetField(1,
"NA");
dtMotors1
.Rows[data
[i
]].SetField(2,
"NA");
}
}
if (data
[i
] > 3 && data
[i
] < 8)
{
if (bAvailable
)
{
dtMotors2
.Rows[data
[i
] - 4].SetField(1,
((double)data
[i
+ 1] / (double)10).ToString("0.0 A"));
dtMotors2
.Rows[data
[i
] - 4].SetField(2, data
[i
+ 2].ToString("0 °C"));
}
else
{
dtMotors2
.Rows[data
[i
] - 4].SetField(1,
"NA");
dtMotors2
.Rows[data
[i
] - 4].SetField(2,
"NA");
}
}
}
}
}
/// <summary>
/// Navi-Ctrl data 'O'
/// GPS-Position, capacatiy, flying time...
/// </summary>
/// <param name="data">the received byte array to process</param>
void _processNCData
(byte[] data
)
{
int i_32, i_16, iVal
;
double d
;
i_32
= data
[4];
iVal
= i_32
<< 24;
i_32
= data
[3];
iVal
+= i_32
<< 16;
i_32
= data
[2];
iVal
+= i_32
<< 8;
iVal
+= data
[1];
d
= (double)iVal
/ Math
.Pow(10,
7);
lblNCGPSLong
.Invoke((Action
)(() => lblNCGPSLong
.Text = d
.ToString("0.######°"))); //GPS-Position: Longitude in decimal degree
//lblNCGPSLong.Invoke((Action)(() => lblNCGPSLong.Text = _convertDegree(d))); //GPS-Position: Longitude in minutes, seconds
i_32
= data
[8];
iVal
= i_32
<< 24;
i_32
= data
[7];
iVal
+= i_32
<< 16;
i_32
= data
[6];
iVal
+= i_32
<< 8;
iVal
+= data
[5];
d
= (double)iVal
/ Math
.Pow(10,
7);
lblNCGPSLat
.Invoke((Action
)(() => lblNCGPSLat
.Text = d
.ToString("0.######°"))); //GPS-Position: Latitude in decimal degree
//lblNCGPSLat.Invoke((Action)(() => lblNCGPSLat.Text = _convertDegree(d))); //GPS-Position: Latitude in minutes, seconds
i_16
= data
[28];
i_16
= (Int16
)(i_16
<< 8);
iVal
= data
[27] + i_16
;
lblNCDistWP
.Invoke((Action
)(() => lblNCDistWP
.Text = ((double)iVal
/ (double)10).ToString("0.0 m"))); //Distance to next WP
i_16
= data
[45];
i_16
= (Int16
)(i_16
<< 8);
iVal
= data
[44] + i_16
;
lblNCDistHP1
.Invoke((Action
)(() => lblNCDistHP1
.Text = ((double)iVal
/ (double)10).ToString("0.0 m"))); //Distance to next WP
lblNCWPIndex
.Invoke((Action
)(() => lblNCWPIndex
.Text = data
[48].ToString())); //Waypoint index
lblNCWPCount
.Invoke((Action
)(() => lblNCWPCount
.Text = data
[49].ToString())); //Waypoints count
i_16
= data
[81];
i_16
= (Int16
)(i_16
<< 8);
iVal
= data
[80] + i_16
;
lblNCCap
.Invoke((Action
)(() => lblNCCap
.Text = iVal
.ToString() + " mAh")); //Capacity used
i_16
= data
[56];
i_16
= (Int16
)(i_16
<< 8);
iVal
= data
[55] + i_16
;
TimeSpan t
= TimeSpan
.FromSeconds(iVal
);
string Text
= t
.Hours.ToString("D2") + ":" + t
.Minutes.ToString("D2") + ":" + t
.Seconds.ToString("D2");
lblNCFlTime
.Invoke((Action
)(() => lblNCFlTime
.Text = Text
.ToString())); //Flying time
lblNCRC
.Invoke((Action
)(() => lblNCRC
.Text = data
[66].ToString())); //RC quality
lblNCErrNmbr
.Invoke((Action
)(() => lblNCErrNmbr
.Text = data
[69].ToString())); //NC Errornumber
//if (data[69] > 0)
// _readNCError();
//break;
if (data
[69] > 0 & data
[69] < 44)
ErrorLog
(LogMsgType
.Error,
"NC Error [" + data
[69].ToString() + "]: " + NC_Error
[data
[69]]);
else
if(_bErrorLog
) _clearErrorLog
("NC Error");
}
/// <summary>
/// Navi-Ctrl WP data struct 'X'
/// called by index
/// </summary>
/// <param name="data">the received byte array to process</param>
void _processWPData
(byte[] data
)
{
if (data
.Length >= 28)
{
int count
= data
[0];
int index
= data
[1];
cbWPIndex
.Invoke((Action
)(() => cbWPIndex
.Items.Clear()));
for (int i
= 0; i
< count
; i
++)
cbWPIndex
.Invoke((Action
)(() => cbWPIndex
.Items.Add(i
+ 1)));
cbWPIndex
.Invoke((Action
)(() => cbWPIndex
.SelectedItem = index
));
DataRow dr
= dtWaypoints
.NewRow();
dr
= Waypoints
.toDataRow(data, dr
);
dtWaypoints
.Rows.Add(dr
);
dgvWP
.Invoke((Action
)(() => dgvWP
.Update()));
}
else
Debug
.Print(new string(ASCIIEncoding
.ASCII.GetChars(data,
0, data
.Length)));
}
/// <summary>
/// OSD Menue 'L'
/// single page called by pagenumber
/// no autoupdate
/// </summary>
/// <param name="data">the received byte array to process</param>
void _processOSDSingle
(byte[] data
)
{
if (data
.Length == 84)
{
string sMessage
= "";
iOSDPage
= data
[0];
iOSDMax
= data
[1];
if (cbOSD
.Items.Count != iOSDMax
) _initOSDCB
();
sMessage
= new string(ASCIIEncoding
.ASCII.GetChars(data,
2, data
.Length - 4));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(0,
20));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(20,
20));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(40,
20));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(60,
20));
lblOSDPageNr
.Invoke((Action
)(() => lblOSDPageNr
.Text = iOSDPage
.ToString("[0]")));
}
else
OSD
(LogMsgType
.Incoming,
"Wrong length: " + data
.Length + " (should be 84)");
}
/// <summary>
/// OSD Menue 'H'
/// called by keys (0x01,0x02,0x03,0x04)
/// autoupdate
/// </summary>
/// <param name="data">the received byte array to process</param>
void _processOSDAuto
(byte[] data
)
{
if (data
.Length == 81)
{
string sMessage
= "";
sMessage
= new string(ASCIIEncoding
.ASCII.GetChars(data,
0, data
.Length - 1));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(0,
20));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(20,
20));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(40,
20));
OSD
(LogMsgType
.Incoming, sMessage
.Substring(60,
20));
}
else
OSD
(LogMsgType
.Incoming,
"Wrong length: " + data
.Length + " (should be 81)");
}
#endregion processing received data
/// <summary> send message to controller to request data
/// for detailed info see http://wiki.mikrokopter.de/en/SerialProtocol/
/// </summary>
/// <param name="CMDID"> the command ID </param>
/// <param name="address"> the address of the controller: 0-any, 1-FC, 2-NC </param>
private void _sendControllerMessage
(char CMDID,
byte address
)
{
if (simpleSerialPort
.Port.IsOpen)
{
Stream serialStream
= simpleSerialPort
.Port.BaseStream;
byte[] bytes
= FlightControllerMessage
.CreateMessage(CMDID, address
);
serialStream
.Write(bytes,
0, bytes
.Length);
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
/// <summary> send message to controller to request data
/// for detailed info see http://wiki.mikrokopter.de/en/SerialProtocol/
/// </summary>
/// <param name="CMDID"> the command ID </param>
/// <param name="address"> the address of the controller: 0-any, 1-FC, 2-NC </param>
/// <param name="data"> additional data for the request</param>
private void _sendControllerMessage
(char CMDID,
byte address,
byte[]data
)
{
if (simpleSerialPort
.Port.IsOpen)
{
Stream serialStream
= simpleSerialPort
.Port.BaseStream;
byte[] bytes
= FlightControllerMessage
.CreateMessage(CMDID, address,data
);
serialStream
.Write(bytes,
0, bytes
.Length);
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
/// <summary>
/// read the analog-label names for the actual controller
/// and load it into listbox
/// </summary>
void _loadLabelNames
()
{
if (_iCtrlAct
> 0 && _iCtrlAct
< 3)
{
switch (_iCtrlAct
)
{
case 1:
sAnalogLabel
= Properties
.Resources.FCLabelTexts.Split(new[] { Environment
.NewLine }, StringSplitOptions
.None);
break;
case 2:
sAnalogLabel
= Properties
.Resources.NCLabelTexts.Split(new[] { Environment
.NewLine }, StringSplitOptions
.None);
break;
}
for (int i
= 0; i
< 32; i
++)
{
if (dtAnalog
.Rows.Count < 32)
dtAnalog
.Rows.Add(sAnalogLabel
[i
],
"");
else
dtAnalog
.Rows[i
].SetField(0, sAnalogLabel
[i
]);
}
dataGridView1
.Invoke((Action
)(()=>dataGridView1
.Refresh()));
}
}
/// <summary>
/// no longer used...
/// read the analog-label textfile for the actual controller
/// </summary>
private void _loadLabelFile
()
{
switch (_iCtrlAct
)
{
case 1:
fileName
= "FCLabelTexts.txt";
break;
case 2:
fileName
= "NCLabelTexts.txt";
break;
//default:
// fileName = "NCLabelTexts.txt";
// break;
}
if (File
.Exists(filePath
+ "\\" + fileName
))
{
sAnalogLabel
.Initialize();
sAnalogLabel
= File
.ReadAllLines(filePath
+ "\\" + fileName
);
lbLabels
.Invoke((Action
)(() => lbLabels
.Items.Clear()));
lbLabels
.Invoke((Action
)(() => lbLabels
.Update()));
lbLabels
.Invoke((Action
)(() => lbLabels
.Items.AddRange(sAnalogLabel
)));
Console
.WriteLine("Names loaded from file");
lblFileName
.Invoke((Action
)(() => lblFileName
.Text = fileName
));
}
else
{
_readCont
(false);
Log
(LogMsgType
.Error,
"Label-file not found!");
Log
(LogMsgType
.Error,
"Please go to settings-tab and load the label texts from the copter control (FC & NC)");
Log
(LogMsgType
.Error,
"When done, you have to save the label texts with the 'save' button!");
}
}
/// <summary>
/// no longer used...
/// assign the analog-label names from the textfile to the datatable
///
/// </summary>
private void _assignLabelNames
()
{
if (lbLabels
.Items.Count == 32)
{
lbLabels
.Items.CopyTo(sAnalogLabel,
0);
for (int i
= 0; i
< 32; i
++)
{
if (dtAnalog
.Rows.Count < 32)
dtAnalog
.Rows.Add(sAnalogLabel
[i
],
"");
else
dtAnalog
.Rows[i
].SetField(0, sAnalogLabel
[i
]);
}
}
}
/// <summary>
/// get the version struct of actual controller
/// </summary>
/// <summary>
/// get the labeltexts for the analog values
/// </summary>
private void _getAnalogLabels
()
{
if (simpleSerialPort
.Port.IsOpen)
{
iLableIndex
= 0;
for (int i
= 0; i
< 32; i
++)
{
Stream serialStream
= simpleSerialPort
.Port.BaseStream;
byte[] bytes
= FlightControllerMessage
.CreateMessage('a',
0,
new byte[1] { (byte)i
});
serialStream
.Write(bytes,
0, bytes
.Length);
Thread
.Sleep(10);
}
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
/// <summary>
/// get the labeltext for a single label
/// </summary>
/// <param name="iIndex">index of the label</param>
private void _getAnalogLabels
(int iIndex
)
{
if (simpleSerialPort
.Port.IsOpen)
{
if (iIndex
< 32)
{
iLableIndex
= iIndex
;
_sendControllerMessage
('a',
0,
new byte[1] { (byte)iLableIndex
});
}
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
private void _getVersion
()
{
_sendControllerMessage
('v',
0);
}
/// <summary>
/// get FC version struct via NC
/// by sending '1' as data (not documented in wiki...)
/// returns HW error 255 (comment in uart1.c : tells the KopterTool that it is the FC-version)
/// </summary>
/// <param name="ctrl">controller number 1=FC</param>
private void _getVersion
(byte ctrl
)
{
_sendControllerMessage
('v',
0,
new byte[1] {ctrl
});
}
/// <summary>
/// Switch back to NC by sending the 'Magic Packet' 0x1B,0x1B,0x55,0xAA,0x00
/// </summary>
private void _switchToNC
()
{
if (simpleSerialPort
.Port.IsOpen)
{
Stream serialStream
= simpleSerialPort
.Port.BaseStream;
byte[] bytes
= new byte[5] { 0x1B,0x1B,0x55,0xAA,0x00
};
serialStream
.Write(bytes,
0, bytes
.Length);
Thread
.Sleep(100);
_getVersion
();
Thread
.Sleep(100);
_OSDMenue
(0);
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
/// <summary>
/// switch to FC
/// </summary>
private void _switchToFC
()
{
_sendControllerMessage
('u',
2,
new byte[1] { (byte)0 });
Thread
.Sleep(100);
_getVersion
();
Thread
.Sleep(100);
_OSDMenue
(0);
}
/// <summary>
/// send RESET signal to FC
/// </summary>
private void _resetCtrl
()
{
_sendControllerMessage
('R',
1);
}
/// <summary>
/// poll the debug data (4sec subscription)
/// </summary>
/// <param name="auto"> onetimequery(false) or autoupdate(true) with set timing interval </param>
private void _readDebugData
(bool auto
)
{
byte interval
= auto
? debugInterval
: (byte)0;
_sendControllerMessage
('d',
0,
new byte[1] { debugInterval
});
}
/// <summary>
/// poll the BL-CTRL status via NC (4sec subscription)
/// </summary>
/// <param name="auto"> onetimequery(false) or autoupdate(true) with set timing interval </param>
private void _readBLCtrl
(bool auto
)
{
byte interval
= auto
? blctrlInterval
: (byte)0;
_sendControllerMessage
('k',
0,
new byte[1] { interval
});
}
/// <summary>
/// poll the NC data struct (4sec subscription)
/// </summary>
/// <param name="auto"> onetimequery(false) or autoupdate(true) with set timing interval </param>
private void _readNavData
(bool auto
)
{
byte interval
= auto
? navctrlInterval
: (byte)0;
_sendControllerMessage
('o',
2,
new byte[1] { interval
});
}
/// <summary>
/// get the errortext for pending NC error
/// </summary>
private void _readNCError
()
{
_sendControllerMessage
('e',
2);
}
/// <summary>
/// start/stop continous polling of controller values
/// </summary>
/// <param name="b">start/stop switch</param>
void _readCont
(bool b
)
{
bReadContinously
= b
;
if (Thread
.CurrentThread.CurrentUICulture.Name == "")
btnReadDebugCont
.Invoke((Action
)(() => btnReadDebugCont
.Text = bReadContinously
? "stop automatic" + Environment
.NewLine + "data refresh" : "start automatic" + Environment
.NewLine + "data refresh"));
else
btnReadDebugCont
.Invoke((Action
)(() => btnReadDebugCont
.Text = bReadContinously
? "Aktualisierung" + Environment
.NewLine + "beenden" : "Aktualisierung" + Environment
.NewLine + "starten"));
btnReadDebugCont
.Invoke((Action
)(() => btnReadDebugCont
.BackColor = bReadContinously
? Color
.FromArgb(192,
255,
192) : Color
.FromArgb(224,
224,
224)));
if (bReadContinously
)
{
if (_debugDataAutorefresh
) { _readDebugData
(true); Thread
.Sleep(10); }
if (_blctrlDataAutorefresh
) { _readBLCtrl
(true); Thread
.Sleep(10); }
if (_navCtrlDataAutorefresh
&& _iCtrlAct
== 2) { _readNavData
(true); Thread
.Sleep(10); }
if (_OSDAutorefresh
) { _OSDMenueAutoRefresh
(); Thread
.Sleep(10);}
lblLifeCounter
.Invoke((Action
)(() => lblLifeCounter
.BackColor = Color
.FromArgb(0,
224,
0)));
}
else
lblLifeCounter
.Invoke((Action
)(() => lblLifeCounter
.BackColor = Color
.FromArgb(224,
224,
224)));
_iLifeCounter
= 0;
}
/// <summary>
/// set values to "NA" when not available with FC
/// </summary>
void _setFieldsNA
()
{
Thread
.Sleep(100);
_initDTMotors
();
lblNCFlTime
.Invoke((Action
)(() => lblNCFlTime
.Text = "NA")); //FlightTime
lblNCErrNmbr
.Invoke((Action
)(() => lblNCErrNmbr
.Text = "NA")); //NC ErrorNr
lblNCMF
.Invoke((Action
)(() => lblNCMF
.Text = "NA")); //earth magnet field
lblNCGSpeed
.Invoke((Action
)(() => lblNCGSpeed
.Text = "NA")); //GroundSpeed
lblNCDistHP
.Invoke((Action
)(() => lblNCDistHP
.Text = "NA")); //Distance to HP
lblNCSat
.Invoke((Action
)(() => lblNCSat
.Text = "NA")); //Sats used
lblNCGPSLong
.Invoke((Action
)(() => lblNCGPSLong
.Text = "NA")); //GPS position - longitude
lblNCGPSLat
.Invoke((Action
)(() => lblNCGPSLat
.Text = "NA")); //GPS position - latitude
lblNCDistWP
.Invoke((Action
)(() => lblNCDistWP
.Text = "NA")); //next WP distance
lblNCWPIndex
.Invoke((Action
)(() => lblNCWPIndex
.Text = "NA")); //index of actual WP
lblNCWPCount
.Invoke((Action
)(() => lblNCWPCount
.Text = "NA")); //count of items in WP list
}
/// <summary>
/// one time query of the OSD Menue with pagenumber
/// </summary>
/// <param name="iMenue">Menue page</param>
void _OSDMenue
(int iMenue
)
{
if (simpleSerialPort
.Port.IsOpen)
{
if (iMenue
> iOSDMax
)
iMenue
= 0;
Stream serialStream
= simpleSerialPort
.Port.BaseStream;
byte[] bytes
= FlightControllerMessage
.CreateMessage('l',
0,
new byte[1] { (byte)iMenue
});
serialStream
.Write(bytes,
0, bytes
.Length);
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
/// <summary>
/// call the OSDMenue and start autorefresh
/// usually by sending a menuekey
/// 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)
/// therefore the value has to be negative (inverted) in order to distinguish from old (2 line) menuestyle
/// and must not have any bits of the menue keys 0x1 0x2 0x4 0x8 (0x10?) --> 0x20 = -33
/// </summary>
void _OSDMenueAutoRefresh
()
{
_sendControllerMessage
('h',
0,
new byte[2] { unchecked((byte)(-33)),OSDInterval
});
}
void _OSDMenueAutoRefresh
(byte key
)
{
_sendControllerMessage
('h',
0,
new byte[2] { unchecked((byte)~key
), OSDInterval
});
}
/// <summary>
/// initialize the OSD menue combobox
/// combox is filled by numbers from 0 to max pagenumber
/// </summary>
void _initOSDCB
()
{
_bCBInit
= true;
if(iOSDMax
== 0)
{
_OSDMenue
(0);
Thread
.Sleep(10);
}
cbOSD
.Invoke((Action
)(()=>cbOSD
.Items.Clear()));
for(int i
= 0; i
<= iOSDMax
;i
++)
{
cbOSD
.Invoke((Action
)(() => cbOSD
.Items.Add(i
)));
}
cbOSD
.Invoke((Action
)(() => cbOSD
.SelectedItem = iOSDPage
));
_bCBInit
= false;
}
/// <summary>
/// initialize the datatables
/// with columnnames etc
/// </summary>
void _dataTablesInit
()
{
dtAnalog
.Columns.Add("ID");
dtAnalog
.Columns.Add("Value");
dataGridView1
.DataSource = dtAnalog
;
dtMotors1
.Columns.Add("#");
if (Thread
.CurrentThread.CurrentUICulture.Name == "")
dtMotors1
.Columns.Add("Current");
else
dtMotors1
.Columns.Add("Strom");
dtMotors1
.Columns.Add("Temp");
dtMotors2
.Columns.Add("#");
if (Thread
.CurrentThread.CurrentUICulture.Name == "")
dtMotors2
.Columns.Add("Current");
else
dtMotors2
.Columns.Add("Strom");
dtMotors2
.Columns.Add("Temp");
dgvMotors1
.DataSource = dtMotors1
;
dgvMotors2
.DataSource = dtMotors2
;
_initDTMotors
();
dgvMotors1
.Columns[0].Width = 24;
dgvMotors1
.Columns[1].Width = 74;
dgvMotors1
.Columns[2].Width = 74;
dgvMotors2
.Columns[0].Width = 24;
dgvMotors2
.Columns[1].Width = 74;
dgvMotors2
.Columns[2].Width = 74;
dtWaypoints
.Columns.Add("Index");
dtWaypoints
.Columns.Add("Type");
dtWaypoints
.Columns.Add("Name");
dtWaypoints
.Columns.Add("Latitude");
dtWaypoints
.Columns.Add("Longitude");
dtWaypoints
.Columns.Add("Altitude");
dtWaypoints
.Columns.Add("Heading");
dtWaypoints
.Columns.Add("Speed");
dtWaypoints
.Columns.Add("Altitude rate");
dtWaypoints
.Columns.Add("Tol.radius");
dtWaypoints
.Columns.Add("Hold time");
dtWaypoints
.Columns.Add("AutoTrigger");
dtWaypoints
.Columns.Add("Cam angle");
dtWaypoints
.Columns.Add("Event");
dtWaypoints
.Columns.Add("Eventchan. Val.");
dtWaypoints
.Columns.Add("Status");
dgvWP
.DataSource = dtWaypoints
;
}
/// <summary>
/// read settings from ini-file
/// </summary>
void _readIni
()
{
if (!File
.Exists(filePath
+ "\\MKLiveViewSettings.ini"))
_writeIni
();
IniFile ini
= new IniFile
("MKLiveViewSettings.ini");
ini
.path = filePath
+ "\\MKLiveViewSettings.ini";
string sVal
= ini
.IniReadValue("default",
"AutorefreshDebugData");
_debugDataAutorefresh
= Convert
.ToBoolean(sVal
);
sVal
= ini
.IniReadValue("default",
"AutorefreshNavCtrlData");
_navCtrlDataAutorefresh
= Convert
.ToBoolean(sVal
);
sVal
= ini
.IniReadValue("default",
"AutorefreshBLCtrlData");
_blctrlDataAutorefresh
= Convert
.ToBoolean(sVal
);
sVal
= ini
.IniReadValue("default",
"AutorefreshOSDData");
_OSDAutorefresh
= Convert
.ToBoolean(sVal
);
sVal
= ini
.IniReadValue("default",
"IntervalDebugData");
debugInterval
= (byte)Convert
.ToInt16(sVal
);
sVal
= ini
.IniReadValue("default",
"IntervalNavCtrlData");
navctrlInterval
= (byte)Convert
.ToInt16(sVal
);
sVal
= ini
.IniReadValue("default",
"IntervalBLCtrlData");
blctrlInterval
= (byte)Convert
.ToInt16(sVal
);
sVal
= ini
.IniReadValue("default",
"IntervalOSDData");
OSDInterval
= (byte)Convert
.ToInt16(sVal
);
for(int i
= 0; i
< 12; i
++)
{
sVal
= ini
.IniReadValue("serial",
"ch" + i
.ToString() + "Val");
if(sVal
!= "")
serChan
[i
] = Convert
.ToInt16(sVal
);
sVal
= ini
.IniReadValue("serial",
"ch" + i
.ToString() + "Title");
if(sVal
!= "")
serChanTitle
[i
] = sVal
;
for (int y
= 0; i
< 4 && y
< 3; y
++)
{
sVal
= ini
.IniReadValue("serial",
"ch" + i
.ToString() + "ValSub" + y
.ToString());
if (sVal
!= "")
serChan_sub
[(i
*3) + y
] = Convert
.ToInt16(sVal
);
}
}
}
/// <summary>
/// save settings to ini-file
/// </summary>
void _writeIni
()
{
IniFile ini
= new IniFile
("MKLiveViewSettings.ini");
ini
.path = filePath
+ "\\MKLiveViewSettings.ini";
ini
.IniWriteValue("default",
"AutorefreshDebugData", _debugDataAutorefresh
? "true":"false");
ini
.IniWriteValue("default",
"AutorefreshNavCtrlData", _navCtrlDataAutorefresh
? "true":"false");
ini
.IniWriteValue("default",
"AutorefreshBLCtrlData", _blctrlDataAutorefresh
? "true":"false");
ini
.IniWriteValue("default",
"AutorefreshOSDData", _OSDAutorefresh
? "true":"false");
ini
.IniWriteValue("default",
"IntervalDebugData", debugInterval
.ToString());
ini
.IniWriteValue("default",
"IntervalNavCtrlData", navctrlInterval
.ToString());
ini
.IniWriteValue("default",
"IntervalBLCtrlData", blctrlInterval
.ToString());
ini
.IniWriteValue("default",
"IntervalOSDData", OSDInterval
.ToString());
for (int i
= 0; i
< 12; i
++)
{
ini
.IniWriteValue("serial",
"ch" + i
.ToString() + "Val", serChan
[i
].ToString());
ini
.IniWriteValue("serial",
"ch" + i
.ToString() + "Title", serChanTitle
[i
]);
for (int y
= 0; i
< 4 && y
< 3; y
++)
{
ini
.IniWriteValue("serial",
"ch" + i
.ToString() + "ValSub" + y
.ToString(), serChan_sub
[(i
* 3) + y
].ToString());
}
}
}
/// <summary>
/// initialize the 2 datatables for motor values
/// dtMotors1 - motor 1 - 4
/// dtMotors2 - motor 5 - 8
/// DataGridView dgvMotors1/2 are bound to dtMotors1/2
/// </summary>
void _initDTMotors
()
{
for(int i
= 0; i
< 4; i
++)
{
if (dtMotors1
.Rows.Count < 4)
dtMotors1
.Rows.Add((i
+ 1).ToString(),
"NA",
"NA");
else
{
dtMotors1
.Rows[i
].SetField(1,
"NA");
dtMotors1
.Rows[i
].SetField(2,
"NA");
}
if (dtMotors2
.Rows.Count < 4)
dtMotors2
.Rows.Add((i
+ 5).ToString(),
"NA",
"NA");
else
{
dtMotors2
.Rows[i
].SetField(1,
"NA");
dtMotors2
.Rows[i
].SetField(2,
"NA");
}
}
dgvMotors1
.Invoke((Action
)(() => dgvMotors1
.Refresh()));
dgvMotors2
.Invoke((Action
)(() => dgvMotors2
.Refresh()));
}
/// <summary>
/// Convert decimal degrees to degrees, minutes, seconds, milliseconds
/// </summary>
/// <param name="coord">the degree value as double</param>
/// <returns>0° 0' 0,0"</returns>
string _convertDegree
(double coord
)
{
//double minutes = (degree - Math.Floor(degree)) * 60.0;
//double seconds = (minutes - Math.Floor(minutes)) * 60.0;
//double tenths = (seconds - Math.Floor(seconds)) * 10.0;
//// get rid of fractional part
//minutes = Math.Floor(minutes);
//seconds = Math.Floor(seconds);
//tenths = Math.Floor(tenths);
//int sec = (int)Math.Round(coord * 3600);
//int deg = sec / 3600;
//sec = Math.Abs(sec % 3600);
//int min = sec / 60;
//sec %= 60;
var ts
= TimeSpan
.FromHours(Math
.Abs(coord
));
double deg
= Math
.Sign(coord
) * Math
.Floor(ts
.TotalHours);
int min
= ts
.Minutes;
int sec
= ts
.Seconds;
int milli
= ts
.Milliseconds;
return deg
.ToString("0° ") + min
.ToString("0") + "' " + sec
.ToString("0") + "," + milli
.ToString() + "\"";
}
/// <summary>
/// Clear the line in the errorlog window
/// containing the error string when error has ceased
/// </summary>
/// <param name="s">substring of errrormessage</param>
void _clearErrorLog
(string s
)
{
rtfError
.Invoke((Action
)(() =>
{
if (rtfError
.Text.Contains(s
))
{
int iLength
= 0;
int iStart
= rtfError
.Text.IndexOf(s
);
int iEnd
= rtfError
.Text.IndexOf('\n', iStart
);
if (iEnd
> 0)
{
iLength
= iEnd
+ 1;
int iHttp
= rtfError
.Text.IndexOf("http", iEnd
);
if (iHttp
== iLength
)
{
int iEnd2
= rtfError
.Text.IndexOf('\n', iLength
);
if (iEnd2
> iLength
)
{
iLength
= iEnd2
+ 1;
rtfError
.Select(iStart, iLength
);
rtfError
.SelectedText = string.Empty;
if(rtfError
.Text.Length < 2) _bErrorLog
= false;
}
}
else
{
rtfError
.Select(iStart, iLength
);
rtfError
.SelectedText = string.Empty;
if(rtfError
.Text.Length < 2) _bErrorLog
= false;
}
}
}
}));
}
/// <summary>
/// request the Waypoint at index
/// </summary>
/// <param name="index"></param>
void _getpWP
(int index
)
{
if (simpleSerialPort
.Port.IsOpen)
{
Stream serialStream
= simpleSerialPort
.Port.BaseStream;
byte[] bytes
= FlightControllerMessage
.CreateMessage('x',
2,
new byte[1] { (byte)index
});
serialStream
.Write(bytes,
0, bytes
.Length);
}
else
Log
(LogMsgType
.Error,
"NOT CONNECTED!");
}
/// <summary>
/// Sending the serial channel values
/// </summary>
void _sendSerialData
()
{
byte[] serData
= new byte[12];
for(int i
= 0; i
< 12; i
++)
{
serData
[i
] = unchecked((byte)(serChan
[i
] - 127));
}
_sendControllerMessage
('y',
1, serData
);
}
/// <summary>
/// init the controls for displaying
/// and setting serial control channels
/// </summary>
void _initSerialCtrl
()
{
trckbarSerial1
.Value = serChan
[0];
textBoxSerial1
.Text = serChanTitle
[0];
lblTbSerial1
.Text = serChan
[0].ToString();
trckbarSerial2
.Value = serChan
[1];
textBoxSerial2
.Text = serChanTitle
[1];
lblTbSerial2
.Text = serChan
[1].ToString();
trckbarSerial3
.Value = serChan
[2];
textBoxSerial3
.Text = serChanTitle
[2];
lblTbSerial3
.Text = serChan
[2].ToString();
trckbarSerial4
.Value = serChan
[3];
textBoxSerial4
.Text = serChanTitle
[3];
lblTbSerial4
.Text = serChan
[3].ToString();
trckbarSerial5
.Value = serChan
[4];
textBoxSerial5
.Text = serChanTitle
[4];
lblTbSerial5
.Text = serChan
[4].ToString();
trckbarSerial6
.Value = serChan
[5];
textBoxSerial6
.Text = serChanTitle
[5];
lblTbSerial6
.Text = serChan
[5].ToString();
trckbarSerial7
.Value = serChan
[6];
textBoxSerial7
.Text = serChanTitle
[6];
lblTbSerial7
.Text = serChan
[6].ToString();
trckbarSerial8
.Value = serChan
[7];
textBoxSerial8
.Text = serChanTitle
[7];
lblTbSerial8
.Text = serChan
[7].ToString();
textBoxSerial1_val1
.Text = serChan_sub
[0].ToString();
textBoxSerial1_val2
.Text = serChan_sub
[1].ToString();
textBoxSerial1_val3
.Text = serChan_sub
[2].ToString();
textBoxSerial2_val1
.Text = serChan_sub
[3].ToString();
textBoxSerial2_val2
.Text = serChan_sub
[4].ToString();
textBoxSerial2_val3
.Text = serChan_sub
[5].ToString();
textBoxSerial3_val1
.Text = serChan_sub
[6].ToString();
textBoxSerial3_val2
.Text = serChan_sub
[7].ToString();
textBoxSerial3_val3
.Text = serChan_sub
[8].ToString();
textBoxSerial4_val1
.Text = serChan_sub
[9].ToString();
textBoxSerial4_val2
.Text = serChan_sub
[10].ToString();
textBoxSerial4_val3
.Text = serChan_sub
[11].ToString();
}
#endregion functions
#region buttons
private void buttonReset_Click
(object sender, EventArgs e
)
{
_resetCtrl
();
}
private void btnVersion_Click
(object sender, EventArgs e
)
{
_getVersion
();
}
private void btnAnalogLabels_Click
(object sender, EventArgs e
)
{
_getAnalogLabels
(0);
}
private void btnDbgData_Click
(object sender, EventArgs e
)
{
_readDebugData
(false); //onetime reading of debug data --> subscription lasts 4sec - this means you will receive data for 4 seconds
}
private void btnSaveLabels_Click
(object sender, EventArgs e
)
{
switch (_iCtrlAct
)
{
case 1:
fileName
= "FCLabelTexts.txt";
break;
case 2:
fileName
= "NCLabelTexts.txt";
break;
default:
fileName
= "NCLabelTexts.txt";
break;
}
if (sAnalogLabel
[0] != null)
{
File
.WriteAllLines(filePath
+ "\\" + fileName, sAnalogLabel
);
Console
.WriteLine("Names saved to file");
_loadLabelFile
();
}
else
Log
(LogMsgType
.Warning,
"there's no data -> read first from fc/nc!");
}
private void btnLoadLabels_Click
(object sender, EventArgs e
)
{
_assignLabelNames
();
}
private void btnReadLabelFile_Click
(object sender, EventArgs e
)
{
_loadLabelFile
();
}
private void btnSwitchFC_Click
(object sender, EventArgs e
)
{
_switchToFC
();
}
private void btnSwitchNC_Click
(object sender, EventArgs e
)
{
_switchToNC
();
}
private void btnReadDbgCont_Click
(object sender, EventArgs e
)
{
_readCont
(!bReadContinously
);
}
private void btnReadBLCtrl_Click
(object sender, EventArgs e
)
{
if (_iCtrlAct
== 2) _readBLCtrl
(false);
else Log
(LogMsgType
.Warning,
"only available when connected to NC");
}
private void btnGetNaviData_Click
(object sender, EventArgs e
)
{
if (_iCtrlAct
== 2) _readNavData
(false);
else Log
(LogMsgType
.Warning,
"only available when connected to NC");
}
private void btnConn_Click
(object sender, EventArgs e
)
{
simpleSerialPort
.Connect(!simpleSerialPort
.Port.IsOpen);
}
private void button3_Click
(object sender, EventArgs e
)
{
_getVersion
(1);
}
private void button4_Click
(object sender, EventArgs e
)
{
_getVersion
(2);
}
private void btnOSD_Click
(object sender, EventArgs e
)
{
if (iOSDPage
> iOSDMax
)
iOSDPage
= 0;
_OSDMenue
(iOSDPage
);
}
private void btnOSDForward_Click
(object sender, EventArgs e
)
{
iOSDPage
++;
if (iOSDPage
> iOSDMax
)
iOSDPage
= 0;
_OSDMenue
(iOSDPage
);
}
private void btnOSDBackward_Click
(object sender, EventArgs e
)
{
iOSDPage
--;
if (iOSDPage
< 0)
iOSDPage
= iOSDMax
;
_OSDMenue
(iOSDPage
);
}
private void btnOSDAuto_Click
(object sender, EventArgs e
)
{
_OSDMenueAutoRefresh
();
}
/// call the OSDMenue with Key 0x8
private void btnOSDLeave_Click
(object sender, EventArgs e
)
{
_OSDMenueAutoRefresh
(8);
}
/// call the OSDMenue with Key 0x4
private void btnOSDEnter_Click
(object sender, EventArgs e
)
{
_OSDMenueAutoRefresh
(4);
}
private void btnGetWP_Click
(object sender, EventArgs e
)
{
if(cbWPIndex
.Items.Count >0)
_getpWP
((int)cbWPIndex
.SelectedItem);
else
_getpWP
(1);
}
#endregion buttons
#region serial control channels - buttons & events
private void tbSerial1_Scroll
(object sender, EventArgs e
)
{
lblTbSerial1
.Text = trckbarSerial1
.Value.ToString();
serChan
[0] = trckbarSerial1
.Value;
if (!_init
) _sendSerialData
();
}
private void textBoxSerial1_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[0] = textBoxSerial1
.Text;
}
private void btnSer1_0_Click
(object sender, EventArgs e
)
{
trckbarSerial1
.Value = 0;
}
private void btnSer1_127_Click
(object sender, EventArgs e
)
{
trckbarSerial1
.Value = 127;
}
private void btnSer1_254_Click
(object sender, EventArgs e
)
{
trckbarSerial1
.Value = 254;
}
private void trckbarSerial1_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial1
.Text = trckbarSerial1
.Value.ToString();
serChan
[0] = trckbarSerial1
.Value;
if (!_init
) _sendSerialData
();
}
private void textBoxSerial2_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[1] = textBoxSerial2
.Text;
}
private void trckbarSerial2_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial2
.Text = trckbarSerial2
.Value.ToString();
serChan
[1] = trckbarSerial2
.Value;
if (!_init
) _sendSerialData
();
}
private void btnSer2_0_Click
(object sender, EventArgs e
)
{
trckbarSerial2
.Value = 0;
}
private void btnSer2_127_Click
(object sender, EventArgs e
)
{
trckbarSerial2
.Value = 127;
}
private void btnSer2_254_Click
(object sender, EventArgs e
)
{
trckbarSerial2
.Value = 254;
}
private void textBoxSerial3_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[2] = textBoxSerial3
.Text;
}
private void trckbarSerial3_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial3
.Text = trckbarSerial3
.Value.ToString();
serChan
[2] = trckbarSerial3
.Value;
if (!_init
) _sendSerialData
();
}
private void btnSer3_0_Click
(object sender, EventArgs e
)
{
trckbarSerial3
.Value = 0;
}
private void btnSer3_127_Click
(object sender, EventArgs e
)
{
trckbarSerial3
.Value = 127;
}
private void btnSer3_254_Click
(object sender, EventArgs e
)
{
trckbarSerial3
.Value = 254;
}
private void textBoxSerial4_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[3] = textBoxSerial4
.Text;
}
private void trckbarSerial4_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial4
.Text = trckbarSerial4
.Value.ToString();
serChan
[3] = trckbarSerial4
.Value;
if (!_init
) _sendSerialData
();
}
private void btnSer4_0_Click
(object sender, EventArgs e
)
{
trckbarSerial4
.Value = 0;
}
private void btnSer4_127_Click
(object sender, EventArgs e
)
{
trckbarSerial4
.Value = 127;
}
private void btnSer4_254_Click
(object sender, EventArgs e
)
{
trckbarSerial4
.Value = 254;
}
private void tbSerial5_Scroll
(object sender, EventArgs e
)
{
lblTbSerial5
.Text = trckbarSerial5
.Value.ToString();
serChan
[4] = trckbarSerial5
.Value;
if (!_init
) _sendSerialData
();
}
private void textBoxSerial5_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[4] = textBoxSerial5
.Text;
}
private void btnSer5_0_Click
(object sender, EventArgs e
)
{
trckbarSerial5
.Value = 0;
}
private void btnSer5_127_Click
(object sender, EventArgs e
)
{
trckbarSerial5
.Value = 127;
}
private void btnSer5_254_Click
(object sender, EventArgs e
)
{
trckbarSerial5
.Value = 254;
}
private void trckbarSerial5_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial5
.Text = trckbarSerial5
.Value.ToString();
serChan
[4] = trckbarSerial5
.Value;
if (!_init
) _sendSerialData
();
}
private void tbSerial6_Scroll
(object sender, EventArgs e
)
{
lblTbSerial6
.Text = trckbarSerial6
.Value.ToString();
serChan
[5] = trckbarSerial6
.Value;
if (!_init
) _sendSerialData
();
}
private void textBoxSerial6_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[5] = textBoxSerial6
.Text;
}
private void btnSer6_0_Click
(object sender, EventArgs e
)
{
trckbarSerial6
.Value = 0;
}
private void btnSer6_127_Click
(object sender, EventArgs e
)
{
trckbarSerial6
.Value = 127;
}
private void btnSer6_254_Click
(object sender, EventArgs e
)
{
trckbarSerial6
.Value = 254;
}
private void trckbarSerial6_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial6
.Text = trckbarSerial6
.Value.ToString();
serChan
[5] = trckbarSerial6
.Value;
if (!_init
) _sendSerialData
();
}
private void tbSerial7_Scroll
(object sender, EventArgs e
)
{
lblTbSerial7
.Text = trckbarSerial7
.Value.ToString();
serChan
[6] = trckbarSerial7
.Value;
if (!_init
) _sendSerialData
();
}
private void textBoxSerial7_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[6] = textBoxSerial7
.Text;
}
private void btnSer7_0_Click
(object sender, EventArgs e
)
{
trckbarSerial7
.Value = 0;
}
private void btnSer7_127_Click
(object sender, EventArgs e
)
{
trckbarSerial7
.Value = 127;
}
private void btnSer7_254_Click
(object sender, EventArgs e
)
{
trckbarSerial7
.Value = 254;
}
private void trckbarSerial7_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial7
.Text = trckbarSerial7
.Value.ToString();
serChan
[6] = trckbarSerial7
.Value;
if (!_init
) _sendSerialData
();
}
private void tbSerial8_Scroll
(object sender, EventArgs e
)
{
lblTbSerial8
.Text = trckbarSerial8
.Value.ToString();
serChan
[7] = trckbarSerial8
.Value;
if (!_init
) _sendSerialData
();
}
private void textBoxSerial8_TextChanged
(object sender, EventArgs e
)
{
serChanTitle
[7] = textBoxSerial8
.Text;
}
private void btnSer8_0_Click
(object sender, EventArgs e
)
{
trckbarSerial8
.Value = 0;
}
private void btnSer8_127_Click
(object sender, EventArgs e
)
{
trckbarSerial8
.Value = 127;
}
private void btnSer8_254_Click
(object sender, EventArgs e
)
{
trckbarSerial8
.Value = 254;
}
private void trckbarSerial8_ValueChanged
(object sender, EventArgs e
)
{
lblTbSerial8
.Text = trckbarSerial8
.Value.ToString();
serChan
[7] = trckbarSerial8
.Value;
if (!_init
) _sendSerialData
();
}
/// <summary>
/// checks the input of a textbox
/// for valid data
/// in this case values 0-254
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textBox_serial_KeyPress
(object sender, KeyPressEventArgs e
)
{
if ("1234567890,\b".IndexOf(e
.KeyChar.ToString()) < 0) //general check for valid chars(0-9) and backspace (\b)
e
.Handled = true;
else
if ("\b".IndexOf(e
.KeyChar.ToString()) < 0)
if (Convert
.ToInt16(((TextBox
)sender
).Text + e
.KeyChar) > 254) //if valid and not backspace, check for upper limit of the resulting number
e
.Handled = true;
else
{
int i
= -1;
switch (((TextBox
)sender
).Name)
{
case "textBoxSerial1_val1":
i
= 0;
break;
case "textBoxSerial1_val2":
i
= 1;
break;
case "textBoxSerial1_val3":
i
= 2;
break;
case "textBoxSerial2_val1":
i
= 3;
break;
case "textBoxSerial2_val2":
i
= 4;
break;
case "textBoxSerial2_val3":
i
= 5;
break;
case "textBoxSerial3_val1":
i
= 6;
break;
case "textBoxSerial3_val2":
i
= 7;
break;
case "textBoxSerial3_val3":
i
= 8;
break;
case "textBoxSerial4_val1":
i
= 9;
break;
case "textBoxSerial4_val2":
i
= 10;
break;
case "textBoxSerial4_val3":
i
= 11;
break;
}
if (i
> -1)
serChan_sub
[i
] = Convert
.ToInt16(((TextBox
)sender
).Text + e
.KeyChar);
}
}
private void btnSer1_val1_Click
(object sender, EventArgs e
)
{
if(textBoxSerial1_val1
.Text.Length > 0)
{
trckbarSerial1
.Value = Convert
.ToInt16(textBoxSerial1_val1
.Text);
}
}
private void btnSer1_val2_Click
(object sender, EventArgs e
)
{
if(textBoxSerial1_val2
.Text.Length > 0)
{
trckbarSerial1
.Value = Convert
.ToInt16(textBoxSerial1_val2
.Text);
}
}
private void btnSer1_val3_Click
(object sender, EventArgs e
)
{
if(textBoxSerial1_val3
.Text.Length > 0)
{
trckbarSerial1
.Value = Convert
.ToInt16(textBoxSerial1_val3
.Text);
}
}
private void btnSer2_val1_Click
(object sender, EventArgs e
)
{
if(textBoxSerial2_val1
.Text.Length > 0)
{
trckbarSerial2
.Value = Convert
.ToInt16(textBoxSerial2_val1
.Text);
}
}
private void btnSer2_val2_Click
(object sender, EventArgs e
)
{
if(textBoxSerial2_val2
.Text.Length > 0)
{
trckbarSerial2
.Value = Convert
.ToInt16(textBoxSerial2_val2
.Text);
}
}
private void btnSer2_val3_Click
(object sender, EventArgs e
)
{
if(textBoxSerial2_val3
.Text.Length > 0)
{
trckbarSerial2
.Value = Convert
.ToInt16(textBoxSerial2_val3
.Text);
}
}
private void btnSer3_val1_Click
(object sender, EventArgs e
)
{
if(textBoxSerial3_val1
.Text.Length > 0)
{
trckbarSerial3
.Value = Convert
.ToInt16(textBoxSerial3_val1
.Text);
}
}
private void btnSer3_val2_Click
(object sender, EventArgs e
)
{
if(textBoxSerial3_val2
.Text.Length > 0)
{
trckbarSerial3
.Value = Convert
.ToInt16(textBoxSerial3_val2
.Text);
}
}
private void btnSer3_val3_Click
(object sender, EventArgs e
)
{
if(textBoxSerial3_val3
.Text.Length > 0)
{
trckbarSerial3
.Value = Convert
.ToInt16(textBoxSerial3_val3
.Text);
}
}
private void btnSer4_val1_Click
(object sender, EventArgs e
)
{
if(textBoxSerial4_val1
.Text.Length > 0)
{
trckbarSerial4
.Value = Convert
.ToInt16(textBoxSerial4_val1
.Text);
}
}
private void btnSer4_val2_Click
(object sender, EventArgs e
)
{
if(textBoxSerial4_val2
.Text.Length > 0)
{
trckbarSerial4
.Value = Convert
.ToInt16(textBoxSerial4_val2
.Text);
}
}
private void btnSer4_val3_Click
(object sender, EventArgs e
)
{
if(textBoxSerial4_val3
.Text.Length > 0)
{
trckbarSerial4
.Value = Convert
.ToInt16(textBoxSerial4_val3
.Text);
}
}
#endregion serial control channels
}
public class IniFile
{
public string path
;
[DllImport
("kernel32")]
private static extern long WritePrivateProfileString
(string section,
string key,
string val,
string filePath
);
[DllImport
("kernel32.dll", CharSet
= CharSet
.Auto)]
static extern uint GetPrivateProfileSectionNames
(IntPtr lpszReturnBuffer,
uint nSize,
string lpFileName
);
[DllImport
("kernel32")]
private static extern int GetPrivateProfileString
(string section,
string key,
string def, StringBuilder retVal,
int size,
string filePath
);
public IniFile
(string INIPath
)
{
path
= INIPath
;
}
public void IniWriteValue
(string Section,
string Key,
string Value)
{
WritePrivateProfileString
(Section, Key,
Value,
this.path);
}
public string IniReadValue
(string Section,
string Key
)
{
StringBuilder temp
= new StringBuilder
(255);
int i
= GetPrivateProfileString
(Section, Key,
"", temp,
255,
this.path);
return temp
.ToString();
}
//Ini_sections auslesen in String-Array
public string[] IniSectionNames
()
{
// uint MAX_BUFFER = 32767;
uint MAX_BUFFER
= 8388608;
IntPtr pReturnedString
= Marshal
.AllocCoTaskMem((int)MAX_BUFFER
);
uint bytesReturned
= GetPrivateProfileSectionNames
(pReturnedString, MAX_BUFFER,
this.path);
if (bytesReturned
== 0)
{
Marshal
.FreeCoTaskMem(pReturnedString
);
return null;
}
string local
= Marshal
.PtrToStringAuto(pReturnedString,
(int)bytesReturned
).ToString();
Marshal
.FreeCoTaskMem(pReturnedString
);
//use of Substring below removes terminating null for split
return local
.Substring(0, local
.Length - 1).Split('\0');
}
}
public static class ControlExtensions
{
/// <summary>
/// Execute a threadsafe operation, when accessing a control via another thread
/// action is a lamdaexpression
/// e.g. comboBox1.ExecuteThreadSafe(() => comboBox1.Enabled = true);
/// </summary>
/// <param name="control"> The control </param>
/// <param name="action"> The 'action' to perform </param>
public static void ExecuteThreadSafe
(this Control control, Action action
)
{
if (control
.InvokeRequired)
{
control
.BeginInvoke(action
); //"BeginInvoke" is an async call -> threadsafety error when called to many times successively -> then take "Invoke"
}
else
{
action
.Invoke();
}
}
}
}