summaryrefslogtreecommitdiffhomepage
path: root/proto-fsuipc/ftnoir_protocol_fsuipc.cpp
blob: 4db85ac530231f514801f0ee7f97ac4c5aee0f05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* Homepage         http://facetracknoir.sourceforge.net/home/default.htm        *
 *                                                                               *
 * ISC License (ISC)                                                             *
 *                                                                               *
 * Copyright (c) 2015, Wim Vriend                                                *
 *                                                                               *
 * 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.             *
 */
#include "ftnoir_protocol_fsuipc.h"
#include "api/plugin-api.hpp"

#include <cmath>

fsuipc::fsuipc()
{
    prevPosX = 0.0f;
    prevPosY = 0.0f;
    prevPosZ = 0.0f;
    prevRotX = 0.0f;
    prevRotY = 0.0f;
    prevRotZ = 0.0f;
}

fsuipc::~fsuipc()
{
    FSUIPC_Close();
    FSUIPCLib.unload();
}

template<typename t>
int fsuipc::scale2AnalogLimits(t x, t min_x, t max_x)
{
    t local_x = x;

    if (local_x > max_x)
    {
        local_x = max_x;
    }
    if (local_x < min_x)
    {
        local_x = min_x;
    }

    t y = (16383 * local_x) / max_x;

    return (int) y;
}

template<typename t>
static inline bool check_float_fresh(t x, t y)
{
    constexpr t eps = t(1e-4);
    return std::fabs(x - y) >= eps;
}

void fsuipc::pose(const double *headpose ) {
    DWORD result;
    TFSState pitch;
    TFSState yaw;
    TFSState roll;
    WORD FSZoom;

    double virtPosX;
    double virtPosY;
    double virtPosZ;

    double virtRotX;
    double virtRotY;
    double virtRotZ;

    //	qDebug() << "FSUIPCServer::run() says: started!";

    virtRotX = -headpose[Pitch];				// degrees
    virtRotY = headpose[Yaw];
    virtRotZ = headpose[Roll];

    virtPosX = 0.0f;											// cm, X and Y are not working for FS2002/2004!
    virtPosY = 0.0f;
    virtPosZ = headpose[TZ];

    //
    // Init. the FSUIPC offsets (derived from Free-track...)
    //
    pitch.Control = 66503;
    yaw.Control = 66504;
    roll.Control = 66505;

    //
    // Only do this when the data has changed. This way, the HAT-switch can be used when tracking is OFF.
    //
    if (check_float_fresh(prevRotX, virtRotX) ||
        check_float_fresh(prevRotY, virtRotY) ||
        check_float_fresh(prevRotZ, virtRotZ) ||
        check_float_fresh(prevPosX, virtPosX) ||
        check_float_fresh(prevPosY, virtPosY) ||
        check_float_fresh(prevPosZ, virtPosZ))
    {
        //
        // Open the connection
        //
        FSUIPC_Open(SIM_ANY, &result);

        //
        // Check the FS-version
        //
        if  (((result == FSUIPC_ERR_OK) || (result == FSUIPC_ERR_OPEN)) &&
             ((FSUIPC_FS_Version == SIM_FS2K2) || (FSUIPC_FS_Version == SIM_FS2K4)))
        {
            // Write the 4! DOF-data to FS. Only rotations and zoom are possible.

            pitch.Value = scale2AnalogLimits(virtRotX, -180., 180.);
            FSUIPC_Write(0x3110, 8, &pitch, &result);

            yaw.Value = scale2AnalogLimits(virtRotY, -180., 180.);
            FSUIPC_Write(0x3110, 8, &yaw, &result);

            roll.Value = scale2AnalogLimits(virtRotZ, -180., 180.);
            FSUIPC_Write(0x3110, 8, &roll, &result);

            FSZoom = WORD(virtPosZ + 64);
            FSUIPC_Write(0x832E, 2, &FSZoom, &result);

            //
            // Write the data, in one go!
            //
            FSUIPC_Process(&result);
            if (result == FSUIPC_ERR_SENDMSG)
            {
                // FSUIPC checks for already open connections and returns FSUIPC_ERR_OPEN in that case
                // the connection scope is global for the process. this is why above code doesn't
                // leak resources or have logic errors. see: http://www.purebasic.fr/english/viewtopic.php?t=31112
                FSUIPC_Close();
            }
        }
    }

    prevPosX = virtPosX;
    prevPosY = virtPosY;
    prevPosZ = virtPosZ;
    prevRotX = virtRotX;
    prevRotY = virtRotY;
    prevRotZ = virtRotZ;
}

module_status fsuipc::initialize()
{
    FSUIPCLib.setFileName( s.LocationOfDLL );
    FSUIPCLib.setLoadHints(QLibrary::PreventUnloadHint);

    if (FSUIPCLib.load() != true)
        return error(tr("Can't load fsuipc at '%1'").arg(s.LocationOfDLL));
    else
        return status_ok();
}

OPENTRACK_DECLARE_PROTOCOL(fsuipc, FSUIPCControls, fsuipcDll)