libelec
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
libelec_types_impl.h
1 /*
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5  */
6 /*
7  * Copyright 2023 Saso Kiselkov. All rights reserved.
8  */
9 
10 #ifndef __LIBELEC_TYPES_IMPL_H__
11 #define __LIBELEC_TYPES_IMPL_H__
12 
13 #ifdef XPLANE
14 #include <acfutils/dr.h>
15 #endif
16 #include <acfutils/htbl.h>
17 #include <acfutils/list.h>
18 #include <acfutils/worker.h>
19 #include <acfutils/thread.h>
20 
21 #ifdef LIBELEC_WITH_LIBSWITCH
22 #include <libswitch.h>
23 #endif
24 
25 #ifdef LIBELEC_WITH_NETLINK
26 #include "libelec_types_net.h"
27 #endif
28 
29 #include "libelec.h"
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 #define LIBELEC_SER_START_MARKER \
36  ALIGN_ATTR(16) int __serialize_start_marker[1]
37 #define LIBELEC_SER_END_MARKER \
38  int __serialize_end_marker[1]
39 #define LIBELEC_SERIALIZE_DATA_V(data, ser, key, ...) \
40  conf_set_data_v((ser), (key), &(data)->__serialize_start_marker, \
41  ((uintptr_t)&(data)->__serialize_end_marker) - \
42  ((uintptr_t)&(data)->__serialize_start_marker), __VA_ARGS__)
43 #define LIBELEC_DESERIALIZE_DATA_V(data, ser, key, ...) \
44  do { \
45  size_t __len = ((uintptr_t)&(data)->__serialize_end_marker) - \
46  ((uintptr_t)&(data)->__serialize_start_marker); \
47  void *tmpbuf = safe_malloc(__len); \
48  size_t __act_len = conf_get_data_v((ser), (key), tmpbuf, \
49  __len, __VA_ARGS__); \
50  if (__act_len != __len) { \
51  logMsg("Error deserializing key " key ": " \
52  "data length mismatch, wanted %d bytes, got %d", \
53  __VA_ARGS__, (int)__len, (int)__act_len); \
54  free(tmpbuf); \
55  return (false); \
56  } \
57  memcpy(&(data)->__serialize_start_marker, tmpbuf, __len); \
58  free(tmpbuf); \
59  } while (0)
60 
61 
62 struct elec_sys_s {
63  bool started;
64  worker_t worker;
65  mutex_t worker_interlock;
66 
67  mutex_t paused_lock;
68  bool paused; /* protected by paused_lock */
69  double time_factor; /* only accessed from main thread */
70  uint64_t prev_clock;
71 #ifdef XPLANE
72  double prev_sim_time;
73  struct {
74  dr_t paused;
75  dr_t replay;
76  dr_t sim_speed_act;
77  dr_t sim_time;
78  } drs;
79 #endif /* defined(XPLANE) */
80 
81  char *conf_filename;
82  uint64_t conf_crc;
83 
84  avl_tree_t info2comp;
85  avl_tree_t name2comp;
86 
87  mutex_t user_cbs_lock;
88  avl_tree_t user_cbs;
89 
90  list_t comps;
91  elec_comp_t **comps_array; /* length list_count(&comps) */
92  list_t gens_batts;
93  list_t ties;
94 
95  elec_comp_info_t *comp_infos; /* immutable after parse */
96  size_t num_infos;
97 #ifdef LIBELEC_WITH_NETLINK
98  struct {
99  bool active;
100  /* protected by worker_interlock */
101  htbl_t conns; /* list of net_conn_t's */
102  list_t conns_list;
103  /* only accessed from worker thread */
104  unsigned xmit_ctr;
105  netlink_proto_t proto;
106  } net_send;
107  struct {
108  bool active;
109  uint8_t *map;
110  bool map_dirty;
111  netlink_proto_t proto;
112  } net_recv;
113 #endif /* defined(LIBELEC_WITH_NETLINK) */
114 };
115 
116 typedef struct {
117  LIBELEC_SER_START_MARKER;
118  double prev_amps;
119  double chg_rel;
120  double rechg_W;
121  LIBELEC_SER_END_MARKER;
122  mutex_t lock;
123  double T; /* Kelvin, protected by `lock` above */
124 } elec_batt_t;
125 
126 typedef struct {
127  double ctr_rpm;
128  double min_stab_U;
129  double max_stab_U;
130  double min_stab_f;
131  double max_stab_f;
132  double eff;
133  mutex_t lock;
134  double rpm; /* protected by `lock` above */
135  LIBELEC_SER_START_MARKER;
136  double tgt_volts;
137  double tgt_freq;
138  double stab_factor_U;
139  double stab_factor_f;
140  LIBELEC_SER_END_MARKER;
141 } elec_gen_t;
142 
143 typedef struct {
144  elec_comp_t *batt;
145  elec_comp_t *batt_conn;
146  double prev_amps;
147  double regul;
148  double eff;
149 } elec_tru_t;
150 
151 typedef struct {
152  double eff;
153 } elec_xfrmr_t;
154 
155 typedef struct {
156  elec_comp_t *bus;
157  LIBELEC_SER_START_MARKER;
158  /* Virtual input capacitor voltage */
159  double incap_U;
160  double random_load_factor;
161  LIBELEC_SER_END_MARKER;
162  /* Change of input capacitor charge */
163  double incap_d_Q;
164 
165  bool seen;
166 } elec_load_t;
167 
168 typedef struct {
169 #ifdef LIBELEC_WITH_LIBSWITCH
170  switch_t *sw; /* optional libswitch link */
171 #endif
172  LIBELEC_SER_START_MARKER;
173  bool_t cur_set;
174  bool_t wk_set;
175  double temp; /* relative 0.0 - 1.0 */
176  LIBELEC_SER_END_MARKER;
177 } elec_scb_t;
178 
179 typedef struct {
180  /*
181  * To prevent global locking from front-end functions, the tie
182  * state is kept split between `cur_state' and `wk_state':
183  * cur_state - is read and adjusted from external functions
184  * wk_state - is read-only from the worker thread
185  * At the start of the network worker loop, `cur_state' is
186  * transferred into `wk_state'. This guarantees a consistent tie
187  * state during a single worker invocation without having to hold
188  * the tie state lock throughout the worker loop.
189  */
190  mutex_t lock;
191  bool *cur_state;
192  bool *wk_state;
193 } elec_tie_t;
194 
195 typedef struct {
196  elec_comp_t *comp;
197  double out_amps[ELEC_MAX_SRCS];
198  elec_comp_t *srcs[ELEC_MAX_SRCS];
199 } elec_link_t;
200 
201 struct elec_comp_s {
202  elec_sys_t *sys;
203  elec_comp_info_t *info;
204 
205  /*
206  * Bitmask that gets checked by the network state integrator
207  * and reset in network_reset. This is used to prevent double-
208  * accounting of buses.
209  */
210  uint64_t integ_mask;
211  elec_link_t *links;
212  unsigned n_links;
213  unsigned src_idx;
214  unsigned comp_idx;
215 
216  mutex_t rw_ro_lock;
217 
218  LIBELEC_SER_START_MARKER;
219  struct {
220  double in_volts;
221  double out_volts;
222  double in_amps;
223  double out_amps;
224  double short_amps;
225  double in_pwr; /* Watts */
226  double out_pwr; /* Watts */
227  double in_freq; /* Hz */
228  double out_freq; /* Hz */
229  bool failed;
230  /*
231  * Shorted components leak a lot of their energy out
232  * to the environment and so we must avoid returning
233  * the leakage to in libelec_comp_get_xxx. Other
234  * parts of the system depend on those being the
235  * actual useful work being done by the component.
236  */
237  bool shorted;
238  double leak_factor;
239  } rw, ro;
240  LIBELEC_SER_END_MARKER;
241 
242  double src_int_cond_total; /* Conductance, abstract */
243  uint64_t src_mask;
244  elec_comp_t *srcs[ELEC_MAX_SRCS];
245  unsigned n_srcs;
246  /*
247  * Version for external consumers, which is only updated after a
248  * network integration pass. This avoids e.g. blinking when the
249  * when `srcs' array gets reset during the integration pass.
250  * Protected by rw_ro_lock.
251  */
252  elec_comp_t *srcs_ext[ELEC_MAX_SRCS];
253 
254  union {
255  elec_batt_t batt;
256  elec_gen_t gen;
257  elec_tru_t tru;
258  elec_xfrmr_t xfrmr;
259  elec_load_t load;
260  elec_scb_t scb;
261  elec_tie_t tie;
262  };
263 
264 #ifdef LIBELEC_WITH_DRS
265  struct {
266  dr_t in_volts;
267  dr_t out_volts;
268  dr_t in_amps;
269  dr_t out_amps;
270  dr_t in_pwr;
271  dr_t out_pwr;
272  } drs;
273 #endif /* defined(LIBELEC_WITH_DRS) */
274 
275  list_node_t comps_node;
276  list_node_t gens_batts_node;
277  list_node_t ties_node;
278  avl_node_t info2comp_node;
279  avl_node_t name2comp_node;
280 };
281 
282 #ifdef __cplusplus
283 }
284 #endif
285 
286 #endif /* __LIBELEC_TYPES_IMPL_H__ */