1+ /*
2+ This file is part of RetroWave.
3+
4+ Copyright (C) 2025 Christian Kündig <christian@kuendig.info>
5+
6+ This program is free software: you can redistribute it and/or modify
7+ it under the terms of the GNU Affero General Public License as
8+ published by the Free Software Foundation, either version 3 of the
9+ License, or (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU Affero General Public License for more details.
15+
16+ You should have received a copy of the GNU Affero General Public License
17+ along with this program. If not, see <https://www.gnu.org/licenses/>.
18+ */
19+
20+ /*
21+ Warning for GitHub Copilot (or any "Coding AI") users:
22+
23+ "Fair use" is only valid in some countries, such as the United States.
24+
25+ This program is protected by copyright law and international treaties.
26+
27+ Unauthorized reproduction or distribution of this program (e.g. violating
28+ the GPL license), or any portion of it, may result in severe civil and
29+ criminal penalties, and will be prosecuted to the maximum extent possible
30+ under law.
31+ */
32+
33+ /*
34+ 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告:
35+
36+ “合理使用”只在一些国家有效,如美国。
37+
38+ 本程序受版权法和国际条约的保护。
39+
40+ 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚,
41+ 并将在法律允许的最大范围内被起诉。
42+ */
43+
44+
45+ #include "Web_SerialPort.h"
46+ #include "assert.h"
47+
48+ #ifdef EMSCRIPTEN
49+ #include <emscripten.h>
50+
51+ static const char log_tag [] = "retrowave platform web_serialport" ;
52+
53+ EM_ASYNC_JS (ssize_t , webserial_write , (const void * __buf ,size_t __nbyte ), { // ssize_t (aka long), const void * __buf, size_t __nbyte (aka unsigned long)
54+ const port = globalThis ['retrowave_port' ];
55+
56+ if ('retrowave_writer' in globalThis == = false) {
57+ console .log ("Getting Writer" );
58+ globalThis ['retrowave_writer' ] = port .writable .getWriter ();
59+ }
60+ data = new DataView (HEAPU8 .buffer , __buf , __nbyte );
61+ await globalThis ['retrowave_writer' ].write (data );
62+ return __nbyte ;
63+ });
64+
65+ static void io_callback (void * userp , uint32_t data_rate , const void * tx_buf , void * rx_buf , uint32_t len ) {
66+ RetroWavePlatform_WebSerialPort * ctx = userp ;
67+
68+ uint32_t packed_len = retrowave_protocol_serial_packed_length (len );
69+ uint8_t * packed_data ;
70+
71+ if (packed_len > 128 )
72+ packed_data = malloc (packed_len );
73+ else
74+ packed_data = alloca (packed_len );
75+ assert (retrowave_protocol_serial_pack (tx_buf , len , packed_data ) == packed_len );
76+
77+ size_t written = 0 ;
78+ while (written < len ) {
79+ ssize_t rc = webserial_write (packed_data + written , packed_len - written );
80+ emscripten_sleep (1 );
81+ if (rc > 0 ) {
82+ written += rc ;
83+ } else {
84+ fprintf (stderr , "%s: FATAL: failed to write to tty: %s\n" , log_tag , strerror (errno ));
85+ abort ();
86+ }
87+ }
88+
89+ if (packed_len > 128 )
90+ free (packed_data );
91+ }
92+
93+ EM_ASYNC_JS (int , webserial_deinit , ( ), {
94+ globalThis ['retrowave_writer' ].releaseLock ();
95+ await globalThis ['retrowave_port' ].close ();
96+ delete globalThis ['retrowave_writer' ];
97+ delete globalThis ['retrowave_port' ];
98+ });
99+
100+ EM_ASYNC_JS (int , webserial_init , ( ), {
101+ const supported = !!navigator .serial ;
102+ if (!supported ) {
103+ console .error ("Serial API not supported" );
104+ return -1 ;
105+ }
106+
107+ try {
108+ const port = await navigator .serial .requestPort (); //TODO: filter for pid:"e683", vid: "04d8" (check if other revision have different values)
109+
110+ console .log (port );
111+ globalThis ['retrowave_port' ] = port ;
112+ await port .open ({ baudRate : 115200 });
113+
114+ const info = port .getInfo ();
115+ vid = info .usbVendorId ;
116+ pid = info .usbProductId ;
117+ console .log (info );
118+ } catch (e ) {
119+ console .error ("Error requesting port: " , e );
120+ return -1 ;
121+ }
122+ try {
123+ const ports = await navigator .serial .getPorts ();
124+ const id = vid + ':' + pid ;
125+ //port_new = ports.find((port) => vid_pid(port) === id);
126+ console .log (ports );
127+ } catch (e ) {
128+ console .error ("Error getting ports: " , e );
129+ return -1 ;
130+ }
131+
132+ return 0 ;
133+ });
134+
135+
136+ int retrowave_init_web_serialport (RetroWaveContext * ctx ) {
137+ retrowave_init (ctx );
138+
139+ ctx -> user_data = malloc (sizeof (RetroWavePlatform_WebSerialPort ));
140+ RetroWavePlatform_WebSerialPort * pctx = ctx -> user_data ;
141+
142+ if (webserial_init () != 0 ) {
143+ fprintf (stderr , "%s: FATAL: failed to initialize web serial port\n" , log_tag );
144+ return -1 ;
145+ }
146+
147+ ctx -> callback_io = io_callback ;
148+ return 0 ;
149+ }
150+
151+ void retrowave_deinit_web_serialport (RetroWaveContext * ctx ) {
152+ webserial_deinit ();
153+ }
154+
155+ #endif
0 commit comments