1 /*
2 	DS5_Output.h is part of DualSenseWindows
3 	https://github.com/Ohjurot/DualSense-Windows
4 
5 	Contributors of this file:
6 	11.2020 Ludwig Füchsl
7 
8 	Licensed under the MIT License (To be found in repository root directory)
9 */
10 module ds5w.ds5output;
11 
12 import ds5w.dswapi;
13 import ds5w.device;
14 import ds5w.ds5state;
15 
16 import std.algorithm;
17 
18 void createHidOutputBuffer(ubyte* hidOutBuffer, DS5OutputState* ptrOutputState)
19 {
20     // Feature mask
21     hidOutBuffer[0x00] = 0xFF;
22     hidOutBuffer[0x01] = 0xF7;
23 
24     // Rumbel motors
25     hidOutBuffer[0x02] = ptrOutputState.rightRumble;
26     hidOutBuffer[0x03] = ptrOutputState.leftRumble;
27 
28     // Mic led
29     hidOutBuffer[0x08] = cast(ubyte) ptrOutputState.microphoneLed;
30 
31     // Player led
32     hidOutBuffer[0x2B] = ptrOutputState.playerLeds.bitmask;
33     if (ptrOutputState.playerLeds.playerLedFade)
34     {
35         hidOutBuffer[0x2B] &= ~(0x20);
36     }
37     else
38     {
39         hidOutBuffer[0x2B] |= 0x20;
40     }
41 
42     // Player led brightness
43     hidOutBuffer[0x26] = 0x03;
44     hidOutBuffer[0x29] = ptrOutputState.disableLeds ? 0x01 : 0x2;
45     hidOutBuffer[0x2A] = ptrOutputState.playerLeds.brightness;
46 
47     // Lightbar
48     hidOutBuffer[0x2C] = ptrOutputState.lightbar.r;
49     hidOutBuffer[0x2D] = ptrOutputState.lightbar.g;
50     hidOutBuffer[0x2E] = ptrOutputState.lightbar.b;
51 
52     // Adaptive Triggers
53     processTrigger(&ptrOutputState.leftTriggerEffect, &hidOutBuffer[0x15]);
54     processTrigger(&ptrOutputState.rightTriggerEffect, &hidOutBuffer[0x0A]);
55 }
56 
57 void processTrigger(TriggerEffect* ptrEffect, ubyte* buffer)
58 {
59     // Switch on effect
60     switch (ptrEffect.effectType)
61     {
62         // Continious
63     case TriggerEffectType.ContinuousResitance:
64         // Mode
65         buffer[0x00] = 0x01;
66         // Parameters
67         buffer[0x01] = ptrEffect.Continuous.startPosition;
68         buffer[0x02] = ptrEffect.Continuous.force;
69 
70         break;
71 
72         // Section
73     case TriggerEffectType.SectionResitance:
74         // Mode
75         buffer[0x00] = 0x02;
76         // Parameters
77         buffer[0x01] = ptrEffect.Continuous.startPosition;
78         buffer[0x02] = ptrEffect.Continuous.force;
79 
80         break;
81 
82         // EffectEx
83     case TriggerEffectType.EffectEx:
84         // Mode
85         buffer[0x00] = 0x02 | 0x20 | 0x04;
86         // Parameters
87         buffer[0x01] = 0xFF - ptrEffect.EffectEx.startPosition;
88         // Keep flag
89         if (ptrEffect.EffectEx.keepEffect)
90         {
91             buffer[0x02] = 0x02;
92         }
93         // Forces
94         buffer[0x04] = ptrEffect.EffectEx.beginForce;
95         buffer[0x05] = ptrEffect.EffectEx.middleForce;
96         buffer[0x06] = ptrEffect.EffectEx.endForce;
97         // Frequency
98         buffer[0x09] = max(ubyte(1), cast(ubyte)(ptrEffect.EffectEx.frequency / 2));
99 
100         break;
101 
102         // Calibrate
103     case TriggerEffectType.Calibrate:
104         // Mode 
105         buffer[0x00] = 0xFC;
106 
107         break;
108 
109         // No resistance / default
110     case TriggerEffectType.NoResitance:
111     default: // All zero
112         buffer[0x00] = 0x00;
113         buffer[0x01] = 0x00;
114         buffer[0x02] = 0x00;
115 
116         break;
117     }
118 }