# 1. 存在的问题
当前只能对一个灯光控制模块进行控制,但是由于产线中的灯光有两组,需要对两个灯光控制模块同时控制,因此需要对插件 PluginAlarm 的 Plugin.cs 进行修改。以及目前插件中的参数并不能实现自动保存,只有手动在 config.cs 代码中添加相应项才能实现对应参数的保存和读取。
# 2. 思路
# 2.1 灯光部分:
在插件代码中添加灯光控制器的对象,并且在增益算法中添加对新增灯光调整。
# 2.2 参数保存部分:
每个插件都存在 Attributes 用于存储当前插件下的控制参数,同时在 config.cs 中定义 Settings 类用来辅助存储插件的控制参数和主程序的控制参数。然后由 config 模块实现运行时 Settings 装载,Settings 实例在保存过程中会被序列化为 json 字符串,然后保存到本地配置文件中,而在读取时会反序列化本地配置文件生成运行时 Settings 实例,当配置文件不存在时,会根据生成默认值的配置文件,当本地配置文件中没有对应的配置项时,会使用预先输入的字段作为默认值。
# 3. 实现
# 3.1 灯光
在对应控件的 Plugins.cs 中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class AutoGain :IPlugin { ...; Control MainWnd;
LightController lightA; LightController lightB; CameraController camera; ...; }
|
在后续使用 light 的地方都替换为 lightA 和 lightB
如
1 2 3 4 5 6 7
| lightA.Intensity(1, intensity); lightB.Intensity(1, intensity); lightA.Intensity(2, intensity); lightB.Intensity(2, intensity); Console.WriteLine($"Set intensity:{intensity}");
|
接下来要关心的就是这些信息要如何自动保存和读取了
# 3.2 配置模块更新
# 3.2.1 配置文件结果预览
历时三天终于完成插件参数读取和保存功能,先放个目前配置文件的内容
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
| { "version": "0.1.1119.02", "Parameters": { "languageflag": 0, "threshold": 20.0, "sensitivity": 90.0, "ImageFormat": "bmp", "th_black_gray_l": 20.0, "thNum": 1, "save_raw": false, "save_200": true, "save_500": false }, "PluginParameters": { "AutoGain": { "COM_LIGHT_A": "COM4", "COM_LIGHT_B": "COM6", "LightLntensity": 125, "CameraGain": 0.5, "CameraAutoGain": false, "LightAutoAdjust": false }, "Alarm": { "Enable": false, "PortName": "COM3", "BaudRate": 34800, "Duration": 2000 } } }
|
现在是以 json 格式化保存各种参数,包括主程序的参数和各个插件功能的参数,其格式定义如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| { "version": "0.1.1119.02", "Parameters": { "languageflag": 0, "threshold": 20.0, ..., }, "PluginParameters": { "AutoGain": { "COM_LIGHT_A": "COM4", "COM_LIGHT_B": "COM6", ..., }, "Alarm": { "Enable": false, "PortName": "COM3", ..., } } }
|
实现方式:
每个插件都存在 Attributes 用于存储当前插件下的控制参数,同时在 config.cs 中定义 Settings 类用来辅助存储插件的控制参数和主程序的控制参数。然后由 config 模块实现运行时 Settings 装载,Settings 实例在保存过程中会被序列化为 json 字符串,然后保存到本地配置文件中,而在读取时会反序列化本地配置文件生成运行时 Settings 实例,当配置文件不存在时,会根据 AddAttr()中的 def 参数生成默认值的配置文件,当本地配置文件中没有对应的配置项时,会使用的 AddAttr()中的 def 参数作为该字段的默认值。
# 3.2.2 Settings 类定义
Settings 类的成员变量主要为主程序的配置项 Parameters 和 插件的配置项 PluginParameters
1 2 3 4 5 6 7 8 9 10
| public class Settings { public string Version; public Dictionary<string, object> Parameters = new Dictionary<string, object>();
public Dictionary<string, Dictionary<string, object>> PluginParameters = new Dictionary<string, Dictionary<string, object>>();
}
|
# 3.2.3 PluginTookits 模块
完善 PluginTookits 模块中的工具,便于插件加载和存储参数
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
|
public static void AddAttr(Dictionary<string, object> Attributes, string key, ref string value, string def) { ...; }
public static void AddAttr(Dictionary<string, object> Attributes, string key, ref int value, int def){ ...; } public static void AddAttr(Dictionary<string, object> Attributes, string key, ref bool value, bool def) { ...; }
public static void savAttr(object mainWnd, Dictionary<string, object> target, string pluginName, string config = "cfg", string type = "PluginParameters") { ...; }
public static void LoadAttr(ref Dictionary<string, object> Attributes, object MainWnd, string name) { ...; }
|
调用的时候,只需要在项目中添加 PluginToolkits 的引用就能使用 Toolkits.AddAttr ()、 Toolkits.savAttr ()、 Toolkits.LoadAttr () 等相关工具函数。
实现框架功能之后,还需要在插件中进行调用和实现。
# 3.2.3 主程序参数加载和保存
在 config 模块中,修改 load 函数
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
| public void load(string file = "./config.json") { if (file.Length > 0 && File.Exists(file)) { log._.Info($"loading configuration from file {file}"); string configString = ""; using (StreamReader sr = File.OpenText(file)) { configString = sr.ReadToEnd(); }
settings = JsonConvert.DeserializeObject<Settings>(configString);
Toolkits.AddAttr(settings.Parameters, "languageflag", ref languageflag, Default.Language); ...; Parameters = settings.Parameters; PluginParameters = settings.PluginParameters;
} else { log._.Warn($"File {file} not exists, using default configuration"); load_default(); settings = new Settings(); save(); } }
|
修改 save () 函数
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
| public void save(string file = "./config.json") { ...;
log._.Info($"saving configuration to file {file}");
settings.Version = version; settings.Parameters = Parameters; settings.PluginParameters = PluginParameters; string SettingsString = JsonConvert.SerializeObject(settings, Formatting.Indented); Console.WriteLine("writing settings ... "); log._.Info("writing settings ... "); using (FileStream fs = File.Open(file, FileMode.Create, FileAccess.Write, FileShare.None)) { byte[] content = new UTF8Encoding(true).GetBytes(SettingsString); fs.Write(content, 0, content.Length); }
log._.Info("save configuration complete."); completed = true; ...;
}
|
而在 load_default () 中
1 2 3 4 5 6 7 8 9 10 11
| private void load_default() { Toolkits.AddAttr(Parameters, "languageflag", ref languageflag, Default.Language); Toolkits.AddAttr(Parameters, "threshold", ref threshold, Default.threshold); ...;
PluginParameters = new Dictionary<string, Dictionary<string, object>>();
}
|
# 3.2.4 插件参数加载和保存
插件实现加载参数的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void Init(Control control = null) {
MainWnd = control; Dictionary<string, object> dic = new Dictionary<string, object>(); Toolkits.LoadAttr(ref dic,MainWnd, Name); Attributes = dic;
Toolkits.AddAttr(Attributes, "AutoGainVersion", ref version, Info.Version); Attributes["AutoGainVersion"] = Info.Version;
Toolkits.AddAttr(Attributes, "LightCOM_A", ref COM_LIGHT_A, "COMx"); Toolkits.AddAttr(Attributes, "LightCOM_B", ref COM_LIGHT_B, "COMx"); Toolkits.AddAttr(Attributes, "LightLntensity", ref intensity, 125); Toolkits.AddAttr(Attributes, "ThresholdMean", ref mean, 130); Toolkits.AddAttr(Attributes, "CameraGain", ref gain, 0.5); ...; }
|
插件实现保存参数的过程:
1 2 3 4 5
| public void OnDestory() { Toolkits.savAttr(MainWnd, Attributes, Name); ...; }
|
当框架实现支持之后,插件很容易就实现了参数的保存和读取,之后修改某些数值就不需要修改源代码和编译重新编译,只用在配置文件中修改对应字段的数值就可以了。