public Entity OffShelf(TagAndData data) { if (data.OneTag.TagInfo == null) { return(null); } string pii = GetPII(data.OneTag.TagInfo); if (string.IsNullOrEmpty(pii)) { return(null); } var entity = FindEntityByPII(pii); if (entity == null) { return(null); } entity.OnShelf = false; // TODO: 如果本来就不是当前馆藏地的(被误放进来的),要从列表中删除 if (entity.BelongToCurrentShelf == false) { this.Remove(entity); } return(entity); }
// 放到架上 public Entity OnShelf(TagAndData data) { if (data.OneTag.TagInfo == null) { return(null); } string pii = GetPII(data.OneTag.TagInfo); if (string.IsNullOrEmpty(pii)) { return(null); } var entity = FindEntityByPII(pii); if (entity != null) { // 馆藏地属于本书架的图书 entity.BelongToCurrentShelf = true; } else { // 这是馆藏地不属于本书架的图书 entity = Add(data, true); entity.BelongToCurrentShelf = false; } entity.OnShelf = true; entity.UID = data.OneTag.UID; return(entity); }
public Entity Add(TagAndData data, bool auto_update = true) { // 查重 Entity entity = FindEntity(data.OneTag.UID); if (entity != null) { if (auto_update) { Update(data); } return(entity); } entity = new Entity { Container = this, UID = data.OneTag.UID, TagInfo = data.OneTag.TagInfo }; this.Add(entity); SetPII(entity); entity.SetError(data.Error); return(entity); }
// 更新一个事项内容 // return: // null 没有找到 // 其他 找到并更新了 public Entity Update(TagAndData data, bool auto_add = true) { Entity entity = FindEntity(data.OneTag.UID); if (entity == null) { if (auto_add) { return(Add(data, false)); } return(null); } if (data.OneTag != null && data.OneTag.TagInfo != null && entity.TagInfo == null) { entity.TagInfo = data.OneTag.TagInfo; } else if (data.OneTag != null && data.OneTag?.TagInfo == null && entity.TagInfo != null) { entity.TagInfo = null; entity.PII = null; entity.FillFinished = false; } SetPII(entity); // 如何触发下一步的获取和显示? entity.SetError(data.Error); return(entity); }
public Entity Add(TagAndData data, bool auto_update = true) { // 查重 Entity entity = FindEntityByUID(data.OneTag.UID); if (entity != null) { if (auto_update) { Update(data); } return(entity); } entity = new Entity { Container = this, UID = data.OneTag.UID, Antenna = data.OneTag.AntennaID.ToString(), ReaderName = data.OneTag.ReaderName, TagInfo = data.OneTag.TagInfo, }; this.Add(entity); // Exception: // 可能会抛出异常 ArgumentException SetPII(entity); if (string.IsNullOrEmpty(data.Error) == false) { entity.AppendError(data.Error); } return(entity); }
void ProcessTag(TagAndData tag) { var entity = InventoryData.AddEntity(tag, out bool isNewly); var info = entity.Tag as ProcessInfo; if (info == null) { info = new ProcessInfo(); entity.Tag = info; } if (isNewly) { App.Invoke(new Action(() => { _entities.Add(entity); })); } if (string.IsNullOrEmpty(entity.PII) == false && string.IsNullOrEmpty(info.State)) { info.State = "processing"; InventoryData.AppendList(entity); InventoryData.ActivateInventory(); } }
// 添加一个新行 ListViewItem AddItem(TagAndData tag) { ListViewItem item = new ListViewItem(); this.listView_tags.Items.Add(item); RefreshItem(item, tag); return(item); }
// 移走一行 void RemoveItem(TagAndData tag) { var item = ListViewUtil.FindItem(this.listView_tags, tag.OneTag.UID, COLUMN_UID); if (item == null) { return; } this.listView_tags.Items.Remove(item); }
// 更新一行内容 ListViewItem UpdateItem(TagAndData tag) { var item = ListViewUtil.FindItem(this.listView_tags, tag.OneTag.UID, COLUMN_UID); if (item == null) { return(AddItem(tag)); } RefreshItem(item, tag); return(item); }
// 更新一个事项内容 // return: // null 没有找到 // 其他 找到并更新了 public Entity Update(TagAndData data, bool auto_add = true) { Entity entity = FindEntityByUID(data.OneTag.UID); if (entity == null) { if (auto_add) { return(Add(data, false)); } return(null); } if (data.OneTag != null && data.OneTag.TagInfo != null && entity.TagInfo == null) { entity.TagInfo = data.OneTag.TagInfo; } else if (data.OneTag != null && data.OneTag?.TagInfo == null && entity.TagInfo != null) { entity.TagInfo = null; entity.PII = null; entity.FillFinished = false; } // 2019/9/29 if (data.OneTag != null) { var id = data.OneTag.AntennaID.ToString(); if (entity.Antenna != id) { entity.Antenna = id; } var readerName = data.OneTag.ReaderName; if (entity.ReaderName != readerName) { entity.ReaderName = readerName; } } // Exception: // 可能会抛出异常 ArgumentException SetPII(entity); // 如何触发下一步的获取和显示? entity.AppendError(data.Error); return(entity); }
public static Entity AddEntity(TagAndData tag, out bool isNewly) { if (_entityTable.ContainsKey(tag.OneTag.UID)) { // TODO: 更新 tagInfo isNewly = false; Entity result = _entityTable[tag.OneTag.UID] as Entity; InventoryData.NewEntity(tag, result, false); return(result); } var entity = InventoryData.NewEntity(tag, null, false); _entityTable[entity.UID] = entity; isNewly = true; return(entity); }
void RefreshItem(ListViewItem item, TagAndData tag) { string pii = ""; var taginfo = tag.OneTag.TagInfo; if (taginfo != null) { // Exception: // 可能会抛出异常 ArgumentException TagDataException var chip = LogicChip.From(taginfo.Bytes, (int)taginfo.BlockSize, ""); pii = chip.FindElement(ElementOID.PII)?.Text; } ListViewUtil.ChangeItemText(item, COLUMN_UID, tag.OneTag.UID); ListViewUtil.ChangeItemText(item, COLUMN_PII, pii); ListViewUtil.ChangeItemText(item, COLUMN_PROTOCOL, tag.OneTag.Protocol); ListViewUtil.ChangeItemText(item, COLUMN_ANTENNA, tag.OneTag.AntennaID.ToString()); }
// Exception: // 可能会抛出异常 ArgumentException TagDataException static void SetTagType(TagAndData data, out string pii, out LogicChip chip) { pii = null; chip = null; if (data.OneTag.Protocol == InventoryInfo.ISO14443A) { data.Type = "patron"; return; } if (data.OneTag.TagInfo == null) { data.Type = ""; // 表示类型不确定 return; } if (string.IsNullOrEmpty(data.Type)) { // Exception: // 可能会抛出异常 ArgumentException TagDataException chip = LogicChip.From(data.OneTag.TagInfo.Bytes, (int)data.OneTag.TagInfo.BlockSize, "" // tag.TagInfo.LockStatus ); pii = chip.FindElement(ElementOID.PII)?.Text; var typeOfUsage = chip.FindElement(ElementOID.TypeOfUsage)?.Text; if (typeOfUsage != null && typeOfUsage.StartsWith("8")) { data.Type = "patron"; } else { data.Type = "book"; } } }
void ProcessTag(BaseChannel <IRfid> channel, TagAndData tag) { var entity = InventoryData.AddEntity(tag, out bool isNewly); var info = entity.Tag as ProcessInfo; if (info == null) { info = new ProcessInfo(); entity.Tag = info; } if (isNewly) { App.Invoke(new Action(() => { _entities.Add(entity); })); } FillEntity(channel, entity); }
// TODO: 可以把 readerNameList 先 Parse 到一个结构来加快 match 速度 static bool InRange(TagAndData data, string readerNameList) { // 匹配读卡器名字 var ret = Reader.MatchReaderName(readerNameList, data.OneTag.ReaderName, out string antenna_list); if (ret == false) { return(false); } var list = GetAntennaList(antenna_list); // 2019/12/19 // 如果列表为空,表示不指定天线编号,所以任何 data 都是匹配命中的 // RL8600 默认天线编号为 0;M201 默认天线编号为 1。列表为空的情况表示不指定天线编号有助于处理好这两种不同做法的读写器 if (list.Count == 0) { return(true); } if (list.IndexOf(data.OneTag.AntennaID) != -1) { return(true); } return(false); // ret is bug!!! }
public static void Refresh(BaseChannel <IRfid> channel, List <OneTag> list, delegate_notifyChanged notifyChanged, delegate_setError setError) { 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>(); foreach (OneTag tag in list) { // 检查以前的列表中是否已经有了 var book = FindBookTag(tag.UID); if (book != null) { found_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; } // 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); } } } List <TagAndData> remove_books = new List <TagAndData>(); List <TagAndData> remove_patrons = new List <TagAndData>(); // 交叉运算 foreach (TagAndData book in _books) { if (found_books.IndexOf(book) == -1) { remove_books.Add(book); } } foreach (TagAndData patron in _patrons) { 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 || new_books.Count > 0 || remove_books.Count > 0 || new_patrons.Count > 0 || remove_patrons.Count > 0) // 2019/8/15 优化 { notifyChanged(new_books, null, 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; } { var gettaginfo_result = GetTagInfo(channel, tag.UID); 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); */ } } // 观察 typeOfUsage 元素 var chip = LogicChip.From(info.Bytes, (int)info.BlockSize, ""); string typeOfUsage = chip.FindElement(ElementOID.TypeOfUsage)?.Text; // 分离 ISO15693 图书标签和读者卡标签 if (string.IsNullOrEmpty(data.Type)) { 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; } } } } // 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); } } }
// 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); } #if NO 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); } } #endif }
// 注:所创建的 Entity 对象其 Error 成员可能有值,表示有出错信息 // Exception: // 可能会抛出异常 ArgumentException static Entity NewEntity(TagAndData tag, Entity entity, bool throw_exception = true) { Entity result = entity; if (result == null) { result = new Entity { UID = tag.OneTag.UID, ReaderName = tag.OneTag.ReaderName, Antenna = tag.OneTag.AntennaID.ToString(), TagInfo = tag.OneTag.TagInfo, }; } LogicChip chip = null; if (string.IsNullOrEmpty(tag.Type)) { // Exception: // 可能会抛出异常 ArgumentException TagDataException try { SetTagType(tag, out string pii, out chip); result.PII = pii; } catch (Exception ex) { App.CurrentApp.SpeakSequence("警告: 标签解析出错"); if (throw_exception == false) { result.AppendError($"RFID 标签格式错误: {ex.Message}", "red", "parseTagError"); } else { throw ex; } } } #if NO // Exception: // 可能会抛出异常 ArgumentException EntityCollection.SetPII(result, pii); #endif // 2020/4/9 if (tag.Type == "patron") { // 避免被当作图书同步到 dp2library result.PII = "(读者卡)" + result.PII; result.AppendError("读者卡误放入书柜", "red", "patronCard"); } // 2020/7/15 // 获得图书 RFID 标签的 OI 和 AOI 字段 if (tag.Type == "book") { if (chip == null) { // Exception: // 可能会抛出异常 ArgumentException TagDataException chip = LogicChip.From(tag.OneTag.TagInfo.Bytes, (int)tag.OneTag.TagInfo.BlockSize, "" // tag.TagInfo.LockStatus ); } string oi = chip.FindElement(ElementOID.OI)?.Text; string aoi = chip.FindElement(ElementOID.AOI)?.Text; result.OI = oi; result.AOI = aoi; // 2020/8/27 // 严格要求必须有 OI(AOI) 字段 if (string.IsNullOrEmpty(oi) && string.IsNullOrEmpty(aoi)) { result.AppendError("没有 OI 或 AOI 字段", "red", "missingOI"); } } return(result); }
// (中间版本) // 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; } }