// 填充 Books 和 Patrons 每个元素的 .TagInfo public static int FillTagInfo(BaseChannel <IRfid> channel) { var news = Books; news.AddRange(Patrons); int count = 0; foreach (TagAndData data in news) { OneTag tag = data.OneTag; if (tag == null) { continue; } if (tag.TagInfo != null && data.Error == null) { continue; } if (tag.Protocol == InventoryInfo.ISO14443A) { continue; } if (tag.TagInfo == null) { // 自动重试一次 GetTagInfoResult gettaginfo_result = null; for (int i = 0; i < 2; i++) { gettaginfo_result = GetTagInfo(channel, tag.ReaderName, tag.UID, tag.AntennaID); if (gettaginfo_result.Value != -1) { break; } } if (gettaginfo_result.Value == -1) { data.Error = gettaginfo_result.ErrorInfo; continue; } else { if (string.IsNullOrEmpty(data.Error) == false) { data.Error = null; } } TagInfo info = gettaginfo_result.TagInfo; tag.TagInfo = info; count++; } } // end of foreach return(count); }
// (中间版本) // parameters: // readerNameList list中包含的内容的读卡器名(列表)。注意 list 中包含的标签,可能并不是全部读卡器的标签。对没有包含在其中的标签,本函数需要注意跳过(维持现状),不要当作被删除处理 // 异常: // 可能抛出 TagInfoException public static void Refresh(BaseChannel <IRfid> channel, string readerNameList, List <OneTag> list, delegate_notifyChanged notifyChanged, delegate_setError setError, delegate_detectType detectType = null) { try { setError?.Invoke("rfid", null); List <TagAndData> new_books = new List <TagAndData>(); List <TagAndData> new_patrons = new List <TagAndData>(); List <TagAndData> error_books = new List <TagAndData>(); List <TagAndData> error_patrons = new List <TagAndData>(); // 从当前列表中发现已有的图书。用于交叉运算 List <TagAndData> found_books = new List <TagAndData>(); // 从当前列表中发现已有的读者。用于交叉运算 List <TagAndData> found_patrons = new List <TagAndData>(); // 即便是发现已经存在 UID 的标签,也要再判断一下 Antenna 是否不同。如果有不同,要进行变化通知 // 从当前列表中发现(除了 UID) 内容有变化的图书。这些图书也会进入 found_books 集合 List <TagAndData> changed_books = new List <TagAndData>(); foreach (OneTag tag in list) { // 检查以前的列表中是否已经有了 var book = FindBookTag(tag.UID); if (book != null) { found_books.Add(book); if (book.OneTag.AntennaID != tag.AntennaID) { // 修改 AntennaID book.OneTag.AntennaID = tag.AntennaID; changed_books.Add(book); } if (string.IsNullOrEmpty(book.Error) == false) { error_books.Add(book); } continue; } var patron = FindPatronTag(tag.UID); if (patron != null) { found_patrons.Add(patron); if (string.IsNullOrEmpty(patron.Error) == false) { error_patrons.Add(patron); } continue; } // 原来的行为 if (detectType == null) { // ISO14443A 的一律当作读者证卡 if (tag.Protocol == InventoryInfo.ISO14443A) { patron = new TagAndData { OneTag = tag, Type = "patron" }; new_patrons.Add(patron); } else { // 根据缓存的 typeOfUsage 来判断 string typeOfUsage = (string)_typeTable[tag.UID]; if (typeOfUsage != null && typeOfUsage.StartsWith("8")) { patron = new TagAndData { OneTag = tag, Type = "patron" }; new_patrons.Add(patron); found_books.Remove(patron); } else { // ISO15693 的则先添加到 _books 中。等类型判断完成,有可能还要调整到 _patrons 中 book = new TagAndData { OneTag = tag }; new_books.Add(book); } } } else { // *** 按照定制函数来进行类别分析 string type = detectType(tag); if (type == "patron") { var new_data = new TagAndData { OneTag = tag, Type = "patron" }; new_patrons.Add(new_data); // TODO: 按照 UID 移走 found_books.Remove(new_data); } else { // "book" or "" var new_data = new TagAndData { OneTag = tag, Type = "" }; new_books.Add(new_data); // TODO: 按照 UID 移走 found_patrons.Remove(new_data); } } } List <TagAndData> remove_books = new List <TagAndData>(); List <TagAndData> remove_patrons = new List <TagAndData>(); // 交叉运算 // 注意对那些在 readerNameList 以外的标签不要当作 removed 处理 foreach (TagAndData book in _books) { if (InRange(book, readerNameList) == false) { continue; } if (found_books.IndexOf(book) == -1) { remove_books.Add(book); } } foreach (TagAndData patron in _patrons) { if (InRange(patron, readerNameList) == false) { continue; } if (found_patrons.IndexOf(patron) == -1) { remove_patrons.Add(patron); } } bool array_changed = false; // 兑现添加 lock (_sync_books) { foreach (TagAndData book in new_books) { if (_books.IndexOf(book) == -1) { _books.Add(book); array_changed = true; } } // 兑现删除 foreach (TagAndData book in remove_books) { _books.Remove(book); array_changed = true; } } lock (_sync_patrons) { foreach (TagAndData patron in new_patrons) { if (_patrons.IndexOf(patron) == -1) { _patrons.Add(patron); array_changed = true; } } foreach (TagAndData patron in remove_patrons) { _patrons.Remove(patron); array_changed = true; } } // 通知一次变化 if (array_changed || changed_books.Count > 0 || new_books.Count > 0 || remove_books.Count > 0 || new_patrons.Count > 0 || remove_patrons.Count > 0) // 2019/8/15 优化 { notifyChanged(new_books, changed_books, remove_books, new_patrons, null, remove_patrons); } // 需要获得 Tag 详细信息的。注意还应当包含以前出错的 Tag //List<TagAndData> news = new_books; // news.AddRange(error_books); List <TagAndData> news = new List <TagAndData>(); news.AddRange(_books); news.AddRange(new_patrons); new_books = new List <TagAndData>(); remove_books = new List <TagAndData>(); new_patrons = new List <TagAndData>(); remove_patrons = new List <TagAndData>(); // .TagInfo 是否发生过填充 bool taginfo_changed = false; { List <TagAndData> update_books = new List <TagAndData>(); List <TagAndData> update_patrons = new List <TagAndData>(); // 逐个获得新发现的 ISO15693 标签的详细数据,用于判断图书/读者类型 foreach (TagAndData data in news) { OneTag tag = data.OneTag; if (tag == null) { continue; } if (tag.TagInfo != null && data.Error == null) { continue; } if (tag.Protocol == InventoryInfo.ISO14443A) { continue; } { /* * // TODO * GetTagInfoResult gettaginfo_result = null; * if (tag.InventoryInfo == null) * gettaginfo_result = GetTagInfo(channel, tag.UID); * else * gettaginfo_result = GetTagInfo(channel, tag.InventoryInfo); */ // 自动重试一次 GetTagInfoResult gettaginfo_result = null; for (int i = 0; i < 2; i++) { gettaginfo_result = GetTagInfo(channel, tag.ReaderName, tag.UID, tag.AntennaID); if (gettaginfo_result.Value != -1) { break; } } if (gettaginfo_result.Value == -1) { setError?.Invoke("rfid", gettaginfo_result.ErrorInfo); // TODO: 是否直接在标签上显示错误文字? data.Error = gettaginfo_result.ErrorInfo; if (data.Type == "patron") { update_patrons.Add(data); } else { update_books.Add(data); } continue; } else { if (string.IsNullOrEmpty(data.Error) == false) { data.Error = null; if (data.Type == "patron") { update_patrons.Add(data); } else { update_books.Add(data); } } } TagInfo info = gettaginfo_result.TagInfo; // 记下来。避免以后重复再次去获取了 if (tag.TagInfo == null) { tag.TagInfo = info; taginfo_changed = true; // 2019/8/25 if (data.Type == "patron") { if (update_patrons.IndexOf(data) == -1) { update_patrons.Add(data); } } else { /* * if (update_books.IndexOf(data) == -1) * update_books.Add(data); */ } } // 对于不确定类型的标签(data.Type 为空的),再次确定类型以便分离 ISO15693 图书标签和读者卡标签 if (string.IsNullOrEmpty(data.Type)) { // 原来的行为 if (detectType == null) { LogicChip chip = null; string typeOfUsage = ""; try { // 观察 typeOfUsage 元素 // Exception: // 可能会抛出异常 ArgumentException TagDataException chip = LogicChip.From(info.Bytes, (int)info.BlockSize, ""); typeOfUsage = chip.FindElement(ElementOID.TypeOfUsage)?.Text; } catch (TagDataException ex) { // throw new TagInfoException(ex.Message, info); // 解析错误的标签,当作图书标签处理 typeOfUsage = ""; } if (typeOfUsage != null && typeOfUsage.StartsWith("8")) { // 需要调整到 _patrons 中 data.Type = "patron"; // 删除列表? 同时添加列表 remove_books.Add(data); update_books.Remove(data); // 容错 new_patrons.Add(data); } else { data.Type = "book"; update_books.Add(data); update_patrons.Remove(data); } // 保存到缓存 if (typeOfUsage != null) { if (_typeTable.Count > 1000) { _typeTable.Clear(); } _typeTable[data.OneTag.UID] = typeOfUsage; } } else { // *** 用定制的函数判断 string new_type = detectType(tag); // 重新分离 ISO15693 图书标签和读者卡标签 if (data.Type != new_type) { if (new_type == "patron") { // book --> patron // 需要调整到 _patrons 中 data.Type = "patron"; // 删除列表? 同时添加列表 remove_books.Add(data); update_books.Remove(data); // 容错 //new_patrons.Add(data); update_patrons.Add(data); } if (new_type == "book") { // patron --> book data.Type = "book"; /* * update_books.Add(data); * update_patrons.Remove(data); */ remove_patrons.Add(data); update_patrons.Remove(data); update_books.Add(data); } } } } } } // end of foreach array_changed = false; // 再次兑现添加和删除 // 兑现添加 lock (_sync_books) { foreach (TagAndData book in new_books) { _books.Add(book); array_changed = true; } // 兑现删除 foreach (TagAndData book in remove_books) { _books.Remove(book); array_changed = true; } } lock (_sync_patrons) { foreach (TagAndData patron in new_patrons) { _patrons.Add(patron); array_changed = true; } foreach (TagAndData patron in remove_patrons) { _patrons.Remove(patron); array_changed = true; } } // 再次通知变化 if (array_changed == true || taginfo_changed == true || new_books.Count > 0 || update_books.Count > 0 || remove_books.Count > 0 || new_patrons.Count > 0 || update_patrons.Count > 0 || remove_patrons.Count > 0) // 2019/8/15 优化 { notifyChanged(new_books, update_books, remove_books, new_patrons, update_patrons, remove_patrons); } } } finally { _dataReady = true; } }
// parameters: // readerNameList list中包含的内容的读卡器名(列表)。注意 list 中包含的标签,可能并不是全部读卡器的标签。对没有包含在其中的标签,本函数需要注意跳过(维持现状),不要当作被删除处理 // 异常: // public static void Refresh(// BaseChannel<IRfid> channel, string readerNameList, List <OneTag> list_param, delegate_getTagInfo getTagInfo, delegate_notifyChanged notifyChanged, delegate_setError setError) { setError?.Invoke("rfid", null); // 对 list 里面的元素要按照天线号进行过滤 // 注:这样过滤主要是为了防范 shelf.xml 对 M201 这样的没有多天线的配置了多个天线用于多个门,引起这里算法故障(在 Tags 中填充很多重复 UID 的对象) // 由于 RfidCenter 中 ListTags() 对于 M201 这样的读卡器没有严格过滤天线号,所以会有上述问题 // 若加固了 RfidCenter 以后,这一段过滤代码可以省略,以便提高执行速度 List <OneTag> list = new List <OneTag>(); foreach (OneTag tag in list_param) { if (InRange(tag, readerNameList) == false) { continue; } list.Add(tag); } List <TagAndData> new_books = new List <TagAndData>(); List <TagAndData> error_books = new List <TagAndData>(); // 从当前列表中发现已有的图书。用于交叉运算 List <TagAndData> found_books = new List <TagAndData>(); // 即便是发现已经存在 UID 的标签,也要再判断一下 Antenna 是否不同。如果有不同,要进行变化通知 // 从当前列表中发现(除了 UID) 内容有变化的图书。这些图书也会进入 found_books 集合 List <TagAndData> changed_books = new List <TagAndData>(); foreach (OneTag tag in list) { // 检查以前的列表中是否已经有了 var book = FindBookTag(tag.UID); /* * // 2020/4/19 验证性做法:从一个读卡器变动到另一个读卡器,第一种顺序,瞬间集合里面可能会有相同 UID 的两个对象 * // 用 Test_transfer_test_1() 单元测试 * // 如果找到的对象是属于当前读卡器以外的范围,则当作没有找到处理 * if (book != null && InRange(book.OneTag, readerNameList) == false) * book = null; */ if (book != null) { found_books.Add(book); if (book.OneTag.AntennaID != tag.AntennaID || book.OneTag.ReaderName != tag.ReaderName) { var onetag = book.OneTag; // 修改 AntennaID onetag.AntennaID = tag.AntennaID; onetag.ReaderName = tag.ReaderName; if (onetag.TagInfo != null) { /* * // TODO: 这里还有个做法,就是干脆把 .TagInfo 设置为 null。这会导致重新获取 TagInfo(所谓两阶段) * onetag.TagInfo = null; * ClearTagTable(onetag.UID); */ onetag.TagInfo.AntennaID = tag.AntennaID; onetag.TagInfo.ReaderName = tag.ReaderName; // 只清理缓存 _tagTable.Remove(onetag.UID); } changed_books.Add(book); } if (string.IsNullOrEmpty(book.Error) == false) { error_books.Add(book); } continue; } // ISO15693 的则先添加到 _books 中。等类型判断完成,有可能还要调整到 _patrons 中 book = new TagAndData { OneTag = tag }; new_books.Add(book); // 2020/4/19 // 对于新加入的标签,只清理缓存。防止以前残留的 cache 信息污染 _tagTable.Remove(tag.UID); } List <TagAndData> remove_books = new List <TagAndData>(); // 交叉运算 // 注意对那些在 readerNameList 以外的标签不要当作 removed 处理 foreach (TagAndData book in _tags) { if (InRange(book.OneTag, readerNameList) == false) { continue; } if (found_books.IndexOf(book) == -1) { remove_books.Add(book); } } bool array_changed = false; // 兑现添加 lock (_sync_tags) { foreach (TagAndData book in new_books) { if (_tags.IndexOf(book) == -1) { _tags.Add(book); array_changed = true; } } // 兑现删除 foreach (TagAndData book in remove_books) { _tags.Remove(book); array_changed = true; } } // 通知一次变化 if (array_changed || changed_books.Count > 0 || new_books.Count > 0 || remove_books.Count > 0) { notifyChanged?.Invoke(new_books, changed_books, remove_books); } List <TagAndData> news = new List <TagAndData>(); news.AddRange(_tags); new_books = new List <TagAndData>(); remove_books = new List <TagAndData>(); // .TagInfo 是否发生过填充 bool taginfo_changed = false; { List <TagAndData> update_books = new List <TagAndData>(); // 逐个获得新发现的 ISO15693 标签的详细数据,用于判断图书/读者类型 foreach (TagAndData data in news) { OneTag tag = data.OneTag; if (tag == null) { continue; } if (tag.TagInfo != null && data.Error == null) { continue; } if (tag.Protocol == InventoryInfo.ISO14443A) { continue; } if (getTagInfo != null) { // 自动重试一次 GetTagInfoResult gettaginfo_result = null; for (int i = 0; i < 2; i++) { // gettaginfo_result = GetTagInfo(channel, tag.ReaderName, tag.UID, tag.AntennaID); gettaginfo_result = GetTagInfo(getTagInfo, tag.ReaderName, tag.UID, tag.AntennaID); if (gettaginfo_result.Value != -1) { break; } } if (gettaginfo_result.Value == -1) { setError?.Invoke("rfid", gettaginfo_result.ErrorInfo); // TODO: 是否直接在标签上显示错误文字? data.Error = gettaginfo_result.ErrorInfo; update_books.Add(data); continue; } else { if (string.IsNullOrEmpty(data.Error) == false) { data.Error = null; update_books.Add(data); } } TagInfo info = gettaginfo_result.TagInfo; // 记下来。避免以后重复再次去获取了 if (tag.TagInfo == null && info != null) { tag.TagInfo = info; taginfo_changed = true; { if (update_books.IndexOf(data) == -1) { update_books.Add(data); } } } } } // end of foreach array_changed = false; // 再次兑现添加和删除 // 兑现添加 lock (_sync_tags) { foreach (TagAndData book in new_books) { _tags.Add(book); array_changed = true; } // 兑现删除 foreach (TagAndData book in remove_books) { _tags.Remove(book); array_changed = true; } } // 再次通知变化 if (array_changed == true || taginfo_changed == true || new_books.Count > 0 || update_books.Count > 0 || remove_books.Count > 0) { notifyChanged?.Invoke(new_books, update_books, remove_books); } } }