Rumblebutt HOTAS Chair
An old, cheap massage chair hooked up to the throttle of a HOTAS to simulate engine hum while playing in VR...
Components and supplies
1
Wemos D1 Mini
Project description
Code
Wemos D1 mini UDP Server and PWM Controller
c_cpp
It receives UDP packet and controls power to 'rumble pack' via PWM and D4184 Mosfet Module
1#include <ESP8266WiFi.h> 2#include <WiFiUdp.h> 3 4// Set WiFi credentials 5#define WIFI_SSID "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 6#define WIFI_PASS "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 7 8// PWM pin, see pinout for Wemos D1 mini 9const int vibrateAllPin = 4; 10 11uint8_t pwmint[1]; 12 13WiFiUDP Udp; 14unsigned int localUdpPort = 4210; // local port to listen on 15char incomingPacket[32]; // buffer for incoming packets 16 17 18void setup() { 19 20 pinMode(vibrateAllPin, OUTPUT); 21 22 // Set value 0 23 pwmint[0] = 0; 24 25 // Begin WiFi 26 WiFi.begin(WIFI_SSID, WIFI_PASS); 27 28 // Loop continuously while WiFi is not connected 29 while (WiFi.status() != WL_CONNECTED) 30 { 31 delay(100); 32 } 33 34 Udp.begin(localUdpPort); 35 36} 37 38void loop() { 39 40 //Write pwmint[0]*4 to D4/GPIO 2 ( this factor x4 is a PWM range conversion for the Wemos, may differ with other boards 41 analogWrite(vibrateAllPin, pwmint[0]*4); 42 43 int packetSize = Udp.parsePacket(); 44 if (packetSize) 45 { 46 // receive incoming UDP packets 47 int len = Udp.read(incomingPacket, 32); 48 if (len > 0) 49 { 50 incomingPacket[len] = 0; 51 } 52 53 54 if (len > 0 ){ 55 56 pwmint[0]= atoi(incomingPacket); 57 58 Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); 59 Udp.write(replyPacket); 60 Udp.endPacket(); 61 62 }else{ 63 64 Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); 65 Udp.write(replyPacketError); 66 Udp.endPacket(); 67 } 68 69 } 70 71 delay(200); 72}
Rumblebutt Raw Input to UDP
c_cpp
Grabs throttle axis of my HOTAS and does some conversion, then sends it via UDP
1/////////////////////////////////////////////////////////////////////////////// 2// 3// Rumblebutt Raw Input to UDP 4// 5/////////////////////////////////////////////////////////////////////////////// 6 7// Attention, including winsock2 and Windows does clash, to prevent that, define _WINSOCKAPI_ like this first: 8#define _WINSOCKAPI_ 9 10#include <Windows.h> 11#include <tchar.h> 12#include <math.h> 13#include <hidsdi.h> 14#include <stdio.h> 15#include <winsock2.h> 16 17 18#pragma comment(lib,"ws2_32.lib") //Winsock Library 19 20#define _USE_MATH_DEFINES 21#define SERVER "xxx.xxx.xxx.xxx" //ip address of udp server 22#define BUFLEN 512 //Max length of buffer 23#define PORT 4210 //The port on which to listen for incoming data 24 25#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 26#define WC_MAINFRAME TEXT("MainFrame") 27#define CHECK(exp) { if(!(exp)) goto Error; } 28#define SAFE_FREE(p) { if(p) { HeapFree(hHeap, 0, p); (p) = NULL; } } 29 30// 31// Global variables 32// 33 34LONG lAxisX; 35LONG lAxisY; 36LONG lAxisZ; 37LONG lAxisRz; 38LONG lHat; 39INT g_NumberOfButtons; 40 41 42//Prototyp winsock 43int startWinsock(void); 44 45void ParseRawInput(PRAWINPUT pRawInput) 46{ 47 PHIDP_PREPARSED_DATA pPreparsedData; 48 HIDP_CAPS Caps; 49 PHIDP_BUTTON_CAPS pButtonCaps; 50 PHIDP_VALUE_CAPS pValueCaps; 51 USHORT capsLength; 52 UINT bufferSize=0; 53 HANDLE hHeap; 54 ULONG value; 55 56 pPreparsedData = NULL; 57 pButtonCaps = NULL; 58 pValueCaps = NULL; 59 hHeap = GetProcessHeap(); 60 61 // 62 // Get the preparsed data block 63 // 64 65 CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 ); 66 CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(hHeap, 0, bufferSize) ); 67 CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 ); 68 69 // 70 // Get the joystick's capabilities 71 // 72 73 CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS ) 74 75 g_NumberOfButtons = 0; 76 77 // Value caps 78 CHECK( pValueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) ); 79 capsLength = Caps.NumberInputValueCaps; 80 CHECK(HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS) 81 82 83 // 84 // Get the state of discrete-valued-controls 85 // 86 87 88 for(int i = 0; i < Caps.NumberInputValueCaps; i++) 89 { 90 CHECK( 91 HidP_GetUsageValue( 92 HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData, 93 (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid 94 ) == HIDP_STATUS_SUCCESS ); 95 96 switch(pValueCaps[i].Range.UsageMin) 97 { 98 case 0x30: // X-axis 99 lAxisX = (LONG)value - 128; 100 break; 101 102 case 0x31: // Y-axis 103 lAxisY = (LONG)value - 128; 104 break; 105 106 case 0x32: // Z-axis 107 lAxisZ = (LONG)value - 128; 108 break; 109 110 case 0x35: // Rotate-Z 111 lAxisRz = (LONG)value - 128; 112 break; 113 114 case 0x39: // Hat Switch 115 lHat = value; 116 break; 117 } 118 } 119 120 // 121 // Clean up 122 // 123 124Error: 125 SAFE_FREE(pPreparsedData); 126 SAFE_FREE(pButtonCaps); 127 SAFE_FREE(pValueCaps); 128} 129 130 131void DrawCrosshair(HDC hDC, int x, int y, LONG xVal, LONG yVal) 132{ 133 Rectangle(hDC, x, y, x + 256, y + 256); 134 MoveToEx(hDC, x + xVal - 5 + 128, y + yVal + 128, NULL); 135 LineTo(hDC, x + xVal + 5 + 128, y + yVal + 128); 136 MoveToEx(hDC, x + xVal + 128, y + yVal - 5 + 128, NULL); 137 LineTo(hDC, x + xVal + 128, y + yVal + 5 + 128); 138} 139 140 141LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 142{ 143 switch(msg) 144 { 145 case WM_CREATE: 146 { 147 // 148 // Register for joystick devices 149 // 150 151 RAWINPUTDEVICE rid; 152 153 rid.usUsagePage = 1; 154 rid.usUsage = 4; // Joystick 155 156 // RIDEV_INPUTSINK is needed to let this program receive input even if not in foreground/focused 157 rid.dwFlags = RIDEV_INPUTSINK; 158 159 rid.hwndTarget = hWnd; 160 161 if(!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) 162 return -1; 163 } 164 return 0; 165 166 case WM_INPUT: 167 { 168 // 169 // Get the pointer to the raw device data, process it and update the window 170 // 171 172 PRAWINPUT pRawInput; 173 UINT bufferSize=0; 174 HANDLE hHeap; 175 176 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER)); 177 178 hHeap = GetProcessHeap(); 179 pRawInput = (PRAWINPUT)HeapAlloc(hHeap, 0, bufferSize); 180 if(!pRawInput) 181 return 0; 182 183 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER)); 184 ParseRawInput(pRawInput); 185 186 HeapFree(hHeap, 0, pRawInput); 187 188 InvalidateRect(hWnd, NULL, TRUE); 189 UpdateWindow(hWnd); 190 } 191 return 0; 192 193 case WM_PAINT: 194 { 195 // 196 // Draw the buttons and axis-values 197 // 198 199 PAINTSTRUCT ps; 200 HDC hDC; 201 202 hDC = BeginPaint(hWnd, &ps); 203 SetBkMode(hDC, TRANSPARENT); 204 205 DrawCrosshair(hDC, 50, 50, lAxisZ, 0); 206 TCHAR text[256]; 207 swprintf_s(text, 256, L"Throttle: %d", lAxisZ); 208 TextOut(hDC, 10, 10, text, wcslen(text)); 209 210 EndPaint(hWnd, &ps); 211 } 212 return 0; 213 214 case WM_DESTROY: 215 PostQuitMessage(0); 216 return 0; 217 } 218 219 return DefWindowProc(hWnd, msg, wParam, lParam); 220} 221 222 223int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) 224{ 225 HWND hWnd; 226 MSG msg; 227 WNDCLASSEX wcex; 228 229 struct sockaddr_in si_other; 230 int s, slen = sizeof(si_other); 231 char buf[BUFLEN]; 232 char message[BUFLEN]; 233 WSADATA wsa; 234 235 //Initialise winsock 236 237 if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) 238 { 239 exit(EXIT_FAILURE); 240 } 241 242 243 //create socket 244 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR) 245 { 246 exit(EXIT_FAILURE); 247 } 248 249 //setup address structure 250 memset((char*)&si_other, 0, sizeof(si_other)); 251 si_other.sin_family = AF_INET; 252 si_other.sin_port = htons(PORT); 253 si_other.sin_addr.S_un.S_addr = inet_addr(SERVER); 254 255 // 256 // Register window class 257 // 258 259 wcex.cbSize = sizeof(WNDCLASSEX); 260 wcex.cbClsExtra = 0; 261 wcex.cbWndExtra = 0; 262 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 263 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 264 wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); 265 wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 266 wcex.hInstance = hInstance; 267 wcex.lpfnWndProc = WindowProc; 268 wcex.lpszClassName = WC_MAINFRAME; 269 wcex.lpszMenuName = NULL; 270 wcex.style = CS_HREDRAW | CS_VREDRAW; 271 272 if(!RegisterClassEx(&wcex)) 273 return -1; 274 275 // 276 // Create window 277 // 278 279 hWnd = CreateWindow(WC_MAINFRAME, TEXT("Rumblebutt Raw Input to UDP"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInstance, NULL); 280 ShowWindow(hWnd, nShowCmd); 281 UpdateWindow(hWnd); 282 283 // 284 // Message loop 285 // 286 287 while(GetMessage(&msg, NULL, 0, 0)) 288 { 289 TranslateMessage(&msg); 290 DispatchMessage(&msg); 291 292 int sendThrottle; 293 294 // The values -127 to 127 are divided into 4 cases 295 // Use this if throttle has backward gear, stop, and forward 296 if (lAxisZ > 84) { 297 // Backwards 298 sendThrottle = 20 + (lAxisZ - 84)*2; 299 } 300 else if (lAxisZ > 74) { 301 // No thrust, no rumble 302 // Close to full stop send nothing to eliminate high pitched sound from chair 303 sendThrottle = 0; 304 } 305 else if (lAxisZ > 0) { 306 // Forward positiv 307 sendThrottle = 75 - lAxisZ; 308 } 309 else { 310 // Forward negativ 311 sendThrottle = 75 + (lAxisZ*-1); 312 } 313 314 /* Use this if throttle in game is only forward or you can shift 315 if (lAxisZ > 0) { 316 // Backwards 42 Values 317 sendThrottle = 128 - lAxisZ; 318 319 // Close to full stop send nothing to eliminate high pitched sound from chair 320 if (sendThrottle < 10) sendThrottle = 0; 321 322 } 323 else { 324 // Forward negativ 325 sendThrottle = 126 + (lAxisZ * -1); 326 } 327 */ 328 329 //Send via UDP 330 char udpsend[4]; 331 sprintf_s(udpsend, sizeof(udpsend), "%d", sendThrottle); 332 sendto(s, udpsend, strlen(udpsend), 0, (struct sockaddr*)&si_other, slen); 333 334 335 } 336 337 closesocket(s); 338 WSACleanup(); 339 340 return (int)msg.wParam; 341} 342 343int startWinsock(void) 344{ 345 WSADATA wsa; 346 return WSAStartup(MAKEWORD(2, 0), &wsa); 347}
Rumblebutt Raw Input to UDP
c_cpp
Grabs throttle axis of my HOTAS and does some conversion, then sends it via UDP
1/////////////////////////////////////////////////////////////////////////////// 2// 3// Rumblebutt Raw Input to UDP 4// 5/////////////////////////////////////////////////////////////////////////////// 6 7// Attention, including winsock2 and Windows does clash, to prevent that, define _WINSOCKAPI_ like this first: 8#define _WINSOCKAPI_ 9 10#include <Windows.h> 11#include <tchar.h> 12#include <math.h> 13#include <hidsdi.h> 14#include <stdio.h> 15#include <winsock2.h> 16 17 18#pragma comment(lib,"ws2_32.lib") //Winsock Library 19 20#define _USE_MATH_DEFINES 21#define SERVER "xxx.xxx.xxx.xxx" //ip address of udp server 22#define BUFLEN 512 //Max length of buffer 23#define PORT 4210 //The port on which to listen for incoming data 24 25#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 26#define WC_MAINFRAME TEXT("MainFrame") 27#define CHECK(exp) { if(!(exp)) goto Error; } 28#define SAFE_FREE(p) { if(p) { HeapFree(hHeap, 0, p); (p) = NULL; } } 29 30// 31// Global variables 32// 33 34LONG lAxisX; 35LONG lAxisY; 36LONG lAxisZ; 37LONG lAxisRz; 38LONG lHat; 39INT g_NumberOfButtons; 40 41 42//Prototyp winsock 43int startWinsock(void); 44 45void ParseRawInput(PRAWINPUT pRawInput) 46{ 47 PHIDP_PREPARSED_DATA pPreparsedData; 48 HIDP_CAPS Caps; 49 PHIDP_BUTTON_CAPS pButtonCaps; 50 PHIDP_VALUE_CAPS pValueCaps; 51 USHORT capsLength; 52 UINT bufferSize=0; 53 HANDLE hHeap; 54 ULONG value; 55 56 pPreparsedData = NULL; 57 pButtonCaps = NULL; 58 pValueCaps = NULL; 59 hHeap = GetProcessHeap(); 60 61 // 62 // Get the preparsed data block 63 // 64 65 CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 ); 66 CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(hHeap, 0, bufferSize) ); 67 CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 ); 68 69 // 70 // Get the joystick's capabilities 71 // 72 73 CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS ) 74 75 g_NumberOfButtons = 0; 76 77 // Value caps 78 CHECK( pValueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) ); 79 capsLength = Caps.NumberInputValueCaps; 80 CHECK(HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS) 81 82 83 // 84 // Get the state of discrete-valued-controls 85 // 86 87 88 for(int i = 0; i < Caps.NumberInputValueCaps; i++) 89 { 90 CHECK( 91 HidP_GetUsageValue( 92 HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData, 93 (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid 94 ) == HIDP_STATUS_SUCCESS ); 95 96 switch(pValueCaps[i].Range.UsageMin) 97 { 98 case 0x30: // X-axis 99 lAxisX = (LONG)value - 128; 100 break; 101 102 case 0x31: // Y-axis 103 lAxisY = (LONG)value - 128; 104 break; 105 106 case 0x32: // Z-axis 107 lAxisZ = (LONG)value - 128; 108 break; 109 110 case 0x35: // Rotate-Z 111 lAxisRz = (LONG)value - 128; 112 break; 113 114 case 0x39: // Hat Switch 115 lHat = value; 116 break; 117 } 118 } 119 120 // 121 // Clean up 122 // 123 124Error: 125 SAFE_FREE(pPreparsedData); 126 SAFE_FREE(pButtonCaps); 127 SAFE_FREE(pValueCaps); 128} 129 130 131void DrawCrosshair(HDC hDC, int x, int y, LONG xVal, LONG yVal) 132{ 133 Rectangle(hDC, x, y, x + 256, y + 256); 134 MoveToEx(hDC, x + xVal - 5 + 128, y + yVal + 128, NULL); 135 LineTo(hDC, x + xVal + 5 + 128, y + yVal + 128); 136 MoveToEx(hDC, x + xVal + 128, y + yVal - 5 + 128, NULL); 137 LineTo(hDC, x + xVal + 128, y + yVal + 5 + 128); 138} 139 140 141LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 142{ 143 switch(msg) 144 { 145 case WM_CREATE: 146 { 147 // 148 // Register for joystick devices 149 // 150 151 RAWINPUTDEVICE rid; 152 153 rid.usUsagePage = 1; 154 rid.usUsage = 4; // Joystick 155 156 // RIDEV_INPUTSINK is needed to let this program receive input even if not in foreground/focused 157 rid.dwFlags = RIDEV_INPUTSINK; 158 159 rid.hwndTarget = hWnd; 160 161 if(!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) 162 return -1; 163 } 164 return 0; 165 166 case WM_INPUT: 167 { 168 // 169 // Get the pointer to the raw device data, process it and update the window 170 // 171 172 PRAWINPUT pRawInput; 173 UINT bufferSize=0; 174 HANDLE hHeap; 175 176 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER)); 177 178 hHeap = GetProcessHeap(); 179 pRawInput = (PRAWINPUT)HeapAlloc(hHeap, 0, bufferSize); 180 if(!pRawInput) 181 return 0; 182 183 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER)); 184 ParseRawInput(pRawInput); 185 186 HeapFree(hHeap, 0, pRawInput); 187 188 InvalidateRect(hWnd, NULL, TRUE); 189 UpdateWindow(hWnd); 190 } 191 return 0; 192 193 case WM_PAINT: 194 { 195 // 196 // Draw the buttons and axis-values 197 // 198 199 PAINTSTRUCT ps; 200 HDC hDC; 201 202 hDC = BeginPaint(hWnd, &ps); 203 SetBkMode(hDC, TRANSPARENT); 204 205 DrawCrosshair(hDC, 50, 50, lAxisZ, 0); 206 TCHAR text[256]; 207 swprintf_s(text, 256, L"Throttle: %d", lAxisZ); 208 TextOut(hDC, 10, 10, text, wcslen(text)); 209 210 EndPaint(hWnd, &ps); 211 } 212 return 0; 213 214 case WM_DESTROY: 215 PostQuitMessage(0); 216 return 0; 217 } 218 219 return DefWindowProc(hWnd, msg, wParam, lParam); 220} 221 222 223int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) 224{ 225 HWND hWnd; 226 MSG msg; 227 WNDCLASSEX wcex; 228 229 struct sockaddr_in si_other; 230 int s, slen = sizeof(si_other); 231 char buf[BUFLEN]; 232 char message[BUFLEN]; 233 WSADATA wsa; 234 235 //Initialise winsock 236 237 if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) 238 { 239 exit(EXIT_FAILURE); 240 } 241 242 243 //create socket 244 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR) 245 { 246 exit(EXIT_FAILURE); 247 } 248 249 //setup address structure 250 memset((char*)&si_other, 0, sizeof(si_other)); 251 si_other.sin_family = AF_INET; 252 si_other.sin_port = htons(PORT); 253 si_other.sin_addr.S_un.S_addr = inet_addr(SERVER); 254 255 // 256 // Register window class 257 // 258 259 wcex.cbSize = sizeof(WNDCLASSEX); 260 wcex.cbClsExtra = 0; 261 wcex.cbWndExtra = 0; 262 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 263 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 264 wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); 265 wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 266 wcex.hInstance = hInstance; 267 wcex.lpfnWndProc = WindowProc; 268 wcex.lpszClassName = WC_MAINFRAME; 269 wcex.lpszMenuName = NULL; 270 wcex.style = CS_HREDRAW | CS_VREDRAW; 271 272 if(!RegisterClassEx(&wcex)) 273 return -1; 274 275 // 276 // Create window 277 // 278 279 hWnd = CreateWindow(WC_MAINFRAME, TEXT("Rumblebutt Raw Input to UDP"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInstance, NULL); 280 ShowWindow(hWnd, nShowCmd); 281 UpdateWindow(hWnd); 282 283 // 284 // Message loop 285 // 286 287 while(GetMessage(&msg, NULL, 0, 0)) 288 { 289 TranslateMessage(&msg); 290 DispatchMessage(&msg); 291 292 int sendThrottle; 293 294 // The values -127 to 127 are divided into 4 cases 295 // Use this if throttle has backward gear, stop, and forward 296 if (lAxisZ > 84) { 297 // Backwards 298 sendThrottle = 20 + (lAxisZ - 84)*2; 299 } 300 else if (lAxisZ > 74) { 301 // No thrust, no rumble 302 // Close to full stop send nothing to eliminate high pitched sound from chair 303 sendThrottle = 0; 304 } 305 else if (lAxisZ > 0) { 306 // Forward positiv 307 sendThrottle = 75 - lAxisZ; 308 } 309 else { 310 // Forward negativ 311 sendThrottle = 75 + (lAxisZ*-1); 312 } 313 314 /* Use this if throttle in game is only forward or you can shift 315 if (lAxisZ > 0) { 316 // Backwards 42 Values 317 sendThrottle = 128 - lAxisZ; 318 319 // Close to full stop send nothing to eliminate high pitched sound from chair 320 if (sendThrottle < 10) sendThrottle = 0; 321 322 } 323 else { 324 // Forward negativ 325 sendThrottle = 126 + (lAxisZ * -1); 326 } 327 */ 328 329 //Send via UDP 330 char udpsend[4]; 331 sprintf_s(udpsend, sizeof(udpsend), "%d", sendThrottle); 332 sendto(s, udpsend, strlen(udpsend), 0, (struct sockaddr*)&si_other, slen); 333 334 335 } 336 337 closesocket(s); 338 WSACleanup(); 339 340 return (int)msg.wParam; 341} 342 343int startWinsock(void) 344{ 345 WSADATA wsa; 346 return WSAStartup(MAKEWORD(2, 0), &wsa); 347}
Comments
Only logged in users can leave comments