Projekt

Obecné

Profil

Stáhnout (13.1 KB) Statistiky
| Větev: | Tag: | Revize:
1
using System;
2
using System.Net.Sockets;
3
using System.Threading;
4
using System.IO;
5
using System.Linq;
6
using System.Text;
7
using UnityEngine;
8

    
9
namespace DeltaRobotVr
10
{
11
    public readonly struct Single3
12
    {
13
        public float X { get; }
14
        public float Y { get; }
15
        public float Z { get; }
16

    
17
        public Single3(float x, float y, float z)
18
        {
19
            X = x;
20
            Y = y;
21
            Z = z;
22
        }
23

    
24
        public override string ToString() => "Single3[ " + X + " " + Y + " " + Z + " ]";
25
    }
26

    
27
    public sealed class Client
28
    {
29
        // singleton instance
30
        public static readonly Client Instance = new Client();
31

    
32
        // default server
33
        private const string DefaultServer = "127.0.0.1";
34
        private const int DefaultPort = 4242;
35

    
36
        // protocol constants
37
        private const UInt16 ProtocolMagicId = 0x3001;
38
        private const UInt16 ProtocolVersionId = 0x2002;
39
        private const UInt16 PingId = 0x3004;
40
        private const UInt16 PongId = 0x3005;
41
        private const UInt16 EotId = 0xF006;
42
        private const UInt16 CurrentActuatorPositionId = 0x4003;
43
        private const UInt16 CurrentDirectionVectorId = 0x4007;
44
        private const UInt16 DesiredDirectionVectorId = 0x4008;
45
        private const UInt16 CurveId = 0xF009;
46

    
47
        private const UInt16 Size8 = 0x0000;
48
        private const UInt16 Size16 = 0x1000;
49
        private const UInt16 Size32 = 0x2000;
50
        private const UInt16 Size64 = 0x3000;
51
        private const UInt16 Size128 = 0x4000;
52
        private const UInt16 SizeVariable = 0xF000;
53
        
54
        private static readonly byte[] ProtocolMagicValue = Encoding.ASCII.GetBytes("DeltaRVr");
55
        private const UInt32 ProtocolVersionValue = 1;
56

    
57
        private const UInt32 PointLength = 12;
58

    
59
        private const int ReconnectPollMillis = 200;
60
        private const int ReconnectTimeMillis = 3000;
61

    
62
        
63
        private Thread _thread;
64
        
65
        private readonly object _isRunningLock = new object();
66
        private bool _isRunning;
67

    
68
        private readonly object _actuatorPositionLock = new object();
69
        private Single3 _actuatorPosition;
70

    
71
        private readonly object _currentDirectionVectorLock = new object();
72
        private Single3 _currentDirectionVector;
73

    
74
        private readonly object _desiredDirectionVectorLock = new object();
75
        private Single3 _desiredDirectionVector;
76

    
77
        private readonly object _curveLock = new object();
78
        private Single3[] _curve;
79
        private long _curveCounter = 0;
80

    
81
        private volatile bool _isConnected;
82
        private volatile string _eotMsg;
83

    
84
        private readonly object _reconnectTimeLock = new object();
85
        private DateTime _reconnectTime = DateTime.Now;
86

    
87
        static Client()
88
        {
89
        }
90

    
91
        private Client()
92
        {
93
        }
94

    
95
        public void Start()
96
        {
97
            _thread = new Thread(ThreadProcedure);
98
            IsRunning = true;
99
            _thread.Start();
100
        }
101

    
102
        public void Stop()
103
        {
104
            IsRunning = false;
105
            _thread.Join();
106
        }
107

    
108
        public string EotMsg
109
        {
110
            get => _eotMsg;
111
            private set => _eotMsg = value;
112
        }
113

    
114
        public bool IsConnected
115
        {
116
            get => _isConnected;
117
            private set => _isConnected = value;
118
        }
119

    
120
        public Single3 ActuatorPosition
121
        {
122
            get
123
            {
124
                lock (_actuatorPositionLock)
125
                {
126
                    return _actuatorPosition;
127
                }
128
            }
129
            private set
130
            {
131
                lock (_actuatorPositionLock)
132
                {
133
                    _actuatorPosition = value;
134
                }
135
            } 
136
        }
137

    
138
        public Single3 CurrentDirectionVector
139
        {
140
            get
141
            {
142
                lock (_currentDirectionVectorLock)
143
                {
144
                    return _currentDirectionVector;
145
                }
146
            }
147
            private set
148
            {
149
                lock (_currentDirectionVectorLock)
150
                {
151
                    _currentDirectionVector = value;
152
                }
153
            }
154
        }
155

    
156
        public Single3 DesiredDirectionVector
157
        {
158
            get
159
            {
160
                lock (_desiredDirectionVectorLock)
161
                {
162
                    return _desiredDirectionVector;
163
                }
164
            }
165
            private set
166
            {
167
                lock (_desiredDirectionVectorLock)
168
                {
169
                    _desiredDirectionVector = value;
170
                }
171
            }
172
        }
173

    
174
        public Single3[] Curve
175
        {
176
            get
177
            {
178
                lock (_curveLock)
179
                {
180
                    return _curve;
181
                }
182
            }
183
            private set
184
            {
185
                lock (_curveLock)
186
                {
187
                    _curve = value;
188
                }
189
            }
190
        }
191

    
192
        public long CurveCounter
193
        {
194
            get
195
            {
196
                lock (_curveLock)
197
                {
198
                    return _curveCounter;
199
                }
200
            }
201
            private set
202
            {
203
                lock (_curveLock)
204
                {
205
                    _curveCounter = value;
206
                }
207
            }
208
        }
209

    
210
        public bool IsRunning
211
        {
212
            get {
213
                lock (_isRunningLock)
214
                {
215
                    return _isRunning;
216
                }
217
            }
218
            private set
219
            {
220
                lock (_isRunningLock)
221
                {
222
                    _isRunning = value;
223
                }
224
            }
225
        }
226

    
227
        public DateTime ReconnectTime
228
        {
229
            get
230
            {
231
                lock (_reconnectTimeLock)
232
                {
233
                    return _reconnectTime;
234
                }
235
            }
236
            private set
237
            {
238
                lock (_reconnectTimeLock)
239
                {
240
                    _reconnectTime = value;
241
                }
242
            }
243
        }
244

    
245
        private void ThreadProcedure()
246
        {
247
            while (IsRunning)
248
            {
249
                try
250
                {
251
                    using var client = new TcpClient(DefaultServer, DefaultPort);
252
                    using var stream = client.GetStream();
253
                    BinaryReader reader = new BinaryReader(stream);
254
                    BinaryWriter writer = new BinaryWriter(stream);
255
                    IsConnected = true;
256

    
257
                    SendProtocolPreamble(writer);
258

    
259
                    // main message reception loop
260
                    while (IsRunning && IsConnected)
261
                    {
262
                        ReadMessages(reader, writer);
263
                    }
264
                }
265
                catch (Exception e)
266
                {
267
                    if (e is SocketException || e is IOException)
268
                    {
269
                        Debug.LogWarning($"Connection error:\n{e}");
270
                    }
271
                    else
272
                    {
273
                        Debug.LogError($"Exception in communication thread:\n{e}");
274
                    }
275
                }
276
                
277
                // wait before reconnection - short polls to prevent blocking if application is closed
278
                ReconnectTime = DateTime.Now.AddMilliseconds(ReconnectTimeMillis);
279
                while (IsRunning && DateTime.Now < ReconnectTime)
280
                {
281
                    Thread.Sleep(ReconnectPollMillis);
282
                }
283
            }
284
        }
285

    
286

    
287
        private void ReadMessages(BinaryReader reader, BinaryWriter writer)
288
        {
289
            var messageIdentifier = reader.ReadUInt16();
290
            switch (messageIdentifier)
291
            {
292
                case ProtocolMagicId:
293
                    ProcessProtocolMagic(reader);
294
                    break;
295
                case ProtocolVersionId:
296
                    ProcessProtocolVersion(reader);
297
                    break;
298
                case PingId:
299
                    ProcessPing(reader, writer);
300
                    break;
301
                case EotId:
302
                    ProcessEot(reader);
303
                    break;
304
                case CurrentActuatorPositionId:
305
                    ProcessCurrentActuatorPosition(reader);
306
                    break;
307
                case CurrentDirectionVectorId:
308
                    ProcessCurrentDirectionVector(reader);
309
                    break;
310
                case DesiredDirectionVectorId:
311
                    ProcessDesiredDirectionVector(reader);
312
                    break;
313
                case CurveId:
314
                    ProcessCurve(reader);
315
                    break;
316
                default: // unknown message
317
                    var sizeIdentifier = (UInt16) (messageIdentifier & 0xF000);
318
                    switch (sizeIdentifier)
319
                    {
320
                        case Size8:
321
                            Skip8(reader);
322
                            break;
323
                        case Size16:
324
                            Skip16(reader);
325
                            break;
326
                        case Size32:
327
                            Skip32(reader);
328
                            break;
329
                        case Size64:
330
                            Skip64(reader);
331
                            break;
332
                        case Size128:
333
                            Skip128(reader);
334
                            break;
335
                        case SizeVariable:
336
                            SkipVariableLength(reader);
337
                            break;
338
                    }
339

    
340
                    break;
341
            }
342
        }
343

    
344
        private void SendProtocolPreamble(BinaryWriter writer)
345
        {
346
            writer.Write(ProtocolMagicId);
347
            writer.Write(ProtocolMagicValue);
348
            writer.Write(ProtocolVersionId);
349
            writer.Write(ProtocolVersionValue);
350
        }
351

    
352
        private void Skip8(BinaryReader reader)
353
        {
354
            reader.ReadByte();
355
        }
356

    
357
        private void Skip16(BinaryReader reader)
358
        {
359
            reader.ReadUInt16();
360
        }
361

    
362
        private void Skip32(BinaryReader reader)
363
        {
364
            reader.ReadUInt32();
365
        }
366

    
367
        private void Skip64(BinaryReader reader)
368
        {
369
            reader.ReadUInt64();
370
        }
371

    
372
        private void Skip128(BinaryReader reader)
373
        {
374
            reader.ReadUInt64();
375
            reader.ReadUInt64();
376
        }
377

    
378
        private void SkipVariableLength(BinaryReader reader)
379
        {
380
            UInt32 numberOfBytes = reader.ReadUInt32();
381
            reader.ReadBytes((int) numberOfBytes);
382
        }
383

    
384
        private void ProcessCurrentActuatorPosition(BinaryReader reader)
385
        {
386
            var x = reader.ReadSingle();
387
            var y = reader.ReadSingle();
388
            var z = reader.ReadSingle();
389
            reader.ReadSingle(); // skip unused
390

    
391
            ActuatorPosition = new Single3(x, y, z);
392
        }
393

    
394
        private void ProcessCurrentDirectionVector(BinaryReader reader)
395
        {
396
            var x = reader.ReadSingle();
397
            var y = reader.ReadSingle();
398
            var z = reader.ReadSingle();
399
            reader.ReadSingle(); // skip unused
400

    
401
            CurrentDirectionVector = new Single3(x, y, z);
402
        }
403

    
404
        private void ProcessDesiredDirectionVector(BinaryReader reader)
405
        {
406
            var x = reader.ReadSingle();
407
            var y = reader.ReadSingle();
408
            var z = reader.ReadSingle();
409
            reader.ReadSingle(); // skip unused
410

    
411
            DesiredDirectionVector = new Single3(x, y, z);
412
        }
413

    
414
        private void ProcessCurve(BinaryReader reader)
415
        {
416
            UInt32 numberOfBytes = reader.ReadUInt32();
417
            UInt32 numberOfPoints = numberOfBytes / PointLength;
418
            Single3[] curve = new Single3[numberOfPoints];
419

    
420
            for(int i = 0; i < numberOfPoints; i++)
421
            {
422
                var x = reader.ReadSingle();
423
                var y = reader.ReadSingle();
424
                var z = reader.ReadSingle();
425
                curve[i] = new Single3(x, y, z);
426
            }
427

    
428
            lock(_curveLock)
429
            {
430
                CurveCounter++;
431
                Curve = curve;
432
            }
433
        }
434

    
435
        private void ProcessEot(BinaryReader reader)
436
        {
437
            UInt32 numberOfBytes = reader.ReadUInt32();
438
            Byte[] buffer = reader.ReadBytes((int) numberOfBytes);
439
            EotMsg = Encoding.ASCII.GetString(buffer);
440
            IsConnected = false;
441
        }
442

    
443
        private void ProcessProtocolMagic(BinaryReader reader)
444
        {
445
            byte[] value = reader.ReadBytes(8);
446
            if (!value.SequenceEqual(ProtocolMagicValue))
447
            {
448
                IsConnected = false;
449
            }
450
        }
451

    
452
        private void ProcessProtocolVersion(BinaryReader reader)
453
        {
454
            UInt32 value = reader.ReadUInt32();
455
            if (value != ProtocolVersionValue)
456
            {
457
                IsConnected = false;
458
            }
459
        }
460

    
461
        private void ProcessPing(BinaryReader reader, BinaryWriter writer)
462
        {
463
            UInt64 pingValue = reader.ReadUInt64();
464

    
465
            writer.Write(PongId);
466
            writer.Write(pingValue);
467
        }
468
    }
469
}
(3-3/16)