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