1 module puppeteer.configuration.configuration; 2 3 import test.puppeteer.configuration.configuration_test : test; 4 mixin test; 5 6 import puppeteer.var_monitor_utils; 7 import puppeteer.value_adapter.value_adapter; 8 9 import puppeteer.configuration.i_configuration; 10 11 import puppeteer.configuration.invalid_configuration_exception; 12 13 import std.meta; 14 import std.conv; 15 import std.stdio; 16 import std.json; 17 18 private enum configAIAdaptersKey = "AI_ADAPTERS"; 19 private enum configPWMOutAvgAdaptersKey = "PWM_OUT_AVG_ADAPTERS"; 20 private enum configVarAdaptersKey = "VAR_ADAPTERS"; 21 22 private enum configAISensorNamesKey = "AI_SENSOR_NAMES"; 23 private enum configVarSensorNamesKey = "VAR_SENSOR_NAMES"; 24 25 shared class Configuration(VarMonitorTypes...) : IConfiguration!VarMonitorTypes 26 if(allSatisfy!(isVarMonitorTypeSupported, VarMonitorTypes)) 27 { 28 protected ValueAdapter!float[ubyte] AIValueAdapters; 29 protected ValueAdapter!float[ubyte] PWMOutAvgValueAdapters; 30 protected mixin(unrollVariableValueAdapters!VarMonitorTypes()); 31 32 protected string[ubyte] AISensorNames; 33 protected mixin(unrollVarMonitorSensorNames!VarMonitorTypes()); 34 35 mixin(unrollHelperMethods!VarMonitorTypes()); 36 37 public void setAIValueAdapterExpression(ubyte pin, string adapterExpression) 38 { 39 setAdapterExpression(AIValueAdapters, pin, adapterExpression); 40 } 41 42 public string getAIValueAdapterExpression(ubyte pin) const 43 { 44 auto adapter = pin in AIValueAdapters; 45 46 return adapter ? adapter.expression : "x"; 47 } 48 49 public float adaptAIValue(ubyte pin, float value) const 50 { 51 auto adapter = pin in AIValueAdapters; 52 53 return adapter ? adapter.opCall(value) : value; 54 } 55 56 public void setPWMOutAvgAdapterExpression(ubyte pin, string adapterExpression) 57 { 58 setAdapterExpression(PWMOutAvgValueAdapters, pin, adapterExpression); 59 } 60 61 public string getPWMOutAvgAdapterExpression(ubyte pin) const 62 { 63 auto adapter = pin in PWMOutAvgValueAdapters; 64 65 return adapter ? adapter.expression : "x"; 66 } 67 68 public float adaptPWMOutAvgValue(ubyte pin, float value) const 69 { 70 auto adapter = pin in PWMOutAvgValueAdapters; 71 72 return adapter ? adapter.opCall(value) : value; 73 } 74 75 public void setVarMonitorValueAdapterExpression(VarType)(ubyte varIndex, string adapterExpression) 76 { 77 alias adapterDict = Alias!(mixin(getVarMonitorValueAdaptersName!VarType)); 78 setAdapterExpression(adapterDict, varIndex, adapterExpression); 79 } 80 81 public string getVarMonitorValueAdapterExpression(VarType)(ubyte varIndex) const 82 { 83 alias adapterDict = Alias!(mixin(getVarMonitorValueAdaptersName!VarType)); 84 85 auto adapter = varIndex in adapterDict; 86 87 return adapter ? adapter.expression : "x"; 88 } 89 90 public VarType adaptVarMonitorValue(VarType)(ubyte varIndex, VarType value) const 91 { 92 alias adapterDict = Alias!(mixin(getVarMonitorValueAdaptersName!VarType)); 93 94 auto adapter = varIndex in adapterDict; 95 96 return adapter ? adapter.opCall(value) : value; 97 } 98 99 private void setAdapterExpression(T)(ref shared ValueAdapter!T[ubyte] adapterDict, ubyte position, string adapterExpression) 100 { 101 if(adapterExpression) 102 adapterDict[position] = shared ValueAdapter!T(adapterExpression); 103 else 104 adapterDict.remove(position); 105 } 106 107 public void setAISensorName(ubyte pin, string name) 108 { 109 setSensorName(AISensorNames, pin, name); 110 } 111 112 public string getAISensorName(ubyte pin) const 113 { 114 return getSensorName(AISensorNames, pin, "AI_" ~ to!string(pin)); 115 } 116 117 public void setVarMonitorSensorName(MonitorType)(ubyte position, string name) 118 { 119 setSensorName(varMonitorSensorNames!MonitorType, position, name); 120 } 121 122 public string getVarMonitorSensorName(MonitorType)(ubyte position) const 123 { 124 return getSensorName(varMonitorSensorNames!MonitorType, position, varMonitorDefaultSensorName!MonitorType ~ "_" ~ to!string(position)); 125 } 126 127 private void setSensorName(ref shared string[ubyte] namesDict, ubyte position, string name) 128 { 129 if(name) 130 namesDict[position] = name; 131 else 132 namesDict.remove(position); 133 } 134 135 private string getSensorName(ref in shared string[ubyte] namesDict, ubyte position, string defaultName) const 136 { 137 if(position in namesDict) 138 return namesDict[position]; 139 else 140 return defaultName; 141 } 142 143 public void load(File configFile) 144 { 145 debug writeln("Trying to load configuration from file ", configFile.name != "" ? configFile.name : "with no name"); 146 147 string content; 148 configFile.readf("%s", &content); 149 150 load(content); 151 debug writeln("Success!"); 152 } 153 154 public void load(string configStr) 155 { 156 string generateSwitch(string method, string arguments) 157 { 158 string str = "switch(typeName) {"; 159 160 foreach(t; VarMonitorTypes) 161 { 162 str ~= "case \"" ~ t.stringof ~ "\":"; 163 str ~= method ~ "!" ~ t.stringof ~ arguments ~ ";"; 164 str ~= "break;"; 165 } 166 167 str ~= "default: throw new InvalidConfigurationException(\"Type \" ~ typeName ~ \" is not supported by this Puppeteer\");"; 168 str ~= "}"; 169 170 return str; 171 } 172 173 void setVarMonitorAdapterDynamic(string typeName, ubyte varIndex, string expr) 174 { 175 mixin(generateSwitch("setVarMonitorValueAdapterExpression", "(varIndex, expr)")); 176 } 177 178 void setVarMonitorSensorNameDynamic(string typeName, ubyte varIndex, string name) 179 { 180 mixin(generateSwitch("setVarMonitorSensorName", "(varIndex, name)")); 181 } 182 183 try 184 { 185 foreach(string key, inner; parseJSON(configStr).object) 186 { 187 switch(key) 188 { 189 case configAIAdaptersKey: 190 foreach(string pin, expr; inner.object) 191 setAIValueAdapterExpression(to!ubyte(pin), expr.str); 192 break; 193 194 case configPWMOutAvgAdaptersKey: 195 foreach(string pin, expr; inner.object) 196 setPWMOutAvgAdapterExpression(to!ubyte(pin), expr.str); 197 break; 198 199 case configVarAdaptersKey: 200 foreach(string typeName, innerJson; inner.object) 201 foreach(string varIndex, expr; innerJson) 202 setVarMonitorAdapterDynamic(typeName, to!ubyte(varIndex), expr.str); 203 break; 204 205 case configAISensorNamesKey: 206 foreach(string pin, name; inner.object) 207 setAISensorName(to!ubyte(pin), name.str); 208 break; 209 210 case configVarSensorNamesKey: 211 foreach(string typeName, innerJson; inner.object) 212 foreach(string varIndex, name; innerJson) 213 setVarMonitorSensorNameDynamic(typeName, to!ubyte(varIndex), name.str); 214 break; 215 216 default: 217 debug writefln("Unexpected entry with key '%s' found 218 in configuration JSON. Ignoring entry.", key); 219 } 220 } 221 } 222 catch(JSONException e) 223 { 224 debug writeln(e); 225 throw new InvalidConfigurationException("Invalid configuration string: " ~ configStr); 226 } 227 } 228 229 public void save(File sinkFile, bool flush = true) const 230 { 231 debug writeln("Trying to save configuration in file ", sinkFile.name != "" ? sinkFile.name : "with no name"); 232 233 sinkFile.write(save()); 234 if(flush) 235 sinkFile.flush(); 236 237 debug writeln("Sucess!"); 238 } 239 240 public string save() const 241 { 242 import std.json; 243 244 enum emptyJson = string[string].init; 245 246 JSONValue config = JSONValue(emptyJson); 247 248 // AI value adapters 249 if(AIValueAdapters.length > 0) 250 { 251 JSONValue json = JSONValue(emptyJson); 252 253 foreach(pin, adapter; AIValueAdapters) 254 json.object[to!string(pin)] = JSONValue(adapter.expression); 255 256 config.object[configAIAdaptersKey] = json; 257 } 258 259 // PWM Out Average value adapters 260 if(PWMOutAvgValueAdapters.length > 0) 261 { 262 JSONValue json = JSONValue(emptyJson); 263 264 foreach(pin, adapter; PWMOutAvgValueAdapters) 265 json.object[to!string(pin)] = JSONValue(adapter.expression); 266 267 config.object[configPWMOutAvgAdaptersKey] = json; 268 } 269 270 // VarMonitor value adapters 271 { 272 JSONValue varAdapters = JSONValue(emptyJson); 273 bool anyWritten = false; 274 275 foreach(T; VarMonitorTypes) 276 { 277 alias varMonitorAdapters = varMonitorValueAdapters!T; 278 279 if(varMonitorAdapters.length > 0) 280 { 281 anyWritten = true; 282 JSONValue json = JSONValue(emptyJson); 283 284 foreach(varIndex, adapter; varMonitorAdapters) 285 json.object[to!string(varIndex)] = JSONValue(adapter.expression); 286 287 varAdapters.object[T.stringof] = json; 288 } 289 } 290 291 if(anyWritten) 292 config.object[configVarAdaptersKey] = varAdapters; 293 } 294 295 // AI sensor names 296 if(AISensorNames.length > 0) 297 { 298 JSONValue json = JSONValue(emptyJson); 299 300 foreach(pin, name; AISensorNames) 301 json.object[to!string(pin)] = JSONValue(name); 302 303 config.object[configAISensorNamesKey] = json; 304 } 305 306 // VarMonitor sensor names 307 { 308 JSONValue varNames = JSONValue(emptyJson); 309 bool anyWritten = false; 310 311 foreach(T; VarMonitorTypes) 312 { 313 alias varMonitorNames = varMonitorSensorNames!T; 314 315 if(varMonitorNames.length > 0) 316 { 317 anyWritten = true; 318 JSONValue typeMonitorNamesJSON = JSONValue(emptyJson); 319 320 foreach(varIndex, name; varMonitorNames) 321 typeMonitorNamesJSON.object[to!string(varIndex)] = JSONValue(name); 322 323 varNames.object[T.stringof] = typeMonitorNamesJSON; 324 } 325 } 326 327 if(anyWritten) 328 config.object[configVarSensorNamesKey] = varNames; 329 } 330 331 return config.toPrettyString(); 332 } 333 334 private alias varMonitorValueAdapters(T) = Alias!(mixin(getVarMonitorValueAdaptersName!T)); 335 private alias varMonitorSensorNames(T) = Alias!(mixin(getVarMonitorSensorNamesName!T)); 336 } 337 338 //Clean this 339 private pure string unrollVariableValueAdapters(VarTypes...)() 340 { 341 string unroll = ""; 342 343 foreach(T; VarTypes) 344 unroll ~= getVarMonitorValueAdaptersType!T ~ " " ~ getVarMonitorValueAdaptersName!T ~ ";\n"; 345 346 return unroll; 347 } 348 349 private enum getVarMonitorValueAdaptersType(VarType) = "ValueAdapter!(" ~ VarType.stringof ~ ")[ubyte]"; 350 private enum getVarMonitorValueAdaptersName(VarType) = VarType.stringof ~ "ValueAdapters"; 351 352 private enum getVarMonitorSensorNamesName(VarType) = VarType.stringof ~ "SensorNames"; 353 354 private pure string unrollVarMonitorSensorNames(VarTypes...)() 355 { 356 string unroll = ""; 357 358 foreach(T; VarTypes) 359 unroll ~= "string[ubyte] " ~ getVarMonitorSensorNamesName!T ~ ";\n"; 360 361 return unroll; 362 }