summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2013-11-27 01:33:53 +0100
committerStanislaw Halik <sthalik@misaki.pl>2013-11-27 01:33:53 +0100
commit5f17327c0d9d5bd2da69139a324434d461519403 (patch)
tree8d16d0a40decf1c6625756f593f6c4698b8d9a6f
parent324f47f0740dda04cc37674d817b1bfcd1a7ec48 (diff)
initial import of hatire by Furax49
Signed-off-by: Stanislaw Halik <sthalik@misaki.pl>
-rw-r--r--CMakeLists.txt16
-rw-r--r--facetracknoir/clientfiles/HAT_100/HAT_100.ino389
-rw-r--r--facetracknoir/clientfiles/HAT_100/README35
-rw-r--r--ftnoir_tracker_hatire/ftnoir_arduino_type.h31
-rw-r--r--ftnoir_tracker_hatire/ftnoir_hat.qrc6
-rw-r--r--ftnoir_tracker_hatire/ftnoir_hatcontrols.ui1066
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat.cpp304
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat.h102
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat.rc61
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.cpp299
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.h78
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat_dll.cpp79
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.cpp102
-rw-r--r--ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.h44
-rw-r--r--ftnoir_tracker_hatire/images/hat.icobin0 -> 1150 bytes
-rw-r--r--ftnoir_tracker_hatire/images/hat_logo.pngbin0 -> 15210 bytes
16 files changed, 2611 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 12c4cee0..307aeac4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -96,7 +96,7 @@ if(MINGW)
endif()
find_package(OpenCV REQUIRED)
- find_package(Qt5 REQUIRED COMPONENTS Core Xml Network Widgets Gui QUIET)
+ find_package(Qt5 REQUIRED COMPONENTS Core Xml Network Widgets Gui SerialPort QUIET)
cmake_policy(SET CMP0020 NEW)
include_directories(${Qt5Core_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS})
add_definitions(${Qt5Core_DEFINITIONS} ${Qt5Xml_DEFINITIONS} ${Qt5Gui_DEFINITIONS} ${Qt5Widgets_DEFINITIONS} ${Qt5Network_DEFINITIONS})
@@ -308,6 +308,13 @@ file(GLOB opentrack-tracker-hydra-rc "ftnoir_tracker_hydra/*.qrc")
QT5_WRAP_UI(opentrack-tracker-hydra-uih ${opentrack-tracker-hydra-ui})
QT5_ADD_RESOURCES(opentrack-tracker-hydra-rcc ${opentrack-tracker-hydra-rc})
+file(GLOB opentrack-tracker-hatire-c "ftnoir_tracker_hatire/*.cpp")
+file(GLOB opentrack-tracker-hatire-h "ftnoir_tracker_hatire/*.h")
+file(GLOB opentrack-tracker-hatire-ui "ftnoir_tracker_hatire/*.ui")
+file(GLOB opentrack-tracker-hatire-rc "ftnoir_tracker_hatire/*.qrc")
+QT5_WRAP_UI(opentrack-tracker-hatire-uih ${opentrack-tracker-hatire-ui})
+QT5_ADD_RESOURCES(opentrack-tracker-hatire-rcc ${opentrack-tracker-hatire-rc})
+
file(GLOB opentrack-csv-c "ftnoir_csv/*.cpp")
# compat lib for POSIX/win32
@@ -524,6 +531,13 @@ if(SDK_ARUCO_LIBPATH)
endif()
endif()
+add_library(opentrack-tracker-hatire SHARED ${opentrack-tracker-hatire-c} ${opentrack-tracker-hatire-h} ${opentrack-tracker-hatire-moc} ${opentrack-tracker-hatire-uih} ${opentrack-tracker-hatire-rcc})
+target_link_libraries(opentrack-tracker-hatire ${MY_QT_LIBS} Qt5SerialPort)
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC)
+ SET_TARGET_PROPERTIES(opentrack-tracker-hatire
+ PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/facetracknoir/posix-version-script.txt")
+endif()
+
if(WIN32)
target_link_libraries(opentrack-tracker-ht
"${CMAKE_SOURCE_DIR}/dinput/dxguid.lib"
diff --git a/facetracknoir/clientfiles/HAT_100/HAT_100.ino b/facetracknoir/clientfiles/HAT_100/HAT_100.ino
new file mode 100644
index 00000000..f8644ffe
--- /dev/null
+++ b/facetracknoir/clientfiles/HAT_100/HAT_100.ino
@@ -0,0 +1,389 @@
+// Arduino sketch for MPU6050 on NanoWII using DMP MotionApps v4.1
+// HAT 14/04/2013 by FuraX49
+//
+// Head Arduino Tracker for FaceTrackNoIR
+// http://facetracknoir.sourceforge.net/home/default.htm
+// I2C device class (I2Cdev)
+// https://github.com/jrowberg/i2cdevlib
+
+
+#include <avr/eeprom.h>
+#include <Wire.h>
+#include "I2Cdev.h"
+#include "MPU6050_9Axis_MotionApps41.h"
+
+
+MPU6050 mpu;
+
+
+typedef struct {
+ int16_t Begin ; // 2 Debut
+ uint16_t Cpt ; // 2 Compteur trame or Code info or error
+ float gyro[3]; // 12 [Y, P, R] gyro
+ float acc[3]; // 12 [x, y, z] Acc
+ int16_t End ; // 2 Fin
+} _hatire;
+
+typedef struct {
+ int16_t Begin ; // 2 Debut
+ uint16_t Code ; // 2 Code info
+ char Msg[24]; // 24 Message
+ int16_t End ; // 2 Fin
+} _msginfo;
+
+typedef struct
+{
+ byte rate;
+ double gyro_offset[3] ;
+ double acc_offset[3] ;
+} _eprom_save;
+
+
+// MPU control/status vars
+bool dmpReady = false; // set true if DMP init was successful
+bool dmpLoaded = false; // set true if DMP loaded successfuly
+uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
+uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
+uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
+uint16_t fifoCount; // count of all bytes currently in FIFO
+uint8_t fifoBuffer[64]; // FIFO storage buffer
+
+char Commande;
+char Version[] = "HAT V 1.00";
+
+// orientation/motion vars
+Quaternion q; // [w, x, y, z] quaternion container
+VectorInt16 aa; // [x, y, z] accel sensor measurements
+VectorFloat gravity; // [x, y, z] gravity vector
+
+float Rad2Deg = (180/M_PI) ;
+
+// trame for message
+_hatire hatire;
+_msginfo msginfo;
+_eprom_save eprom_save;
+
+
+bool AskCalibrate = false; // set true when calibrating is ask
+int CptCal = 0;
+const int NbCal = 5;
+
+
+
+
+// ================================================================
+// === INTERRUPT DETECTION ROUTINE ===
+// ================================================================
+volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
+
+void dmpDataReady() {
+ mpuInterrupt = true;
+}
+
+// ================================================================
+// === PRINT SERIAL FORMATTE ===
+// ================================================================
+void PrintCodeSerial(uint16_t code,char Msg[24],bool EOL ) {
+ msginfo.Code=code;
+ memset(msginfo.Msg,0x00,24);
+ strcpy(msginfo.Msg,Msg);
+ if (EOL) msginfo.Msg[23]=0x0A;
+ // Send HATIRE message to PC
+ Serial.write((byte*)&msginfo,30);
+}
+
+
+// ================================================================
+// === INITIAL SETUP ===
+// ================================================================
+
+void setup() {
+ // join I2C bus (I2Cdev library doesn't do this automatically)
+ Wire.begin();
+
+ // initialize serial communication
+ while (!Serial); // wait for Leonardo enumeration, others continue immediately
+
+ Serial.begin(115200);
+ PrintCodeSerial(2000,Version,true);
+
+ hatire.Begin=0xAAAA;
+ hatire.Cpt=0;
+ hatire.End=0x5555;
+
+ msginfo.Begin=0xAAAA;
+ msginfo.Code=0;
+ msginfo.End=0x5555;
+
+ // initialize device
+ PrintCodeSerial(3001,"Initializing I2C",true);
+ mpu.initialize();
+
+ // verify connection
+ PrintCodeSerial(3002,"Testing connections",true);
+
+ if (mpu.testConnection()){
+ PrintCodeSerial(3003,"MPU6050 connection OK",true);
+ } else {
+ PrintCodeSerial(9007,"MPU6050 ERRROR CNX",true);
+ }
+
+ while (Serial.available() && Serial.read()); // empty buffer
+
+ // load and configure the DMP
+ PrintCodeSerial(3004,"Initializing DMP...",true);
+ devStatus = mpu.dmpInitialize();
+
+ // make sure it worked (returns 0 if so)
+ if (devStatus == 0) {
+ dmpLoaded=true;
+
+ // Read Epprom saved params
+ PrintCodeSerial(3005,"Reading saved params...",true);
+ ReadParams();
+
+ // turn on the DMP, now that it's ready
+ PrintCodeSerial(3006,"Enabling DMP...",true);
+ mpu.setDMPEnabled(true);
+
+ // enable Arduino interrupt detection
+ PrintCodeSerial(3007,"Enabling interrupt",true);
+ attachInterrupt(0, dmpDataReady, RISING);
+ mpuIntStatus = mpu.getIntStatus();
+
+ // set our DMP Ready flag so the main loop() function knows it's okay to use it
+ PrintCodeSerial(5000,"HAT BEGIN",true);
+ dmpReady = true;
+ // get expected DMP packet size for later comparison
+ packetSize = mpu.dmpGetFIFOPacketSize();
+ // Empty FIFO
+ fifoCount = mpu.getFIFOCount();
+ while (fifoCount > packetSize) {
+ fifoCount = mpu.getFIFOCount();
+ mpu.getFIFOBytes(fifoBuffer, fifoCount);
+ }
+ }
+ else {
+ // ERROR!
+ // 1 = initial memory load failed
+ // 2 = DMP configuration updates failed
+ // (if it's going to break, usually the code will be 1)
+ dmpLoaded=false;
+ PrintCodeSerial(9000+devStatus,"DMP Initialization failed",true);
+ }
+}
+
+
+// ================================================================
+// === RAZ OFFSET ===
+// ================================================================
+void razoffset() {
+ eprom_save.gyro_offset[0] = 0;
+ eprom_save.gyro_offset[1] = 0;
+ eprom_save.gyro_offset[2] = 0;
+ eprom_save.acc_offset[0] = 0;
+ eprom_save.acc_offset[1] = 0;
+ eprom_save.acc_offset[2] = 0;
+}
+
+
+// ================================================================
+// === SAVE PARAMS ===
+// ================================================================
+void SaveParams() {
+ eeprom_write_block((const void*)&eprom_save, (void*) 0, sizeof(eprom_save));
+}
+
+
+
+// ================================================================
+// === READ PARAMS ===
+// ================================================================
+void ReadParams() {
+ eeprom_read_block( (void*)&eprom_save, (void*) 0, sizeof(eprom_save));
+}
+
+
+// ================================================================
+// === Serial Command ===
+// ================================================================
+void serialEvent(){
+ Commande = (char)Serial.read();
+ switch (Commande) {
+ case 'S':
+ PrintCodeSerial(5001,"HAT START",true);
+ if (dmpLoaded==true) {
+ mpu.resetFIFO();
+ hatire.Cpt=0;
+ attachInterrupt(0, dmpDataReady, RISING);
+ mpu.setDMPEnabled(true);
+ dmpReady = true;
+ }
+ else {
+ PrintCodeSerial(9011,"Error DMP not loaded",true);
+ }
+ break;
+
+ case 's':
+ PrintCodeSerial(5002,"HAT STOP",true);
+ if (dmpReady==true) {
+ mpu.setDMPEnabled(false);
+ detachInterrupt(0);
+ dmpReady = false;
+ }
+ break;
+
+ case 'R':
+ PrintCodeSerial(5003,"HAT RESET",true);
+ if (dmpLoaded==true) {
+ mpu.setDMPEnabled(false);
+ detachInterrupt(0);
+ mpu.resetFIFO();
+ hatire.Cpt=0;
+ dmpReady = false;
+ setup();
+ }
+ else {
+ PrintCodeSerial(9011,"Error DMP not loaded",true);
+ }
+ break;
+
+
+ case 'C':
+ CptCal=0;
+ razoffset();
+ AskCalibrate=true;
+ break;
+
+ case 'V':
+ PrintCodeSerial(2000,Version,true);
+ break;
+
+ case 'I':
+ Serial.println();
+ Serial.print("Version : \t");
+ Serial.println(Version);
+ Serial.println("Gyroscopes offsets");
+ for (int i=0; i <= 2; i++) {
+ Serial.print(i);
+ Serial.print(" : ");
+ Serial.print(eprom_save.gyro_offset[i]);
+ Serial.println();
+ }
+ Serial.println("Accelerometers offsets");
+ for (int i=0; i <= 2; i++) {
+ Serial.print(i);
+ Serial.print(" : ");
+ Serial.print(eprom_save.acc_offset[i]);
+ Serial.println();
+ }
+ break;
+
+
+ default:
+ break;
+ }
+}
+
+
+// ================================================================
+// === MAIN PROGRAM LOOP ===
+// ================================================================
+void loop() {
+ // Leonardo BUG (simul Serial Event)
+ if(Serial.available() > 0) serialEvent();
+
+
+ // if programming failed, don't try to do anything
+ if (dmpReady) {
+
+
+ while (!mpuInterrupt && fifoCount < packetSize) ;
+
+ // reset interrupt flag and get INT_STATUS byte
+ mpuInterrupt = false;
+ mpuIntStatus = mpu.getIntStatus();
+
+ // get current FIFO count
+ fifoCount = mpu.getFIFOCount();
+
+ // check for overflow (this should never happen unless our code is too inefficient)
+ if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
+ // reset so we can continue cleanly
+ mpu.resetFIFO();
+ PrintCodeSerial(9010,"Overflow FIFO DMP",true);
+ hatire.Cpt=0;
+
+ // otherwise, check for DMP data ready interrupt (this should happen frequently)
+ }
+ else if (mpuIntStatus & 0x02) {
+ // wait for correct available data length, should be a VERY short wait
+ while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
+
+ // read a packet from FIFO
+ mpu.getFIFOBytes(fifoBuffer, packetSize);
+
+ // track FIFO count here in case there is > 1 packet available
+ // (this lets us immediately read more without waiting for an interrupt)
+ fifoCount -= packetSize;
+
+ // Get Euler angles in degrees
+ mpu.dmpGetQuaternion(&q, fifoBuffer);
+ mpu.dmpGetGravity(&gravity, &q);
+ mpu.dmpGetYawPitchRoll(hatire.gyro, &q, &gravity);
+
+ // Get real acceleration, adjusted to remove gravity
+ // not used in this script
+ // mpu.dmpGetAccel(&aa, fifoBuffer);
+ // mpu.dmpGetLinearAccel(&hatire.acc, &aa, &gravity);
+
+ // Calibration sur X mesures
+ if (AskCalibrate) {
+ if ( CptCal>=NbCal) {
+ CptCal=0;
+ eprom_save.gyro_offset[0] = eprom_save.gyro_offset[0] / NbCal ;
+ eprom_save.gyro_offset[1] = eprom_save.gyro_offset[1] / NbCal ;
+ eprom_save.gyro_offset[2] = eprom_save.gyro_offset[2] / NbCal ;
+ AskCalibrate=false;
+ SaveParams();
+ }
+ else {
+ eprom_save.gyro_offset[0] += (float) hatire.gyro[0];
+ eprom_save.gyro_offset[1] += (float) hatire.gyro[1];
+ eprom_save.gyro_offset[2] += (float) hatire.gyro[2];
+
+ CptCal++;
+ }
+ }
+
+
+ // Conversion angles Euler en +-180 Degr�es
+ for (int i=0; i <= 2; i++) {
+ hatire.gyro[i]= (hatire.gyro[i] - eprom_save.gyro_offset[i] ) * Rad2Deg;
+ if (hatire.gyro[i]>180) {
+ hatire.gyro[i] = hatire.gyro[i] - 360;
+ }
+ }
+
+ if (AskCalibrate) {
+ hatire.gyro[0] = 0;
+ hatire.gyro[1] = 0;
+ hatire.gyro[2] = 0;
+ hatire.acc[0]= 0;
+ hatire.acc[1] = 0;
+ hatire.acc[2] = 0;
+ }
+
+ // Send Trame to HATIRE PC
+ Serial.write((byte*)&hatire,30);
+
+ hatire.Cpt++;
+ if (hatire.Cpt>999) {
+ hatire.Cpt=0;
+ }
+ }
+ }
+ delay(1);
+}
+
+
diff --git a/facetracknoir/clientfiles/HAT_100/README b/facetracknoir/clientfiles/HAT_100/README
new file mode 100644
index 00000000..1e4f2926
--- /dev/null
+++ b/facetracknoir/clientfiles/HAT_100/README
@@ -0,0 +1,35 @@
+ Frame exchange protocol fixed size of 30 bytes like this :
+
+ typedef struct {
+ int16_t Begin ; // 2 Debut
+ uint16_t Cpt ; // 2 Compteur trame or Code
+ float gyro[3]; // 12 [Y, P, R] gyro
+ float acc[3]; // 12 [x, y, z] Acc
+ int16_t End ; // 2 Fin
+} _hatire;
+_hat hat;
+
+
+void setup() {
+ Serial.begin(115200);
+ // header frame
+ hatire.Begin=0xAAAA;
+ // Frame Number or Error code
+ hat.Cpt=0;
+ // footer frame
+ hat.End=0x5555;
+}
+
+
+ void loop() {
+ mpu.dmpGetYawPitchRoll(hatire.gyro);
+ mpu.dmpAccXYZ(hatire.acc);
+ // Send Trame to HATIRE PC
+ Serial.write((byte*)&hatire,30);
+ hatire.Cpt++;
+ if (hatire.Cpt>999) {
+ hatire.Cpt=0;
+ }
+ delay(1);
+}
+
diff --git a/ftnoir_tracker_hatire/ftnoir_arduino_type.h b/ftnoir_tracker_hatire/ftnoir_arduino_type.h
new file mode 100644
index 00000000..4d19043b
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_arduino_type.h
@@ -0,0 +1,31 @@
+#ifndef FTNOIR_TARDUINO_TYPE_H
+#define FTNOIR_TARDUINO_TYPE_H
+
+// Arduino trame structure
+#pragma pack(push,2)
+struct TArduinoData
+{
+ quint16 Begin; // Header trame 0xAAAA;
+ quint16 Code; // 0->999 Num Trame >=2000 Info >=3000 Init >=5000 Start Command >=9000 Error
+ float Gyro[3];
+ float Acc[3];
+ quint16 End; // End trame 0x5555;
+} ;
+#pragma pack(pop)
+
+
+inline QDataStream & operator >> ( QDataStream& in, TArduinoData& out )
+{
+ in.setByteOrder(QDataStream::LittleEndian );
+ in.setFloatingPointPrecision(QDataStream::SinglePrecision );
+
+ in >> (quint16)out.Begin >> (quint16)out.Code
+ >> (float)out.Gyro[0] >> (float)out.Gyro[1] >> (float)out.Gyro[2]
+ >> (float)out.Acc[0] >> (float)out.Acc[1] >> (float)out.Acc[2]
+ >> (quint16)out.End;
+ return in;
+}
+
+
+
+#endif \ No newline at end of file
diff --git a/ftnoir_tracker_hatire/ftnoir_hat.qrc b/ftnoir_tracker_hatire/ftnoir_hat.qrc
new file mode 100644
index 00000000..4c606f92
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_hat.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>images/hat.ico</file>
+ <file>images/hat_logo.png</file>
+ </qresource>
+</RCC>
diff --git a/ftnoir_tracker_hatire/ftnoir_hatcontrols.ui b/ftnoir_tracker_hatire/ftnoir_hatcontrols.ui
new file mode 100644
index 00000000..86f9e48a
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_hatcontrols.ui
@@ -0,0 +1,1066 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UIHATControls</class>
+ <widget class="QWidget" name="UIHATControls">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>370</width>
+ <height>520</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>370</width>
+ <height>520</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>370</width>
+ <height>520</height>
+ </size>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="windowTitle">
+ <string>Head Arduino Tracker settings FaceTrackNoIR</string>
+ </property>
+ <property name="windowIcon">
+ <iconset>
+ <normaloff>images/hat.ico</normaloff>images/hat.ico</iconset>
+ </property>
+ <property name="windowOpacity">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="layoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>480</y>
+ <width>361</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_frm_dialog">
+ <item>
+ <widget class="QPushButton" name="btnOK">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>80</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnSave">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>80</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnCancel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>80</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>360</width>
+ <height>470</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>360</width>
+ <height>470</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>360</width>
+ <height>470</height>
+ </size>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="usesScrollButtons">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="tab_config">
+ <attribute name="icon">
+ <iconset resource="ftnoir_hat.qrc">
+ <normaloff>:/images/hat.ico</normaloff>:/images/hat.ico</iconset>
+ </attribute>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <widget class="QGroupBox" name="groupBox_status">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>350</y>
+ <width>331</width>
+ <height>91</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Information</string>
+ </property>
+ <widget class="QWidget" name="formLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>311</width>
+ <height>51</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayout_status">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>10</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="lab_tps">
+ <property name="minimumSize">
+ <size>
+ <width>31</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>13</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Trame per seconde</string>
+ </property>
+ <property name="text">
+ <string>tps :</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="lab_status">
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Status :</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="lab_vstatus">
+ <property name="minimumSize">
+ <size>
+ <width>170</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="lab_vtps">
+ <property name="minimumSize">
+ <size>
+ <width>31</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>13</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>00</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>130</y>
+ <width>331</width>
+ <height>211</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>106</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Axis Configuration</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <widget class="QWidget" name="layoutWidget_Configuration">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>311</width>
+ <height>181</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinAndMaxSize</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="3" column="2">
+ <widget class="QCheckBox" name="chkEnableYaw">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Enable Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="chkEnableRoll">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Enable Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QComboBox" name="cb_yaw">
+ <property name="toolTip">
+ <string>Associate Axis</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>RotX</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>RotY</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>RotZ</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="label_yaw">
+ <property name="text">
+ <string>Yaw:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QComboBox" name="cb_roll">
+ <property name="toolTip">
+ <string>Associate Axis</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>RotX</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>RotY</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>RotZ</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QComboBox" name="cb_pitch">
+ <property name="toolTip">
+ <string>Associate Axis</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>RotX</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>RotY</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>RotZ</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QCheckBox" name="chkEnablePitch">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Enable Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_pitch">
+ <property name="text">
+ <string>Pitch:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label_roll">
+ <property name="text">
+ <string>Roll:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QCheckBox" name="chkInvertRoll">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Invert Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="4">
+ <widget class="QCheckBox" name="chkInvertPitch">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Invert Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="4">
+ <widget class="QCheckBox" name="chkInvertYaw">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Invert Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Enable</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Axis</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Invert</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="label_x">
+ <property name="text">
+ <string>X:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QCheckBox" name="chkEnableX">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Enable Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QComboBox" name="cb_x">
+ <property name="toolTip">
+ <string>Associate Axis</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Z</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="4" column="4">
+ <widget class="QCheckBox" name="chkInvertX">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Invert Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="label_y">
+ <property name="text">
+ <string>Y:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2">
+ <widget class="QCheckBox" name="chkEnableY">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Enable Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="3">
+ <widget class="QComboBox" name="cb_y">
+ <property name="toolTip">
+ <string>Associate Axis</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Z</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="5" column="4">
+ <widget class="QCheckBox" name="chkInvertY">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Invert Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QLabel" name="label_z">
+ <property name="text">
+ <string>Z:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="2">
+ <widget class="QCheckBox" name="chkEnableZ">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Enable Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="3">
+ <widget class="QComboBox" name="cb_z">
+ <property name="toolTip">
+ <string>Associate Axis</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Z</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="6" column="4">
+ <widget class="QCheckBox" name="chkInvertZ">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Invert Axis</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <spacer name="horizontalSpacer_12">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer_11">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QWidget" name="layoutWidget6">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>90</y>
+ <width>331</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout__arduino">
+ <item>
+ <spacer name="horizontalSpacer_10">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>13</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnCenter">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Center</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>13</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnReset">
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Reset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>13</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="layoutWidget1">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>331</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Serial Port :</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="cbSerialPort">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToMinimumContentsLength</enum>
+ </property>
+ <property name="modelColumn">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="horizontalLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>50</y>
+ <width>331</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_serial">
+ <property name="leftMargin">
+ <number>7</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_info">
+ <property name="text">
+ <string>Choose the Serial Com port where is connected ARDUINO.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QWidget" name="tab_about">
+ <attribute name="title">
+ <string>About</string>
+ </attribute>
+ <widget class="QLabel" name="label_10">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>111</width>
+ <height>111</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;FTNoIR HAT Plugin&lt;br /&gt;Version 1.0&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by FuraX49&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://hatire.sourceforge.net/&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#0000ff;&quot;&gt;Manual (external)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_35">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>20</y>
+ <width>128</width>
+ <height>128</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="ftnoir_hat.qrc">:/images/hat_logo.png</pixmap>
+ </property>
+ </widget>
+ <widget class="QPlainTextEdit" name="pteINFO">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>190</y>
+ <width>331</width>
+ <height>251</height>
+ </rect>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="maximumBlockCount">
+ <number>800</number>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="lineSend">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>160</y>
+ <width>241</width>
+ <height>20</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="btnSend">
+ <property name="geometry">
+ <rect>
+ <x>260</x>
+ <y>160</y>
+ <width>75</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Send</string>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ <tabstops>
+ <tabstop>btnCancel</tabstop>
+ </tabstops>
+ <resources>
+ <include location="ftnoir_hat.qrc"/>
+ </resources>
+ <connections/>
+ <slots>
+ <slot>startEngineClicked()</slot>
+ <slot>stopEngineClicked()</slot>
+ <slot>cameraSettingsClicked()</slot>
+ </slots>
+</ui>
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat.cpp b/ftnoir_tracker_hatire/ftnoir_tracker_hat.cpp
new file mode 100644
index 00000000..e961a10f
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat.cpp
@@ -0,0 +1,304 @@
+/********************************************************************************
+* FaceTrackNoIR This program is a private project of some enthusiastic *
+* gamers from Holland, who don't like to pay much for *
+* head-tracking. *
+* *
+* Copyright (C) 2012 Wim Vriend (Developing) *
+* Ron Hendriks (Researching and Testing) *
+* *
+* Homepage: http://facetracknoir.sourceforge.net/home/default.htm *
+* *
+* This program 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. *
+* *
+* This program 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 this program; if not, see <http://www.gnu.org/licenses/>. *
+* *
+********************************************************************************/
+
+
+#include "ftnoir_tracker_hat.h"
+#include <QMessageBox>
+#include <QDebug>
+#include <QCoreApplication>
+
+FTNoIR_Tracker::FTNoIR_Tracker()
+{
+ SerialPort = NULL;
+ waitTimeout = 1000;
+ TrackerSettings settings;
+ settings.load_ini();
+ applysettings(settings);
+
+
+ // Create events
+ m_StopThread = CreateEvent(0, TRUE, FALSE, 0);
+ m_WaitThread = CreateEvent(0, TRUE, FALSE, 0);
+
+ ListErrInf = new QList<QString>();
+
+ // prepare & reserve QByteArray
+ datagram.reserve(30);
+}
+
+FTNoIR_Tracker::~FTNoIR_Tracker()
+{
+ // Trigger thread to stop
+ ::SetEvent(m_StopThread);
+
+ // Wait until thread finished
+ if (isRunning()) {
+ ::WaitForSingleObject(m_WaitThread, INFINITE);
+ }
+
+ // Close handles
+ ::CloseHandle(m_StopThread);
+ ::CloseHandle(m_WaitThread);
+
+ if (SerialPort!=NULL) {
+ if (SerialPort->isOpen() ) {
+ SerialPort->putChar('s'); //Send STOP to Arduino
+ SerialPort->close();
+ }
+ delete SerialPort;
+ SerialPort=NULL;
+ }
+
+}
+
+//send CENTER to Arduino
+void FTNoIR_Tracker::notifyCenter() {
+ if (SerialPort!=NULL) {
+ if (SerialPort->isOpen() ) {
+ SerialPort->putChar('C');
+ }
+ }
+}
+
+
+
+//send CENTER to Arduino
+void FTNoIR_Tracker::center() {
+ if (SerialPort!=NULL) {
+ if (SerialPort->isOpen() ) {
+ SerialPort->putChar('C');
+ }
+ }
+}
+
+//send RESET to Arduino
+void FTNoIR_Tracker::reset() {
+ if (SerialPort!=NULL) {
+ if (SerialPort->isOpen() ) {
+ SerialPort->putChar('R');
+ }
+ }
+}
+
+//send command to Arduino
+void FTNoIR_Tracker::sendcmd(QString* cmd) {
+ QReadLocker locker(&rwlock);
+ QByteArray bytes;
+ if (SerialPort!=NULL) {
+ if (SerialPort->isOpen() ) {
+ bytes.append(cmd->toAscii());
+ SerialPort->write(bytes);
+ }
+ }
+}
+
+// return FPS and last status
+void FTNoIR_Tracker::get_info(QString* info, int* tps ){
+ QReadLocker locker(&rwlock);
+ *tps=HAT.Code;
+ if (ListErrInf->size()>0) {
+ *info=ListErrInf->takeFirst();
+ } else {
+ *info= QString();
+ }
+}
+
+
+/** QThread run @override **/
+void FTNoIR_Tracker::run() {
+ //
+ // Read the data that was received.
+ //
+ forever {
+
+ // Check event for stop thread
+ if(::WaitForSingleObject(m_StopThread, 0) == WAIT_OBJECT_0)
+ {
+ // Set event
+ ::SetEvent(m_WaitThread);
+ qDebug() << "FTNoIR_Tracker::run() terminated run()";
+ return;
+ }
+ if (SerialPort->bytesAvailable()>=30) {
+ QWriteLocker locker(&rwlock);
+ datagram.clear();
+ datagram=SerialPort->read(30);
+ QDataStream datastream(datagram);
+ datastream>>ArduinoData;
+
+ if (ArduinoData.Begin==0xAAAA && ArduinoData.End==0x5555 ) {
+ if (ArduinoData.Code <= 1000) {
+ HAT=ArduinoData;
+ } else {
+ ListErrInf->push_back(QString::fromAscii(datagram.mid(4,24),24)) ;
+ }
+ } else {
+ SerialPort->read(1);
+ }
+ }
+ //for lower cpu load
+ usleep(10000);
+ }
+}
+
+void FTNoIR_Tracker::Initialize( QFrame *videoframe )
+{
+ qDebug() << "FTNoIR_Tracker::Initialize says: Starting ";
+
+ //
+ // Create SerialPort if they don't exist already.
+ // They must be created here, because they must be in the new thread (FTNoIR_Tracker::run())
+ //
+
+ if (SerialPort == NULL) {
+ qDebug() << "FTNoIR_Tracker::Initialize() Open SerialPort";
+ SerialPort = new QextSerialPort(sSerialPortName);
+ if (SerialPort->open(QIODevice::ReadWrite | QIODevice::Unbuffered ) == true) {
+ SerialPort->flush();
+ SerialPort->setBaudRate(BAUD115200);
+ SerialPort->setParity(PAR_NONE);
+ SerialPort->setDataBits(DATA_8);
+ SerialPort->setStopBits(STOP_1);
+ SerialPort->setFlowControl(FLOW_OFF);
+ SerialPort->setTimeout(waitTimeout);
+ SerialPort->setQueryMode(QextSerialPort::EventDriven); //Polling
+ // Send START to arduino
+ SerialPort->putChar('S');
+ }
+ else {
+ QMessageBox::warning(0,"FaceTrackNoIR Error", "Unable to open SerialPort",QMessageBox::Ok,QMessageBox::NoButton);
+ delete SerialPort;
+ SerialPort = NULL;
+ }
+ }
+ return;
+}
+
+void FTNoIR_Tracker::StartTracker( HWND parent_window )
+{
+ start( QThread::TimeCriticalPriority );
+ return;
+}
+
+void FTNoIR_Tracker::StopTracker( bool exit )
+{
+ //
+ // OK, the thread is not stopped, doing this. That might be dangerous anyway...
+ //
+ if (exit || !exit) return;
+ return;
+}
+
+//
+// Return 6DOF info
+//
+bool FTNoIR_Tracker::GiveHeadPoseData(THeadPoseData *data)
+{
+ QReadLocker locker(&rwlock);
+ data->frame_number = HAT.Code;
+
+ if (bEnableYaw) {
+ if (bInvertYaw ) data->yaw = HAT.Gyro[iYawAxe] * -1.0f;
+ else data->yaw = HAT.Gyro[iYawAxe];
+ }
+
+ if (bEnablePitch) {
+ if (bInvertPitch)data->pitch = HAT.Gyro[iPitchAxe] * -1.0f;
+ else data->pitch = HAT.Gyro[iPitchAxe];
+ }
+
+ if (bEnableRoll) {
+ if (bInvertRoll) data->roll = HAT.Gyro[iRollAxe] * -1.0f;
+ else data->roll = HAT.Gyro[iRollAxe];
+ }
+
+ if (bEnableX) {
+ if (bInvertX) data->x = HAT.Acc[iXAxe]* -1.0f;
+ else data->x = HAT.Acc[iXAxe];
+ }
+
+ if (bEnableY) {
+ if (bInvertY) data->y = HAT.Acc[iYAxe]* -1.0f;
+ else data->y = HAT.Acc[iYAxe];
+ }
+
+ if (bEnableZ) {
+ if (bInvertZ) data->z = HAT.Acc[iZAxe]* -1.0f;
+ else data->z = HAT.Acc[iZAxe];
+ }
+
+ return true;
+}
+
+
+
+//
+// Apply modification Settings
+//
+void FTNoIR_Tracker::applysettings(const TrackerSettings& settings){
+ qDebug()<<"Tracker:: Applying settings";
+
+ QReadLocker locker(&rwlock);
+ sSerialPortName= settings.SerialPortName;
+
+ bEnableRoll = settings.EnableRoll;
+ bEnablePitch = settings.EnablePitch;
+ bEnableYaw = settings.EnableYaw;
+ bEnableX = settings.EnableX;
+ bEnableY = settings.EnableY;
+ bEnableZ = settings.EnableZ;
+
+ bInvertRoll = settings.InvertRoll;
+ bInvertPitch = settings.InvertPitch;
+ bInvertYaw = settings.InvertYaw;
+ bInvertX = settings.InvertX;
+ bInvertY = settings.InvertY;
+ bInvertZ = settings.InvertZ;
+
+
+ iRollAxe= settings.RollAxe;
+ iPitchAxe= settings.PitchAxe;
+ iYawAxe= settings.YawAxe;
+ iXAxe= settings.XAxe;
+ iYAxe= settings.YAxe;
+ iZAxe= settings.ZAxe;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Factory function that creates instances if the Tracker object.
+
+// Export both decorated and undecorated names.
+// GetTracker - Undecorated name, which can be easily used with GetProcAddress
+// Win32 API function.
+// _GetTracker@0 - Common name decoration for __stdcall functions in C language.
+#pragma comment(linker, "/export:GetTracker=_GetTracker@0")
+
+FTNOIR_TRACKER_BASE_EXPORT ITrackerPtr __stdcall GetTracker()
+{
+ return new FTNoIR_Tracker;
+}
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat.h b/ftnoir_tracker_hatire/ftnoir_tracker_hat.h
new file mode 100644
index 00000000..54e67f48
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat.h
@@ -0,0 +1,102 @@
+#ifndef FTNOIR_TRACKER_HAT_H
+#define FTNOIR_TRACKER_HAT_H
+
+#include "..\ftnoir_tracker_base\ftnoir_tracker_base.h"
+#include "ftnoir_tracker_hat_settings.h"
+#include "ftnoir_arduino_type.h"
+
+#include <QExtSerialPort\qextserialport.h>
+#include <QExtSerialPort\qextserialenumerator.h>
+#include <QThread>
+#include <QReadWriteLock>
+#include <QTimer>
+#include <QSettings>
+#include "Windows.h"
+#include "math.h"
+
+class QextSerialPort;
+class QExtSerialEnumerator;
+
+class FTNoIR_Tracker : public ITracker, QThread
+{
+
+public:
+ FTNoIR_Tracker();
+ ~FTNoIR_Tracker();
+
+ void Initialize( QFrame *videoframe );
+ void StartTracker( HWND parent_window );
+ void StopTracker( bool exit );
+ bool GiveHeadPoseData(THeadPoseData *data);
+
+ void applysettings(const TrackerSettings& settings);
+ void notifyCenter();
+ void center();
+ void reset();
+ void sendcmd(QString* cmd);
+ void get_info(QString* info , int* tps );
+
+protected:
+ void run(); // qthread override run method
+
+
+private:
+ // Handles to neatly terminate thread...
+ HANDLE m_StopThread;
+ HANDLE m_WaitThread;
+
+ TArduinoData ArduinoData, HAT ; // Trame from Arduino
+ QByteArray datagram;
+ QextSerialPort *SerialPort;
+ QReadWriteLock rwlock;
+ QList<QString>* ListErrInf ;
+ int waitTimeout;
+ QString sSerialPortName; // Port serial name
+ bool bEnableRoll;
+ bool bEnablePitch;
+ bool bEnableYaw;
+ bool bEnableX;
+ bool bEnableY;
+ bool bEnableZ;
+
+ bool bInvertRoll;
+ bool bInvertPitch;
+ bool bInvertYaw;
+ bool bInvertX;
+ bool bInvertY;
+ bool bInvertZ;
+
+
+ int iRollAxe;
+ int iPitchAxe;
+ int iYawAxe;
+ int iXAxe;
+ int iYAxe;
+ int iZAxe;
+
+};
+
+
+//*******************************************************************************************************
+// FaceTrackNoIR Tracker DLL. Functions used to get general info on the Tracker
+//*******************************************************************************************************
+class FTNoIR_TrackerDll : public ITrackerDll
+{
+public:
+ FTNoIR_TrackerDll();
+ ~FTNoIR_TrackerDll();
+
+ void Initialize();
+
+ void getFullName(QString *strToBeFilled);
+ void getShortName(QString *strToBeFilled);
+ void getDescription(QString *strToBeFilled);
+ void getIcon(QIcon *icon);
+
+private:
+ QString trackerFullName; // Trackers' name and description
+ QString trackerShortName;
+ QString trackerDescription;
+};
+
+#endif // FTNOIR_TRACKER_HAT_H \ No newline at end of file
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat.rc b/ftnoir_tracker_hatire/ftnoir_tracker_hat.rc
new file mode 100644
index 00000000..62e0a613
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat.rc
@@ -0,0 +1,61 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+//#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.cpp b/ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.cpp
new file mode 100644
index 00000000..b889341f
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.cpp
@@ -0,0 +1,299 @@
+/********************************************************************************
+* FaceTrackNoIR This program is a private project of some enthusiastic *
+* gamers from Holland, who don't like to pay much for *
+* head-tracking. *
+* *
+* Copyright (C) 2012 Wim Vriend (Developing) *
+* Ron Hendriks (Researching and Testing) *
+* *
+* Homepage: http://facetracknoir.sourceforge.net/home/default.htm *
+* *
+* This program 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. *
+* *
+* This program 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 this program; if not, see <http://www.gnu.org/licenses/>. *
+* *
+********************************************************************************/
+#include "ftnoir_tracker_hat.h"
+#include "ftnoir_tracker_hat_dialog.h"
+
+#include <QMessageBox>
+#include <QDebug>
+
+//*******************************************************************************************************
+// FaceTrackNoIR Client Settings-dialog.
+//*******************************************************************************************************
+
+//
+// Constructor for server-settings-dialog
+//
+TrackerControls::TrackerControls() : settingsDirty(false), theTracker(NULL), timer(this),
+QWidget()
+{
+
+ settingsDirty= false;
+ theTracker = NULL;
+ ui.setupUi( this );
+ pre_trame = 0;
+ settings.load_ini();
+
+ // make SerialPort list
+ foreach (QextPortInfo PortInfo , QextSerialEnumerator::getPorts() ) {
+ ui.cbSerialPort->addItem(PortInfo.portName);
+ }
+ // Stop if no SerialPort dispo
+ if (ui.cbSerialPort->count()<1) {
+ QMessageBox::critical(this,"FaceTrackNoIR Error", "No SerialPort avaible");
+ } else {
+
+ int indxport =ui.cbSerialPort->findText(settings.SerialPortName,Qt::MatchExactly );
+ if (indxport!=-1) {
+ ui.cbSerialPort->setCurrentIndex(indxport);
+ } else {
+ QMessageBox::warning(this,"FaceTrackNoIR Error", "Selected SerialPort modified");
+ ui.cbSerialPort-> setCurrentIndex(indxport);
+ }
+ }
+
+ ui.chkEnableRoll->setChecked(settings.EnableRoll);
+ ui.chkEnablePitch->setChecked(settings.EnablePitch);
+ ui.chkEnableYaw->setChecked(settings.EnableYaw);
+ ui.chkEnableX->setChecked(settings.EnableX);
+ ui.chkEnableY->setChecked(settings.EnableY);
+ ui.chkEnableZ->setChecked(settings.EnableZ);
+
+ ui.chkInvertRoll->setChecked(settings.InvertRoll);
+ ui.chkInvertPitch->setChecked(settings.InvertPitch);
+ ui.chkInvertYaw->setChecked(settings.InvertYaw);
+ ui.chkInvertX->setChecked(settings.InvertX);
+ ui.chkInvertY->setChecked(settings.InvertY);
+ ui.chkInvertZ->setChecked(settings.InvertZ);
+
+
+ ui.cb_roll->setCurrentIndex(settings.RollAxe);
+ ui.cb_pitch->setCurrentIndex(settings.PitchAxe);
+ ui.cb_yaw->setCurrentIndex(settings.YawAxe);
+ ui.cb_x->setCurrentIndex(settings.XAxe);
+ ui.cb_y->setCurrentIndex(settings.YAxe);
+ ui.cb_z->setCurrentIndex(settings.ZAxe);
+
+
+ // Connect Qt signals to member-functions
+ connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK()));
+ connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel()));
+ connect(ui.btnSave, SIGNAL(clicked()), this, SLOT(doSave()));
+
+
+ connect(ui.cbSerialPort, SIGNAL(currentIndexChanged(QString)), this,SLOT(set_mod_port(QString)) );
+
+ connect( ui.chkEnableRoll,SIGNAL(toggled(bool)), this,SLOT(set_ena_roll(bool)) );
+ connect( ui.chkEnablePitch,SIGNAL(toggled(bool)), this,SLOT(set_ena_pitch(bool)) );
+ connect( ui.chkEnableYaw,SIGNAL(toggled(bool)), this,SLOT(set_ena_yaw(bool)) );
+ connect( ui.chkEnableX,SIGNAL(toggled(bool)), this,SLOT(set_ena_x(bool)) );
+ connect( ui.chkEnableY,SIGNAL(toggled(bool)), this,SLOT(set_ena_y(bool)) );
+ connect( ui.chkEnableZ,SIGNAL(toggled(bool)), this,SLOT(set_ena_z(bool)) );
+
+ connect( ui.chkInvertRoll,SIGNAL(toggled(bool)), this,SLOT(set_inv_roll(bool)) );
+ connect( ui.chkInvertPitch,SIGNAL(toggled(bool)), this,SLOT(set_inv_pitch(bool)) );
+ connect( ui.chkInvertYaw,SIGNAL(toggled(bool)), this,SLOT(set_inv_yaw(bool)) );
+ connect( ui.chkInvertX,SIGNAL(toggled(bool)), this,SLOT(set_inv_x(bool)) );
+ connect( ui.chkInvertY,SIGNAL(toggled(bool)), this,SLOT(set_inv_y(bool)) );
+ connect( ui.chkInvertZ,SIGNAL(toggled(bool)), this,SLOT(set_inv_z(bool)) );
+
+
+ connect(ui.cb_roll, SIGNAL(currentIndexChanged(int)), this,SLOT(set_rot_roll(int)));
+ connect(ui.cb_pitch, SIGNAL(currentIndexChanged(int)),this,SLOT(set_rot_pitch(int)));
+ connect(ui.cb_yaw, SIGNAL(currentIndexChanged(int)), this,SLOT(set_rot_yaw(int)));
+ connect(ui.cb_x, SIGNAL(currentIndexChanged(int)), this,SLOT(set_acc_x(int)));
+ connect(ui.cb_y, SIGNAL(currentIndexChanged(int)), this,SLOT(set_acc_y(int)));
+ connect(ui.cb_z, SIGNAL(currentIndexChanged(int)), this,SLOT(set_acc_z(int)));
+
+ connect(ui.btnReset, SIGNAL(clicked()), this, SLOT(doReset()));
+ connect(ui.btnCenter, SIGNAL(clicked()), this, SLOT(doCenter()));
+ connect(ui.btnSend, SIGNAL(clicked()), this, SLOT(doSend()));
+
+ connect(&timer,SIGNAL(timeout()), this,SLOT(poll_tracker_info()));
+}
+
+//
+// Destructor for server-dialog
+//
+TrackerControls::~TrackerControls() {
+ delete this;
+}
+
+
+//
+// Initialize tracker-client-dialog
+//
+void TrackerControls::Initialize(QWidget *parent) {
+ QPoint offsetpos(100, 100);
+ if (parent) {
+ this->move(parent->pos() + offsetpos);
+ }
+ show();
+}
+
+
+//
+// Apply online settings to tracker
+//
+void TrackerControls::settings_changed()
+{
+ settingsDirty = true;
+ if (theTracker) theTracker->applysettings(settings);
+}
+
+
+//
+// Center asked to ARDUINO
+//
+void TrackerControls::doCenter() {
+ if (theTracker) theTracker->center();
+}
+
+//
+// Reset asked to ARDUINO
+//
+void TrackerControls::doReset() {
+ if (theTracker) theTracker->reset();
+}
+
+
+//
+// Send command to ARDUINO
+//
+void TrackerControls::doSend() {
+ if (theTracker) {
+ if (!ui.lineSend->text().isEmpty()) {
+ QString cmd;
+ cmd=ui.lineSend->text();
+ theTracker->sendcmd(&cmd);
+ ui.lineSend->clear();
+ }
+ }
+}
+
+
+//
+// Display FPS and Status of Arduino.
+//
+void TrackerControls::poll_tracker_info()
+{
+ if (theTracker)
+ {
+ QString info;
+ int num_trame;
+ int nb_trame;
+
+ theTracker->get_info(&info,&num_trame);
+ if ( !info.isNull()) {
+ ui.lab_vstatus->setText(info);
+ ui.pteINFO->moveCursor(QTextCursor::End);
+ ui.pteINFO->insertPlainText(info);
+ }
+
+
+ if (pre_trame<num_trame)
+ { nb_trame=num_trame-pre_trame;}
+ else
+ {nb_trame=(1000-pre_trame)+num_trame;}
+ ui.lab_vtps->setText(QString::number(nb_trame*(1000/timer.interval())));
+
+ pre_trame=num_trame;
+ }
+
+}
+
+
+void TrackerControls::doSave() {
+ settingsDirty=false;
+ settings.save_ini();
+}
+
+
+//
+// OK clicked on server-dialog
+//
+void TrackerControls::doOK() {
+ settingsDirty=false;
+ settings.save_ini();
+ this->close();
+}
+
+//
+// Cancel clicked on server-dialog
+//
+void TrackerControls::doCancel() {
+ //
+ // Ask if changed Settings should be saved
+ //
+ if (settingsDirty) {
+ int ret = QMessageBox::question ( this, "Settings have changed", "Do you want to save the settings?", QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard );
+
+ // qDebug() << "doCancel says: answer =" << ret;
+
+ switch (ret) {
+ case QMessageBox::Save:
+ settings.save_ini();
+ close();
+ break;
+ case QMessageBox::Discard:
+ close();
+ break;
+ case QMessageBox::Cancel:
+ // Cancel was clicked
+ break;
+ default:
+ // should never be reached
+ break;
+ }
+ }
+ else {
+ close();
+ }
+}
+
+
+void TrackerControls::registerTracker(ITracker *tracker) {
+// theTracker = (FTNoIR_Tracker *) tracker;
+ theTracker = static_cast<FTNoIR_Tracker*>(tracker);
+ if (isVisible() && settingsDirty) theTracker->applysettings(settings);
+ ui.cbSerialPort->setEnabled(false);
+ timer.start(250);
+ ui.lab_vstatus->setText("HAT START");
+}
+
+
+void TrackerControls::unRegisterTracker() {
+ theTracker = NULL;
+ ui.cbSerialPort->setEnabled(true);
+ timer.stop();
+ ui.lab_vstatus->setText("HAT STOPPED");
+ ui.lab_vtps->setText("");
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Factory function that creates instances if the Tracker-settings dialog object.
+
+// Export both decorated and undecorated names.
+// GetTrackerDialog - Undecorated name, which can be easily used with GetProcAddress
+// Win32 API function.
+// _GetTrackerDialog@0 - Common name decoration for __stdcall functions in C language.
+#pragma comment(linker, "/export:GetTrackerDialog=_GetTrackerDialog@0")
+
+FTNOIR_TRACKER_BASE_EXPORT ITrackerDialogPtr __stdcall GetTrackerDialog( )
+{
+ return new TrackerControls;
+}
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.h b/ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.h
new file mode 100644
index 00000000..c463f361
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat_dialog.h
@@ -0,0 +1,78 @@
+#ifndef FTNOIR_TRACKER_HAT_DIALOG_H
+#define FTNOIR_TRACKER_HAT_DIALOG_H
+
+#include "..\ftnoir_tracker_base\ftnoir_tracker_base.h"
+#include "ftnoir_tracker_hat_settings.h"
+#include "ftnoir_tracker_hat.h"
+#include "ui_ftnoir_hatcontrols.h"
+
+#include <QTimer>
+#include <QMessageBox>
+
+// Widget that has controls for FTNoIR protocol client-settings.
+class TrackerControls: public QWidget, Ui::UIHATControls, public ITrackerDialog
+{
+ Q_OBJECT
+
+public:
+ explicit TrackerControls();
+ virtual ~TrackerControls();
+
+ void Initialize(QWidget *parent);
+ void registerTracker(ITracker *tracker);
+ void unRegisterTracker() ;
+
+private:
+ Ui::UIHATControls ui;
+ int pre_trame;
+ FTNoIR_Tracker *theTracker;
+
+protected slots:
+
+ /*
+ void set_mod_port(int val) { settings.SerialPortName = ui.cbSerialPort->itemText(val);
+ QMessageBox::warning(this,"FaceTrackNoIR Error", settings.SerialPortName);
+ settings_changed(); }
+*/
+ void set_mod_port(const QString & val) { settings.SerialPortName =val;
+ QMessageBox::warning(this,"FaceTrackNoIR Error", settings.SerialPortName);
+ settings_changed(); }
+ void set_ena_roll(bool val) { settings.EnableRoll = val; settings_changed(); }
+ void set_ena_pitch(bool val) { settings.EnablePitch = val; settings_changed(); }
+ void set_ena_yaw(bool val) { settings.EnableYaw = val; settings_changed(); }
+ void set_ena_x(bool val) { settings.EnableX = val; settings_changed(); }
+ void set_ena_y(bool val) { settings.EnableY = val; settings_changed(); }
+ void set_ena_z(bool val) { settings.EnableZ = val; settings_changed(); }
+
+ void set_inv_roll(bool val) { settings.InvertRoll = val; settings_changed(); }
+ void set_inv_pitch(bool val) { settings.InvertPitch = val; settings_changed(); }
+ void set_inv_yaw(bool val) { settings.InvertYaw = val; settings_changed(); }
+ void set_inv_x(bool val) { settings.InvertX = val; settings_changed(); }
+ void set_inv_y(bool val) { settings.InvertY = val; settings_changed(); }
+ void set_inv_z(bool val) { settings.InvertZ = val; settings_changed(); }
+
+
+ void set_rot_roll(int val) { settings.RollAxe = val; settings_changed(); }
+ void set_rot_pitch(int val) { settings.PitchAxe = val; settings_changed(); }
+ void set_rot_yaw(int val) { settings.YawAxe = val; settings_changed(); }
+ void set_acc_x(int val) { settings.XAxe = val; settings_changed(); }
+ void set_acc_y(int val) { settings.YAxe = val; settings_changed(); }
+ void set_acc_z(int val) { settings.ZAxe = val; settings_changed(); }
+
+ void doOK();
+ void doCancel();
+ void doSave();
+ void doReset();
+ void doCenter();
+ void doSend();
+ void poll_tracker_info();
+
+protected:
+ bool settingsDirty;
+ void settings_changed();
+ TrackerSettings settings;
+ QTimer timer;
+};
+
+
+#endif //FTNOIR_TRACKER_HAT_DIALOG_H \ No newline at end of file
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat_dll.cpp b/ftnoir_tracker_hatire/ftnoir_tracker_hat_dll.cpp
new file mode 100644
index 00000000..246eb397
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat_dll.cpp
@@ -0,0 +1,79 @@
+/********************************************************************************
+* FaceTrackNoIR This program is a private project of some enthusiastic *
+* gamers from Holland, who don't like to pay much for *
+* head-tracking. *
+* *
+* Copyright (C) 2012 Wim Vriend (Developing) *
+* Ron Hendriks (Researching and Testing) *
+* *
+* Homepage: http://facetracknoir.sourceforge.net/home/default.htm *
+* *
+* This program 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. *
+* *
+* This program 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 this program; if not, see <http://www.gnu.org/licenses/>. *
+* *
+********************************************************************************/
+
+#include "ftnoir_tracker_hat.h"
+#include <QICon>
+#include <QDebug>
+
+FTNoIR_TrackerDll::FTNoIR_TrackerDll() {
+ //populate the description strings
+ trackerFullName = "Head Arduino Tracker";
+ trackerShortName = "HAT";
+ trackerDescription = "FaceTrackNoIR HAT";
+}
+
+FTNoIR_TrackerDll::~FTNoIR_TrackerDll()
+{
+
+}
+
+void FTNoIR_TrackerDll::Initialize()
+{
+ return;
+}
+
+void FTNoIR_TrackerDll::getFullName(QString *strToBeFilled)
+{
+ *strToBeFilled = trackerFullName;
+};
+
+void FTNoIR_TrackerDll::getShortName(QString *strToBeFilled)
+{
+ *strToBeFilled = trackerShortName;
+};
+
+void FTNoIR_TrackerDll::getDescription(QString *strToBeFilled)
+{
+ *strToBeFilled = trackerDescription;
+};
+
+void FTNoIR_TrackerDll::getIcon(QIcon *icon)
+{
+ *icon = QIcon(":/images/hat.ico");
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Factory function that creates instances if the Tracker object.
+
+// Export both decorated and undecorated names.
+// GetTrackerDll - Undecorated name, which can be easily used with GetProcAddress
+// Win32 API function.
+// _GetTrackerDll@0 - Common name decoration for __stdcall functions in C language.
+#pragma comment(linker, "/export:GetTrackerDll=_GetTrackerDll@0")
+
+FTNOIR_TRACKER_BASE_EXPORT ITrackerDllPtr __stdcall GetTrackerDll()
+{
+ return new FTNoIR_TrackerDll;
+}
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.cpp b/ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.cpp
new file mode 100644
index 00000000..f8b342cc
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.cpp
@@ -0,0 +1,102 @@
+/********************************************************************************
+* FaceTrackNoIR This program is a private project of some enthusiastic *
+* gamers from Holland, who don't like to pay much for *
+* head-tracking. *
+* *
+* Copyright (C) 2012 Wim Vriend (Developing) *
+* Ron Hendriks (Researching and Testing) *
+* *
+* Homepage: http://facetracknoir.sourceforge.net/home/default.htm *
+* *
+* This program 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. *
+* *
+* This program 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 this program; if not, see <http://www.gnu.org/licenses/>. *
+* *
+********************************************************************************/
+#include <QCoreApplication>
+#include <QSettings>
+
+#include "ftnoir_tracker_hat_settings.h"
+
+void TrackerSettings::load_ini()
+{
+ qDebug("TrackerSettings::load_ini()");
+ QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup( "HAT" );
+
+ SerialPortName=iniFile.value ( "PortName" ).toString();
+
+ EnableRoll = iniFile.value( "EnableRoll", 1 ).toBool();
+ EnablePitch = iniFile.value( "EnablePitch", 1 ).toBool();
+ EnableYaw = iniFile.value( "EnableYaw", 1 ).toBool();
+ EnableX = iniFile.value( "EnableX", 0 ).toBool();
+ EnableY = iniFile.value( "EnableY", 0 ).toBool();
+ EnableZ = iniFile.value( "EnableZ", 0 ).toBool();
+
+
+ InvertRoll = iniFile.value( "InvertRoll", 1 ).toBool();
+ InvertPitch = iniFile.value( "InvertPitch", 1 ).toBool();
+ InvertYaw = iniFile.value( "InvertYaw", 1 ).toBool();
+ InvertX = iniFile.value( "InvertX", 0 ).toBool();
+ InvertY = iniFile.value( "InvertY", 0 ).toBool();
+ InvertZ = iniFile.value( "InvertZ", 0 ).toBool();
+
+
+ RollAxe=iniFile.value("RollAxe",1).toInt();
+ PitchAxe=iniFile.value("PitchAxe",2).toInt();
+ YawAxe=iniFile.value("YawAxe",0).toInt();
+ XAxe=iniFile.value("XAxe",1).toInt();
+ YAxe=iniFile.value("YAxe",2).toInt();
+ ZAxe=iniFile.value("ZAxe",0).toInt();
+
+ iniFile.endGroup();
+}
+
+
+void TrackerSettings::save_ini() const
+{
+ qDebug("TrackerSettings::save_ini()");
+
+ QSettings settings("Abbequerque Inc.", "FaceTrackNoIR"); // Registry settings (in HK_USER)
+ QString currentFile = settings.value( "SettingsFile", QCoreApplication::applicationDirPath() + "/Settings/default.ini" ).toString();
+ QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file)
+
+ iniFile.beginGroup ( "HAT" );
+
+ iniFile.setValue ( "PortName",SerialPortName );
+
+ iniFile.setValue( "EnableRoll", EnableRoll );
+ iniFile.setValue( "EnablePitch", EnablePitch );
+ iniFile.setValue( "EnableYaw", EnableYaw );
+ iniFile.setValue( "EnableX", EnableX );
+ iniFile.setValue( "EnableY", EnableY );
+ iniFile.setValue( "EnableZ", EnableZ );
+
+ iniFile.setValue( "InvertRoll", InvertRoll );
+ iniFile.setValue( "InvertPitch", InvertPitch );
+ iniFile.setValue( "InvertYaw", InvertYaw );
+ iniFile.setValue( "InvertX", InvertX );
+ iniFile.setValue( "InvertY", InvertY );
+ iniFile.setValue( "InvertZ", InvertZ );
+
+ iniFile.setValue ( "RollAxe", RollAxe );
+ iniFile.setValue ( "PitchAxe", PitchAxe );
+ iniFile.setValue ( "YawAxe",YawAxe );
+ iniFile.setValue ( "XAxe", XAxe );
+ iniFile.setValue ( "YAxe", YAxe );
+ iniFile.setValue ( "ZAxe", ZAxe );
+
+ iniFile.endGroup();
+}
diff --git a/ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.h b/ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.h
new file mode 100644
index 00000000..a29fed6b
--- /dev/null
+++ b/ftnoir_tracker_hatire/ftnoir_tracker_hat_settings.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2012 Patrick Ruoff
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+#ifndef FTNOIR_TRACKER_HAT_SETTINGS_H
+#define FTNOIR_TRACKER_HAT_SETTINGS_H
+
+
+//-----------------------------------------------------------------------------
+struct TrackerSettings
+{
+
+ QString SerialPortName;
+ bool EnableRoll;
+ bool EnablePitch;
+ bool EnableYaw;
+ bool EnableX;
+ bool EnableY;
+ bool EnableZ;
+
+ bool InvertRoll;
+ bool InvertPitch;
+ bool InvertYaw;
+ bool InvertX;
+ bool InvertY;
+ bool InvertZ;
+
+
+ int RollAxe;
+ int PitchAxe;
+ int YawAxe;
+ int XAxe;
+ int YAxe;
+ int ZAxe;
+
+ void load_ini();
+ void save_ini() const;
+};
+
+
+#endif //FTNOIR_TRACKER_HAT_SETTINGS_H \ No newline at end of file
diff --git a/ftnoir_tracker_hatire/images/hat.ico b/ftnoir_tracker_hatire/images/hat.ico
new file mode 100644
index 00000000..d8f5aac4
--- /dev/null
+++ b/ftnoir_tracker_hatire/images/hat.ico
Binary files differ
diff --git a/ftnoir_tracker_hatire/images/hat_logo.png b/ftnoir_tracker_hatire/images/hat_logo.png
new file mode 100644
index 00000000..c3a92b1b
--- /dev/null
+++ b/ftnoir_tracker_hatire/images/hat_logo.png
Binary files differ