Skip to content

Commit bd325d8

Browse files
committed
chuni-io: v1.0. led support, more ir sensors.
1 parent 99e1105 commit bd325d8

File tree

9 files changed

+344
-95
lines changed

9 files changed

+344
-95
lines changed

ChuniVController/ChuniIO/chuniio.cc

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ static HANDLE chuni_io_slider_thread;
2020
static bool chuni_io_slider_stop_flag;
2121
static SOCKET chuni_socket;
2222
static USHORT chuni_port = 24864; // CHUNI on dialpad
23+
static struct sockaddr_in remote;
24+
static bool remote_exist = false;
2325

2426
HRESULT chuni_io_jvs_init(void)
2527
{
@@ -139,11 +141,29 @@ void chuni_io_slider_stop(void)
139141

140142
void chuni_io_slider_set_leds(const uint8_t* rgb)
141143
{
142-
static uint8_t prev_rgb_status[32];
143-
144-
for (uint8_t i = 0; i < 32; i++) {
145-
if (rgb[i] != prev_rgb_status[i]) log_debug("SET_LED[%d]: %d\n", i, rgb[i]);
144+
static uint8_t prev_rgb_status[96];
145+
static chuni_msg_t message;
146+
message.src = SRC_GAME;
147+
message.type = LED_SET;
148+
149+
// ignore odd, since no 1/32 color strip exist.
150+
for (uint8_t i = 0; i < 96; i += 6) {
151+
if (rgb[i] != prev_rgb_status[i] || rgb[i + 1] != prev_rgb_status[i + 1] || rgb[i + 2] != prev_rgb_status[i + 2]) {
152+
uint8_t n = i / 6;
153+
log_debug("SET_LED[%d]: rgb(%d, %d, %d)\n", n, rgb[i + 1], rgb[i + 2], rgb[i]);
154+
if (!remote_exist) log_warn("remote does not exist.\n");
155+
else {
156+
message.target = n;
157+
message.led_color_r = rgb[i + 1];
158+
message.led_color_g = rgb[i + 2];
159+
message.led_color_b = rgb[i];
160+
sendto(chuni_socket, (const char*)&message, sizeof(chuni_msg_t), 0, (const sockaddr*)&remote, sizeof(struct sockaddr_in));
161+
}
162+
}
163+
146164
prev_rgb_status[i] = rgb[i];
165+
prev_rgb_status[i + 1] = rgb[i + 1];
166+
prev_rgb_status[i + 2] = rgb[i + 2];
147167
}
148168
}
149169

@@ -159,7 +179,10 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void* ctx)
159179
callback = (chuni_io_slider_callback_t) ctx;
160180

161181
while (!chuni_io_slider_stop_flag) {
162-
int len = recv(chuni_socket, recv_buf, 32, 0); // FIXME: discard pending data on proc start
182+
int addr_sz = sizeof(struct sockaddr_in);
183+
// FIXME: discard pending data on proc start?
184+
int len = recvfrom(chuni_socket, recv_buf, 32, 0, (sockaddr*)&remote, &addr_sz);
185+
remote_exist = true;
163186
if (len == (int) sizeof(chuni_msg_t)) {
164187
const chuni_msg_t* msg = (const chuni_msg_t*)recv_buf;
165188
if (msg->src != SRC_CONTROLLER) {
@@ -169,27 +192,40 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void* ctx)
169192
}
170193
switch (msg->type) {
171194
case COIN_INSERT:
195+
log_debug("adding coin.\n");
172196
chuni_coin_pending = true;
173197
break;
174198
case SLIDER_PRESS:
175-
if (msg->target >= 32) log_error("invalid slider value %d in SLIDER_PRESS.\n", msg->target);
176-
else pressure[msg->target] = 128;
199+
log_debug("slider_press at %d.\n", msg->target);
200+
if (msg->target >= 16) log_error("invalid slider value %d in SLIDER_PRESS.\n", msg->target);
201+
else {
202+
pressure[(msg->target) * 2] = 128;
203+
pressure[(msg->target) * 2 + 1] = 128;
204+
}
177205
break;
178206
case SLIDER_RELEASE:
179-
if (msg->target >= 32) log_error("invalid slider value %d in SLIDER_RELEASE.\n", msg->target);
180-
else pressure[msg->target] = 0;
207+
log_debug("slider released on %d.\n", msg->target);
208+
if (msg->target >= 16) log_error("invalid slider value %d in SLIDER_RELEASE.\n", msg->target);
209+
else {
210+
pressure[(msg->target) * 2] = 0;
211+
pressure[(msg->target) * 2 + 1] = 0;
212+
}
181213
break;
182214
case CABINET_TEST:
215+
log_debug("setting cabinet_test.\n");
183216
chuni_test_pending = true;
184217
break;
185218
case CABINET_SERVICE:
219+
log_debug("setting cabinet_service.\n");
186220
chuni_service_pending = true;
187221
break;
188222
case IR_BLOCKED:
223+
log_debug("ir %d blokced.\n", msg->target);
189224
if (msg->target >= 6) log_error("invalid slider value %d in IR_BLOCKED.\n", msg->target);
190225
else chuni_ir_sensor_map |= 1 << msg->target;
191226
break;
192227
case IR_UNBLOCKED:
228+
log_debug("ir %d unblokced.\n", msg->target);
193229
if (msg->target >= 6) log_error("invalid slider value %d in IR_UNBLOCKED.\n", msg->target);
194230
else chuni_ir_sensor_map &= ~(1 << msg->target);
195231
break;

ChuniVController/ChuniIO/chuniio.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
#endif
88

99
typedef enum {
10-
SRC_GAME,
11-
SRC_CONTROLLER
10+
SRC_GAME = 0 ,
11+
SRC_CONTROLLER = 1
1212
} chuni_msg_src_t;
1313

1414
typedef enum {
@@ -23,14 +23,16 @@ typedef enum {
2323
} chuni_msg_type_t;
2424

2525
typedef struct {
26-
chuni_msg_src_t src;
27-
chuni_msg_type_t type;
26+
uint8_t src;
27+
uint8_t type;
2828

2929
// For SLIDER_*, IR_* and LED_SET. Index of the target SLIDER/LED/IR_SENSOR
3030
uint8_t target;
3131

3232
// for LED_SET only
33-
uint32_t led_color;
33+
uint8_t led_color_r;
34+
uint8_t led_color_g;
35+
uint8_t led_color_b;
3436
} chuni_msg_t;
3537

3638
typedef void (*chuni_io_slider_callback_t)(const uint8_t* state);

ChuniVController/ChuniVController/App.xaml.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Net.Security;
6+
using System.Net.Sockets;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using System.Runtime.InteropServices;
10+
using System.Threading;
11+
12+
namespace ChuniVController
13+
{
14+
public enum ChuniMessageSources
15+
{
16+
Game = 0,
17+
Controller = 1
18+
}
19+
20+
public enum ChuniMessageTypes
21+
{
22+
CoinInsert = 0,
23+
SliderPress = 1,
24+
SliderRelease = 2,
25+
LedSet = 3,
26+
CabinetTest = 4,
27+
CabinetService = 5,
28+
IrBlocked = 6,
29+
IrUnblocked = 7
30+
}
31+
32+
public struct ChuniIoMessage
33+
{
34+
public byte Source;
35+
public byte Type;
36+
public byte Target;
37+
public byte LedColorRed;
38+
public byte LedColorGreen;
39+
public byte LedColorBlue;
40+
}
41+
42+
public class ChuniIO
43+
{
44+
private readonly UdpClient _client;
45+
private readonly string _ioServerAddress;
46+
private readonly int _port;
47+
private bool _running;
48+
private byte[] _sendBuffer;
49+
private readonly IntPtr _sendBufferUnmanaged;
50+
private readonly RecvCallback _recvCallback;
51+
private Thread _recvThread;
52+
53+
private struct RecvContext
54+
{
55+
public UdpClient client;
56+
public RecvCallback callback;
57+
}
58+
59+
public delegate void RecvCallback(ChuniIoMessage message);
60+
61+
public ChuniIO(string ioServerAddress, int port, RecvCallback recvCallback)
62+
{
63+
_ioServerAddress = ioServerAddress;
64+
_port = port;
65+
_running = false;
66+
_client = new UdpClient();
67+
_sendBuffer = new byte[32];
68+
_sendBufferUnmanaged = Marshal.AllocHGlobal(32);
69+
70+
_recvCallback = recvCallback;
71+
}
72+
73+
~ChuniIO()
74+
{
75+
Marshal.FreeHGlobal(_sendBufferUnmanaged);
76+
}
77+
78+
private static void RecvThread(object c)
79+
{
80+
ChuniIoMessage message = new ChuniIoMessage();
81+
int sz = Marshal.SizeOf(message);
82+
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
83+
IntPtr recvBufferPtr;
84+
recvBufferPtr = Marshal.AllocHGlobal(32);
85+
86+
RecvContext context = (RecvContext) c;
87+
88+
try
89+
{
90+
while (true)
91+
{
92+
byte[] recvBuffer = context.client.Receive(ref endpoint);
93+
if (recvBuffer.Length == 0) break;
94+
if (recvBuffer.Length != sz) continue;
95+
Marshal.Copy(recvBuffer, 0, recvBufferPtr, sz);
96+
message = (ChuniIoMessage)Marshal.PtrToStructure(recvBufferPtr, message.GetType());
97+
context.callback(message);
98+
}
99+
}
100+
catch
101+
{
102+
// noting, just exit.
103+
}
104+
105+
106+
Marshal.FreeHGlobal(recvBufferPtr);
107+
}
108+
109+
public bool Start()
110+
{
111+
if (_running) return false;
112+
try
113+
{
114+
_client.Connect(_ioServerAddress, _port);
115+
}
116+
catch
117+
{
118+
return false;
119+
}
120+
121+
RecvContext c = new RecvContext();
122+
c.client = _client;
123+
c.callback = _recvCallback;
124+
125+
_recvThread = new Thread(RecvThread);
126+
_recvThread.Start(c);
127+
128+
_running = true;
129+
return true;
130+
}
131+
132+
public bool Stop()
133+
{
134+
if (!_running) return false;
135+
try
136+
{
137+
_client.Close();
138+
}
139+
catch
140+
{
141+
return false;
142+
}
143+
return true;
144+
}
145+
146+
public void Join()
147+
{
148+
_recvThread.Join();
149+
}
150+
151+
private void SendCallback(IAsyncResult ar)
152+
{
153+
// don't care
154+
}
155+
156+
public void Send(ChuniIoMessage message)
157+
{
158+
int sz = Marshal.SizeOf(message);
159+
Marshal.StructureToPtr(message, _sendBufferUnmanaged, false);
160+
Marshal.Copy(_sendBufferUnmanaged, _sendBuffer, 0, sz);
161+
_client.BeginSend(_sendBuffer, sz, SendCallback, null);
162+
}
163+
164+
165+
166+
}
167+
}

ChuniVController/ChuniVController/ChuniVController.csproj

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,14 @@
5555
<Generator>MSBuild:Compile</Generator>
5656
<SubType>Designer</SubType>
5757
</ApplicationDefinition>
58+
<Compile Include="ChuniIO.cs" />
5859
<Compile Include="TouchPad.xaml.cs">
5960
<DependentUpon>TouchPad.xaml</DependentUpon>
6061
</Compile>
6162
<Page Include="MainWindow.xaml">
6263
<Generator>MSBuild:Compile</Generator>
6364
<SubType>Designer</SubType>
6465
</Page>
65-
<Compile Include="App.xaml.cs">
66-
<DependentUpon>App.xaml</DependentUpon>
67-
<SubType>Code</SubType>
68-
</Compile>
6966
<Compile Include="MainWindow.xaml.cs">
7067
<DependentUpon>MainWindow.xaml</DependentUpon>
7168
<SubType>Code</SubType>

0 commit comments

Comments
 (0)