@@ -125,13 +125,55 @@ pub struct BreakpointConfig {
125125 pub enable_conditional : bool ,
126126}
127127
128+ /// How the proxy reaches the debug target (stub TCP vs future native probe).
129+ #[ derive( Debug , Clone , Copy , Serialize , Deserialize , PartialEq , Eq , Default ) ]
130+ #[ serde( rename_all = "lowercase" ) ]
131+ pub enum BackendTransport {
132+ /// GDB remote stub on `proxy.target_host`:`proxy.target_port` (OpenOCD, probe-rs GDB port, …).
133+ #[ default]
134+ #[ serde( alias = "stub" ) ]
135+ Tcp ,
136+ /// Direct probe / native integration (not implemented; reserved for #9).
137+ Native ,
138+ }
139+
140+ impl BackendTransport {
141+ /// Parse from config strings (`tcp`, `stub`, `native`).
142+ pub fn parse ( s : & str ) -> ConfigResult < Self > {
143+ match s. trim ( ) . to_ascii_lowercase ( ) . as_str ( ) {
144+ "tcp" | "stub" => Ok ( Self :: Tcp ) ,
145+ "native" => Ok ( Self :: Native ) ,
146+ "" => Err ( ConfigError :: InvalidValue {
147+ field : "backend.transport" . to_string ( ) ,
148+ reason : "Cannot be empty" . to_string ( ) ,
149+ } ) ,
150+ other => Err ( ConfigError :: InvalidValue {
151+ field : "backend.transport" . to_string ( ) ,
152+ reason : format ! ( "Must be tcp or native, got: {other}" ) ,
153+ } ) ,
154+ }
155+ }
156+ }
157+
158+ impl std:: str:: FromStr for BackendTransport {
159+ type Err = String ;
160+
161+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
162+ Self :: parse ( s) . map_err ( |e| e. to_string ( ) )
163+ }
164+ }
165+
128166/// Backend configuration
129167#[ derive( Debug , Clone , Serialize , Deserialize ) ]
130168pub struct BackendConfig {
131- /// Backend type (openocd, probe-rs, pyocd)
169+ /// Label for the stub or tool (openocd, probe-rs, pyocd, …) — logging / future use only.
132170 #[ serde( default = "default_backend_type" ) ]
133171 pub backend_type : String ,
134172
173+ /// Transport to the target (`tcp` = remote stub; `native` reserved).
174+ #[ serde( default ) ]
175+ pub transport : BackendTransport ,
176+
135177 /// Backend-specific options
136178 #[ serde( default ) ]
137179 pub options : std:: collections:: HashMap < String , String > ,
@@ -235,6 +277,7 @@ impl Default for BackendConfig {
235277 fn default ( ) -> Self {
236278 Self {
237279 backend_type : default_backend_type ( ) ,
280+ transport : BackendTransport :: default ( ) ,
238281 options : std:: collections:: HashMap :: new ( ) ,
239282 }
240283 }
@@ -326,12 +369,11 @@ impl Config {
326369 } ) ;
327370 }
328371
329- // Validate backend config
330- let valid_backends = [ "openocd" , "probe-rs" , "pyocd" ] ;
331- if !valid_backends. contains ( & self . backend . backend_type . as_str ( ) ) {
372+ // Backend label is free-form (openocd, probe-rs, custom); must not be empty.
373+ if self . backend . backend_type . trim ( ) . is_empty ( ) {
332374 return Err ( ConfigError :: InvalidValue {
333375 field : "backend.backend_type" . to_string ( ) ,
334- reason : format ! ( "Must be one of: {}" , valid_backends . join ( ", " ) ) ,
376+ reason : "Cannot be empty" . to_string ( ) ,
335377 } ) ;
336378 }
337379
@@ -382,6 +424,12 @@ impl Config {
382424 self . backend . backend_type = backend;
383425 }
384426
427+ if let Ok ( t) = std:: env:: var ( "RSGDB_TRANSPORT" ) {
428+ if let Ok ( tr) = BackendTransport :: parse ( & t) {
429+ self . backend . transport = tr;
430+ }
431+ }
432+
385433 if let Ok ( v) = std:: env:: var ( "RSGDB_RECORD" ) {
386434 let v = v. trim ( ) ;
387435 if v == "1" || v. eq_ignore_ascii_case ( "true" ) || v. eq_ignore_ascii_case ( "yes" ) {
0 commit comments