-
Notifications
You must be signed in to change notification settings - Fork 0
/
sim_tmxr.h
356 lines (328 loc) · 22.8 KB
/
sim_tmxr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/* sim_tmxr.h: terminal multiplexer definitions
Copyright (c) 2001-2008, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Based on the original DZ11 simulator by Thord Nilson, as updated by
Arthur Krewat.
10-Oct-12 MP Added extended attach support for serial, per line
listener and outgoing connections
17-Jan-11 MP Added buffered line capabilities
20-Nov-08 RMS Added three new standardized SHOW routines
07-Oct-08 JDB Added serial port support to TMXR, TMLN
27-May-08 JDB Added lnorder to TMXR structure,
added tmxr_set_lnorder and tmxr_set_lnorder
14-May-08 JDB Added dptr to TMXR structure
04-Jan-04 RMS Changed TMXR ldsc to be pointer to linedesc array
Added tmxr_linemsg, logging (from Mark Pizzolato)
29-Dec-03 RMS Added output stall support, increased buffer size
22-Dec-02 RMS Added break support (from Mark Pizzolato)
20-Aug-02 RMS Added tmxr_open_master, tmxr_close_master, tmxr.port
30-Dec-01 RMS Renamed tmxr_fstatus, added tmxr_fstats
20-Oct-01 RMS Removed tmxr_getchar, formalized buffer guard,
added tmxr_rqln, tmxr_tqln
*/
#ifndef SIM_TMXR_H_
#define SIM_TMXR_H_ 0
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SIMH_SERHANDLE_DEFINED
#define SIMH_SERHANDLE_DEFINED 0
typedef struct SERPORT *SERHANDLE;
#endif
#include "sim_defs.h"
#include "sim_sock.h"
#define TMXR_V_VALID 15
#define TMXR_VALID (1 << TMXR_V_VALID)
#define TMXR_MAXBUF 256 /* buffer size */
#define TMXR_DTR_DROP_TIME 500 /* milliseconds to drop DTR for 'pseudo' modem control */
#define TMXR_MODEM_RING_TIME 3 /* seconds to wait for DTR for incoming connections */
#define TMXR_DEFAULT_CONNECT_POLL_INTERVAL 1 /* seconds between connection polls */
#define TMXR_DBG_XMT 0x00100000 /* Debug Transmit Data */
#define TMXR_DBG_RCV 0x00200000 /* Debug Received Data */
#define TMXR_DBG_RET 0x00400000 /* Debug Returned Received Data */
#define TMXR_DBG_MDM 0x00800000 /* Debug Modem Signals */
#define TMXR_DBG_CFG 0x01000000 /* Debug Line Configuration Activities */
#define TMXR_DBG_CON 0x02000000 /* Debug Connection Activities */
#define TMXR_DBG_ASY 0x04000000 /* Debug Asynchronous Activities - unused */
#define TMXR_DBG_TRC 0x08000000 /* Debug trace routine calls */
#define TMXR_DBG_PXMT 0x10000000 /* Debug Transmit Packet Data */
#define TMXR_DBG_PRCV 0x20000000 /* Debug Received Packet Data */
#define TMXR_DBG_EXP 0x40000000 /* Debug Expect Activities */
#define TMXR_DBG_SEND 0x80000000 /* Debug Send Activities */
/* Modem Control Bits */
#define TMXR_MDM_DTR 0x01 /* Data Terminal Ready */
#define TMXR_MDM_RTS 0x02 /* Request To Send */
#define TMXR_MDM_DCD 0x04 /* Data Carrier Detect */
#define TMXR_MDM_RNG 0x08 /* Ring Indicator */
#define TMXR_MDM_CTS 0x10 /* Clear To Send */
#define TMXR_MDM_DSR 0x20 /* Data Set Ready */
#define TMXR_MDM_INCOMING (TMXR_MDM_DCD|TMXR_MDM_RNG|TMXR_MDM_CTS|TMXR_MDM_DSR) /* Settable Modem Bits */
#define TMXR_MDM_OUTGOING (TMXR_MDM_DTR|TMXR_MDM_RTS) /* Settable Modem Bits */
/* Receive line speed limits */
#define TMLN_SPD_50_BPS 200000 /* usec per character */
#define TMLN_SPD_75_BPS 133333 /* usec per character */
#define TMLN_SPD_110_BPS 90909 /* usec per character */
#define TMLN_SPD_134_BPS 74626 /* usec per character */
#define TMLN_SPD_150_BPS 66666 /* usec per character */
#define TMLN_SPD_300_BPS 33333 /* usec per character */
#define TMLN_SPD_600_BPS 16666 /* usec per character */
#define TMLN_SPD_1200_BPS 8333 /* usec per character */
#define TMLN_SPD_1800_BPS 5555 /* usec per character */
#define TMLN_SPD_2000_BPS 5000 /* usec per character */
#define TMLN_SPD_2400_BPS 4166 /* usec per character */
#define TMLN_SPD_3600_BPS 2777 /* usec per character */
#define TMLN_SPD_4800_BPS 2083 /* usec per character */
#define TMLN_SPD_7200_BPS 1388 /* usec per character */
#define TMLN_SPD_9600_BPS 1041 /* usec per character */
#define TMLN_SPD_19200_BPS 520 /* usec per character */
#define TMLN_SPD_25000_BPS 400 /* usec per character */
#define TMLN_SPD_38400_BPS 260 /* usec per character */
#define TMLN_SPD_40000_BPS 250 /* usec per character */
#define TMLN_SPD_50000_BPS 200 /* usec per character */
#define TMLN_SPD_57600_BPS 173 /* usec per character */
#define TMLN_SPD_76800_BPS 130 /* usec per character */
#define TMLN_SPD_80000_BPS 125 /* usec per character */
#define TMLN_SPD_115200_BPS 86 /* usec per character */
/* Internal struct */
struct framer_data;
typedef struct tmln TMLN;
typedef struct tmxr TMXR;
struct loopbuf {
int32 bpr; /* xmt buf remove */
int32 bpi; /* xmt buf insert */
int32 size;
};
struct tmln {
int conn; /* line connected flag */
SOCKET sock; /* connection socket */
char *ipad; /* IP address */
SOCKET master; /* line specific master socket */
char *port; /* line specific listening port */
char *acl; /* Access control list (CIDR) to accept or reject connects from */
uint32 backlog; /* line specific listening backlog */
int32 acl_accepted_sessions; /* count of ACL accepted tcp connections */
int32 acl_rejected_sessions; /* count of ACL rejected tcp connections */
int32 sessions; /* count of tcp connections received */
uint32 cnms; /* conn time */
int32 tsta; /* Telnet state */
int32 rcve; /* rcv enable */
int32 xmte; /* xmt enable */
int32 dstb; /* disable Telnet binary mode */
t_bool notelnet; /* raw binary data (no telnet interpretation) */
t_bool nomessage; /* no connect/disconnect message on line even if telnet */
uint8 *telnet_sent_opts; /* Telnet Options which we have sent a DON'T/WON'T */
int32 rxbpr; /* rcv buf remove */
int32 rxbpi; /* rcv buf insert */
int32 rxbsz; /* rcv buffer size */
int32 rxcnt; /* rcv count */
int32 rxpcnt; /* rcv packet count */
int32 txbpr; /* xmt buf remove */
int32 txbpi; /* xmt buf insert */
int32 txcnt; /* xmt count */
int32 txpcnt; /* xmt packet count */
int32 txdrp; /* xmt drop count */
int32 txstall; /* xmt stall count */
int32 txbsz; /* xmt buffer size */
int32 txbfd; /* xmt buffered flag */
t_bool modem_control; /* line supports modem control behaviors */
t_bool port_speed_control; /* line programmatically sets port speed */
int32 modembits; /* modem bits which are currently set */
FILE *txlog; /* xmt log file */
FILEREF *txlogref; /* xmt log file reference */
char *txlogname; /* xmt log file name */
char *rxb; /* rcv buffer */
char *rbr; /* rcv break */
char *txb; /* xmt buffer */
uint8 *rxpb; /* rcv packet buffer */
uint32 rxpbsize; /* rcv packet buffer size */
uint32 rxpboffset; /* rcv packet buffer offset */
uint32 rxbps; /* rcv bps speed (0 - unlimited) */
double bpsfactor; /* receive speed factor (scaled to usecs) */
#define USECS_PER_SECOND 1000000.0
uint32 rxdeltausecs; /* rcv inter character min time (usecs) */
double rxnexttime; /* min time for next receive character */
uint32 txbps; /* xmt bps speed (0 - unlimited) */
uint32 txdeltausecs; /* xmt inter character min time (usecs) */
double txnexttime; /* min time for next transmit character */
t_bool txdone; /* sent data complete indicator - private */
uint8 *txpb; /* xmt packet buffer */
uint32 txpbsize; /* xmt packet buffer size */
uint32 txppsize; /* xmt packet packet size */
uint32 txppoffset; /* xmt packet buffer offset */
TMXR *mp; /* back pointer to mux */
char *serconfig; /* line config */
SERHANDLE serport; /* serial port handle */
t_bool ser_connect_pending; /* serial connection notice pending */
SOCKET connecting; /* Outgoing socket while connecting */
char *destination; /* Outgoing destination address:port */
t_bool loopback; /* Line in loopback mode */
t_bool halfduplex; /* Line in half-duplex mode */
t_bool datagram; /* Line is datagram packet oriented */
t_bool packet; /* Line is packet oriented */
int32 lpbpr; /* loopback buf remove */
int32 lpbpi; /* loopback buf insert */
int32 lpbcnt; /* loopback buf used count */
int32 lpbsz; /* loopback buffer size */
char *lpb; /* loopback buffer */
UNIT *uptr; /* input polling unit (default to mp->uptr) */
UNIT *o_uptr; /* output polling unit (default to lp->uptr)*/
DEVICE *dptr; /* line specific device */
EXPECT *expect; /* Expect rules */
SEND *send; /* Send input state */
struct framer_data *framer; /* ddcmp framer data */
};
struct tmxr {
int32 lines; /* # lines */
char *port; /* listening port */
SOCKET master; /* master socket */
TMLN *ldsc; /* line descriptors */
int32 *lnorder; /* line connection order */
DEVICE *dptr; /* multiplexer device */
char *acl; /* Access control list (CIDR) to accept or reject connects from */
int32 acl_accepted_sessions; /* count of ACL accepted tcp connections */
int32 acl_rejected_sessions; /* count of ACL rejected tcp connections */
uint32 backlog; /* listen backlog */
UNIT *uptr; /* polling unit (connection) */
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
int32 txcount; /* count of transmit bytes */
int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */
int32 sessions; /* count of tcp connections received */
uint32 poll_interval; /* frequency of connection polls (seconds) */
uint32 last_poll_time; /* time of last connection poll */
uint32 ring_start_time; /* time ring signal was raised */
char *ring_ipad; /* incoming connection address awaiting DTR */
SOCKET ring_sock; /* incoming connection socket awaiting DTR */
t_bool notelnet; /* default telnet capability for incoming connections */
t_bool nomessage; /* no connect/disconnect message on line even if telnet */
t_bool modem_control; /* multiplexer supports modem control behaviors */
t_bool port_speed_control; /* multiplexer programmatically sets port speed */
t_bool packet; /* Lines are packet oriented */
t_bool datagram; /* Lines use datagram packet transport */
};
int32 tmxr_poll_conn (TMXR *mp);
t_stat tmxr_reset_ln (TMLN *lp);
t_stat tmxr_detach_ln (TMLN *lp);
int32 tmxr_input_pending_ln (TMLN *lp);
int32 tmxr_getc_ln (TMLN *lp);
t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize);
t_stat tmxr_get_packet_ln_ex (TMLN *lp, const uint8 **pbuf, size_t *psize, uint8 frame_byte);
void tmxr_poll_rx (TMXR *mp);
t_stat tmxr_putc_ln (TMLN *lp, int32 chr);
t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size);
t_stat tmxr_put_packet_ln_ex (TMLN *lp, const uint8 *buf, size_t size, uint8 frame_byte);
void tmxr_poll_tx (TMXR *mp);
int32 tmxr_send_buffered_data (TMLN *lp);
t_stat tmxr_open_master (TMXR *mp, CONST char *cptr);
t_stat tmxr_close_master (TMXR *mp);
t_stat tmxr_connection_poll_interval (TMXR *mp, uint32 seconds);
t_stat tmxr_attach (TMXR *mp, UNIT *uptr, CONST char *cptr);
#define tmxr_attach_ex(mp, uptr, cptr, async) tmxr_attach (mp, uptr, cptr)
t_stat tmxr_detach (TMXR *mp, UNIT *uptr);
t_stat tmxr_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
char *tmxr_line_attach_string(TMLN *lp);
t_stat tmxr_set_modem_control_passthru (TMXR *mp);
t_stat tmxr_clear_modem_control_passthru (TMXR *mp);
t_stat tmxr_set_notelnet (TMXR *mp);
t_stat tmxr_clear_notelnet (TMXR *mp);
t_stat tmxr_set_nomessage (TMXR *mp);
t_stat tmxr_clear_nomessage (TMXR *mp);
t_stat tmxr_set_port_speed_control (TMXR *mp);
t_stat tmxr_clear_port_speed_control (TMXR *mp);
t_stat tmxr_set_backlog (TMXR *mp, int32 backlog);
t_stat tmxr_set_line_port_speed_control (TMXR *mp, int line);
t_stat tmxr_clear_line_port_speed_control (TMXR *mp, int line);
t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits);
t_stat tmxr_set_line_loopback (TMLN *lp, t_bool enable_loopback);
t_bool tmxr_get_line_loopback (TMLN *lp);
t_stat tmxr_set_line_halfduplex (TMLN *lp, t_bool enable_loopback);
t_bool tmxr_get_line_halfduplex (TMLN *lp);
t_stat tmxr_set_line_speed (TMLN *lp, CONST char *speed);
t_stat tmxr_set_config_line (TMLN *lp, CONST char *config);
t_stat tmxr_set_line_modem_control (TMLN *lp, t_bool enab_disab);
t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll);
t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll);
t_stat tmxr_set_console_units (UNIT *rxuptr, UNIT *txuptr);
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
void tmxr_msg (SOCKET sock, const char *msg);
void tmxr_linemsg (TMLN *lp, const char *msg);
void tmxr_linemsgf (TMLN *lp, const char *fmt, ...);
void tmxr_linemsgvf (TMLN *lp, const char *fmt, va_list args);
void tmxr_fconns (FILE *st, const TMLN *lp, int32 ln);
void tmxr_fstats (FILE *st, const TMLN *lp, int32 ln);
t_stat tmxr_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tmxr_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_dscln (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
int32 tmxr_rqln (const TMLN *lp);
int32 tmxr_tqln (const TMLN *lp);
int32 tmxr_tpqln (const TMLN *lp);
int32 tmxr_txdone_ln (TMLN *lp);
t_bool tmxr_tpbusyln (const TMLN *lp);
t_stat tmxr_set_lnorder (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc);
t_stat tmxr_show_sync_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char *desc);
t_stat tmxr_show_sync (FILE* st, UNIT* uptr, int32 val, CONST void *desc);
t_stat tmxr_flush_log_files (void);
t_stat tmxr_activate (UNIT *uptr, int32 interval);
t_stat tmxr_activate_abs (UNIT *uptr, int32 interval);
t_stat tmxr_activate_after (UNIT *uptr, uint32 usecs_walltime);
t_stat tmxr_activate_after_abs (UNIT *uptr, uint32 usecs_walltime);
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval);
t_stat tmxr_clock_coschedule_abs (UNIT *uptr, int32 interval);
t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks);
t_stat tmxr_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 ticks);
t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
t_stat tmxr_locate_line (const char *dev_line, TMLN **lp);
const char *tmxr_send_line_name (const SEND *snd);
const char *tmxr_expect_line_name (const EXPECT *exp);
t_stat tmxr_startup (void);
t_stat tmxr_shutdown (void);
t_stat tmxr_sock_test (DEVICE *dptr, const char *cptr);
/* Framer support. These are a NOP if called on a non-framer line. */
void tmxr_start_framer (TMLN *line, int dmc_mode);
void tmxr_stop_framer (TMLN *line);
void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize);
#define tmxr_debug(dbits, lp, msg, buf, bufsize) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) _tmxr_debug (dbits, lp, msg, buf, bufsize); } while (0)
#define tmxr_debug_msg(dbits, lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) sim_debug (dbits, (lp)->mp->dptr, "%s", msg); } while (0)
#define tmxr_debug_return(lp, val) do {if (sim_deb && (val) && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_RET & (lp)->mp->dptr->dctrl)) { if ((lp)->rxbps) sim_debug (TMXR_DBG_RET, (lp)->mp->dptr, "Ln%d: 0x%x - Next after: %.0f\n", (int)((lp)-(lp)->mp->ldsc), val, (lp)->rxnexttime); else sim_debug (TMXR_DBG_RET, (lp)->mp->dptr, "Ln%d: 0x%x\n", (int)((lp)-(lp)->mp->ldsc), val); } } while (0)
#define tmxr_debug_trace(mp, msg) do {if (sim_deb && (mp)->dptr && (TMXR_DBG_TRC & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, mp->dptr, "%s\n", (msg)); } while (0)
#define tmxr_debug_trace_line(lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_TRC & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, (lp)->mp->dptr, "Ln%d:%s\n", (int)((lp)-(lp)->mp->ldsc), (msg)); } while (0)
#define tmxr_debug_connect(mp, msg) do {if (sim_deb && (mp)->dptr && (TMXR_DBG_CON & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_CON, mp->dptr, "%s\n", (msg)); } while (0)
#define tmxr_debug_connect_line(lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_CON & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_CON, (lp)->mp->dptr, "Ln%d:%s\n", (int)((lp)-(lp)->mp->ldsc), (msg)); } while (0)
t_stat tmxr_add_debug (DEVICE *dptr);
#if (!defined(NOT_MUX_USING_CODE))
#define sim_activate tmxr_activate
#define sim_activate_abs tmxr_activate_abs
#define sim_activate_after tmxr_activate_after
#define sim_activate_after_abs tmxr_activate_after_abs
#define sim_clock_coschedule tmxr_clock_coschedule
#define sim_clock_coschedule_abs tmxr_clock_coschedule_abs
#define sim_clock_coschedule_tmr tmxr_clock_coschedule_tmr
#define sim_clock_coschedule_tmr_abs tmxr_clock_coschedule_tmr_abs
#endif
#ifdef __cplusplus
}
#endif
#endif /* _SIM_TMXR_H_ */