Example #1
0
File: TagList.cs Project: zgren/dp2
        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;
                        }

                        // 观察 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);
                }
            }
        }
Example #2
0
        // 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
        }
Example #3
0
File: TagList.cs Project: zgren/dp2
        // (中间版本)
        // 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;
            }
        }