吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 457|回复: 15
上一主题 下一主题
收起左侧

[C&C++ 原创] C++半导体SECS/GEM开源库

[复制链接]
跳转到指定楼层
楼主
TokeyJs 发表于 2026-5-7 21:29 回帖奖励
本帖最后由 TokeyJs 于 2026-5-8 21:22 编辑

C++半导体SECS/GEM开源库(E30目前还未实现,后续计划去实现)。
TinySECSGem (https://github.com/tokeyjs/TinySECSGem)是一个面向半导体设备端与上位机端的轻量级 Windows C++ SECS/HSMS 通信库(TCP通信底层使用HPSocket库)。
当前版本聚焦于通信层:
SEMI E37 / HSMS-SS 传输与会话行为
SEMI E5 / SECS-II 消息序列化、解析与 Item Tree 数据模型
SEMI E30 中的 GEM 行为特性仍处于规划阶段,当前版本尚未实现。TinySECSGem 适合用于构建 SECS 消息收发、集成原型、Host 侧工具和设备侧通信服务,但目前不具备完整 GEM 设备行为模型。

最近工作有涉及到SECS,发现CPP的开源库几乎没有,所以在空闲时间根据E37,E5等协议标准开发了此库,在代码完成差不多的时候还使用AI进行代码审查等辅助工作(目前AI真的好用呀,好多小bug都能发现,并且效率还高!)。
欢迎大佬给库提点建议!!!

主要功能:目前库版本已满足半导体SECS E37 E5标准,已经可以用来开发SECS项目使用,已经完成了通信底层数据解析与数据组装功能。其实现在未实现的E30标准也只是在此基础上增加一些应用层面的功能特性。
E5协议主要是数据结构的序列化与反序列化:本库将SECS数据body解析成一棵树的结构,实现E5标准中的ListItem、BinaryItem、ASCIIItem、BooleanItem、UInt4ByteItem等基础数据结构类型,这些Item都继承自BaseItem,不同数据类型的序列化与非序列化都由各自类进行实现。
下面贴一些BaseItem和ListItem类的代码:
[C++] 纯文本查看 复制代码
//=====BaseItem.h===
#pragma once
#include<vector>
#include<string>
#include<cstdint>
#include "TinySECSGem.h"

namespace TinySECSGem 
{
        class BinaryItem;
        class BooleanItem;
        class ASCIIItem;
        class UnicodeItem;
        class JIS8Item;
        class Int1ByteItem;
        class Int2ByteItem;
        class Int4ByteItem;
        class Int8ByteItem;
        class UInt1ByteItem;
        class UInt2ByteItem;
        class UInt4ByteItem;
        class UInt8ByteItem;
        class Float4ByteItem;
        class Float8ByteItem;
        class ListItem;


    /**
    * @brief SECS-II数据项抽象基类
    *
    * 该类定义了SECS/GEM协议中所有SECS-II数据项的统一抽象接口,
    * 用于表示标准SECS数据结构中的任意数据节点,包括基础类型、
    * 数组类型以及复合结构(LIST)类型等。
    *
    * 所有具体SECS-II数据类型(如ASCII、U1、U2、LIST等)均继承自该类实现。
    */
    class TinySECSGEM_API BaseItem
    {
    protected:
        EnumSECSItemType m_eItemType;   ///< SECS-II数据类型标识(如ASCII/U1/U2/LIST等)

    public:

        /**
         * @brief 构造BaseItem对象
         */
        BaseItem();

        /**
         * @brief 析构BaseItem对象
         */
        virtual ~BaseItem();

        /**
         * @brief 获取当前数据项序列化后的总字节大小
         * @Return 当前数据项占用的字节数(包含子节点)
         */
        virtual size_t totalByteSize() const = 0;

        /**
         * @brief 获取当前数据项数组元素数量
         * @return 数组元素个数
         */
        virtual size_t GetArraySize() const = 0;

        /**
         * @brief 清空当前数据内容
         */
        virtual void clear() = 0;

        /**
         * @brief 深拷贝当前数据项对象
         * @return 返回新创建的对象副本(调用方负责释放内存)
         */
        virtual BaseItem* clone() = 0;

        /**
         * @brief 将当前数据结构转换为可读字符串(调试用途)
         * @Param frontStr 输出前缀(用于缩进格式化)
         * @return 格式化后的字符串表示
         */
        virtual std::string print(std::string frontStr = "") const = 0;

        /**
         * @brief 序列化当前数据项为SECS-II字节流
         * @param buff 输出缓冲区
         * @param buffSize 缓冲区大小
         * @return 实际写入的字节数
         */
        virtual int Serialization(BYTE* buff, size_t buffSize) = 0;

        /**
         * @brief 从SECS-II字节流反序列化数据项
         * @param startBufPos 起始缓冲区指针
         * @param endBufPos 结束缓冲区指针(buf不包括endBufPos)
         * @param bOk 输出参数,表示解析是否成功
         * @return 解析后的BaseItem对象指针(失败返回nullptr)
         */
        static BaseItem* Deserialization(BYTE* startBufPos, BYTE* endBufPos, bool& bOk);

        /**
         * @brief 解析SECS-II数据项头部信息
         *
         * 用于解析数据项格式类型及长度信息(Item Header)
         *
         * @param bufStart 起始缓冲区指针
         * @param bufEnd 结束缓冲区指针(buf不包括bufEnd位置)
         * @param format 输出数据类型格式
         * @param lengthByteSize 输出长度字段所占字节数
         * @param lengthByte 输出数据长度值
         * @return true 解析成功
         * @return false 解析失败
         */
        static bool DeserializationItemHeader(
            BYTE* bufStart,
            BYTE* bufEnd,
            EnumSECSItemType& format,
            size_t& lengthByteSize,
            size_t& lengthByte);

        /**
         * @brief 序列化SECS-II数据项头部信息
         *
         * 将数据类型及长度信息编码为SECS-II Item Header格式
         *
         * @param bufStart 输出缓冲区起始位置
         * @param bufEnd 输出缓冲区结束位置(buf不包括BufEnd)
         * @param format 数据类型格式
         * @param singleTypeSize 单个元素大小
         * @param arraySize 数组元素数量
         * @return 写入的字节数
         */
        static int SerializationItemHeader(
            BYTE* bufStart,
            BYTE* bufEnd,
            EnumSECSItemType format,
            size_t singleTypeSize,
            size_t arraySize);

        /**
         * @brief 获取当前数据项格式类型
         * @return EnumSECSItemType 当前SECS-II数据类型
         */
        EnumSECSItemType getFormat() const;

        /**
         * @brief 类型安全转换为指定派生类型
         * @tparam T 目标类型
         * @return 转换成功返回指针,否则返回nullptr
         */
        template<typename T>
        T* as() {
            return dynamic_cast<T*>(this);
        }

        /**
         * @brief const版本类型安全转换
         */
        template<typename T>
        const T* as() const {
            return dynamic_cast<const T*>(this);
        }

        /**
         * @brief 判断当前对象是否为指定类型
         * @tparam T 目标类型
         * @return true 类型匹配
         * @return false 类型不匹配
         */
        template<typename T>
        bool is() const {
            return dynamic_cast<const T*>(this) != nullptr;
        }
    };

}



//=====BaseItem.cpp===

#include "BaseItem.h"
#include "BinaryItem.h"
#include "BooleanItem.h"
#include "ASCIIItem.h"
#include "UnicodeItem.h"
#include "JIS8Item.h"
#include "Int1ByteItem.h"
#include "Int2ByteItem.h"
#include "Int4ByteItem.h"
#include "Int8ByteItem.h"
#include "UInt1ByteItem.h"
#include "UInt2ByteItem.h"
#include "UInt4ByteItem.h"
#include "UInt8ByteItem.h"
#include "Float4ByteItem.h"
#include "Float8ByteItem.h"
#include "ListItem.h"
#include "TopItem.h"



TinySECSGem::BaseItem::BaseItem()
    : m_eItemType(EnumSECSItemType::ItemType_UNKNOW)
{
}

TinySECSGem::BaseItem::~BaseItem() 
{ 
}


bool TinySECSGem::BaseItem::DeserializationItemHeader(BYTE* bufStart, BYTE* bufEnd, EnumSECSItemType& format, size_t& lengthByteSize, size_t& lengthByte)
{
    size_t index = 0;
    if (bufEnd <= bufStart || !bufStart || !bufEnd)
        return false;
    
    format = (EnumSECSItemType)(bufStart[index] >> 2); 
    lengthByteSize = (bufStart[index] & 0x3); 
    index++;
    if ((bufEnd - bufStart) < (1 + lengthByteSize)
        || lengthByteSize == 0)
        return false;
    lengthByte = 0;
    lengthByte = bufStart[index++];
    if (lengthByteSize >= 2)
    {
        lengthByte <<= 8;
        lengthByte |= bufStart[index++];
    }
    if (lengthByteSize == 3)
    {
        lengthByte <<= 8;
        lengthByte |= bufStart[index++];
    }
    return true;
}

int TinySECSGem::BaseItem::SerializationItemHeader(BYTE* bufStart, BYTE* bufEnd, EnumSECSItemType format, size_t singleTypeSize, size_t arraySize)
{
    if (!bufStart || !bufEnd || bufEnd - bufStart < 2)
        return -1; 
    size_t index = 0;
    BYTE lengthByteSize = 0;
    unsigned int length = arraySize * singleTypeSize;
    bufStart[index] = (BYTE)format;
    bufStart[index] <<= 2;

    if (length <= 0xFFU)
    {
        lengthByteSize = 1;
        bufStart[index] |= lengthByteSize;
        index++;
        if (bufEnd - bufStart < 1 + lengthByteSize)
            return -1;
        bufStart[index++] = (length & 0xFFU);
    }
    else if (length <= 0xFFFFU)
    {
        lengthByteSize = 2;
        bufStart[index] |= lengthByteSize;
        index++;
        if (bufEnd - bufStart < 1 + lengthByteSize)
            return -1;
        bufStart[index++] = ((length >> 8) & 0xFFU);
        bufStart[index++] = (length & 0xFFU);
    }
    else if (length <= 0xFFFFFFU)
    {
        lengthByteSize = 3;
        bufStart[index] |= lengthByteSize;
        index++;
        if (bufEnd - bufStart < 1 + lengthByteSize)
            return -1;
        bufStart[index++] = ((length >> 16) & 0xFFU);
        bufStart[index++] = ((length >> 8) & 0xFFU);
        bufStart[index++] = (length & 0xFFU);
    }
    else
    {
        return -1;
    }

    return 1 + lengthByteSize;
}


TinySECSGem::BaseItem* TinySECSGem::BaseItem::Deserialization(BYTE* startBufPos, BYTE* endBufPos, bool& bOk)
{
    if (startBufPos > endBufPos)
    {
        bOk = false;
        return nullptr;
    }

    if (startBufPos == endBufPos)
    {
        bOk = true;
        return nullptr;
    }

    bOk = true;
    BaseItem* item = TopItem::Deserialization(startBufPos, endBufPos);
    if (!item)
    {
        bOk = false;
        delete item;
        return nullptr;
    }
    return item;
}



TinySECSGem::EnumSECSItemType  TinySECSGem::BaseItem::getFormat() const
{ 
    return m_eItemType; 
}




// ===ListItem.h===

#pragma once
#include "BaseItem.h"

#include<vector>
#include<string>
#include<cstdint>

#include "BinaryItem.h"
#include "BooleanItem.h"
#include "ASCIIItem.h"
#include "UnicodeItem.h"
#include "JIS8Item.h"
#include "Int1ByteItem.h"
#include "Int2ByteItem.h"
#include "Int4ByteItem.h"
#include "Int8ByteItem.h"
#include "UInt1ByteItem.h"
#include "UInt2ByteItem.h"
#include "UInt4ByteItem.h"
#include "UInt8ByteItem.h"
#include "Float4ByteItem.h"
#include "Float8ByteItem.h"

namespace TinySECSGem {

    /**
    * @brief SECS-II LIST data item implementation
    *
    * Represents the LIST compound data structure in the SECS/GEM protocol.
    * LIST is a variable-length container type for organizing multiple
    * SECS-II data items. Supports nested structures (List of List),
    * making it one of the core node types in the SECS data tree.
    */
    class TinySECSGEM_API ListItem : public BaseItem
    {
    private:
        std::vector<BaseItem*> m_data;   ///< Child item container (owning raw pointers)

    public:

        /**
         * @brief Construct an empty LIST
         */
        ListItem();

        /**
         * @brief Construct a single-element LIST
         * @param val Initial child item (ListItem takes ownership)
         */
        ListItem(BaseItem* val);

        /**
         * @brief Copy constructor (deep copy)
         * @param item Source LIST
         */
        ListItem(const ListItem& item);

        /**
         * @brief Copy assignment (deep copy)
         * @param item Source LIST
         */
        ListItem& operator=(const ListItem& item);

        /**
         * @brief Assign a single child (clears current content, inserts val)
         * @param val Item pointer (ListItem takes ownership)
         */
        ListItem& operator=(BaseItem* val);

        /**
         * @brief Destructor, releases all child items
         */
        ~ListItem();

        /**
         * @brief Clone this LIST (deep copy)
         * @return New LIST pointer (caller owns the memory)
         */
        virtual BaseItem* clone();

        /**
         * @brief Compute total serialized byte size (including all children)
         */
        virtual size_t totalByteSize() const;

        /**
         * @brief Serialize LIST to SECS-II byte stream
         * @param buff Output buffer
         * @param buffSize Buffer size
         * @return Actual bytes written
         */
        virtual int Serialization(BYTE* buff, size_t buffSize);

        /**
         * @brief Deserialize a LIST from byte stream
         * @param bufStart Start buffer pointer
         * @param bufEnd End buffer pointer (exclusive)
         * @return Parsed ListItem pointer (nullptr on failure)
         */
        static ListItem* Deserialization(BYTE* bufStart, BYTE* bufEnd);

        /**
        * @brief Convert to human-readable string (debug)
        * @param frontStr Prefix for indentation
        * @return Formatted string
        */
        virtual std::string print(std::string frontStr = "") const;

        /**
         * @brief Get the number of child items
         * @return Child count
         */
        virtual size_t GetArraySize() const;

        /**
         * @brief Clear all child items and release memory
         */
        virtual void clear();

        /**
         * @brief Append a child at the end
         * @param val Item pointer (ListItem takes ownership)
         */
        void push_back(BaseItem* val);

        /**
         * @brief Remove the last child
         */
        void pop_back();

        /**
         * @brief Set the child at the specified index
         *
         * @param index Index (out-of-range inserts at end)
         * @param val Value (old value is released)
         */
        void set(BaseItem* val, size_t index = 0);

        /**
         * @brief Insert a child at the specified position
         * @param pos Insertion index
         * @param val Item pointer (ListItem takes ownership)
         */
        void insert(size_t pos, BaseItem* val);

        /**
         * @brief Erase the child at the specified position
         * @param pos Index to erase
         */
        void erase(size_t pos);

        /**
         * @brief Get the child at the specified index, cast to target type
         * @tparam T Target type
         * @param index Index
         * @return Cast pointer, or nullptr on failure
         */
        template<typename T>
        T* get(size_t index) const {
            if (index >= GetArraySize()) return nullptr;
            return m_data[index]->as<T>();
        }

        /**
         * @brief Check whether the child at index is of the specified type
         * @tparam T Target type
         * @param index Index
         * @return true if type matches
         * @return false if type mismatch or out of bounds
         */
        template<typename T>
        bool isType(size_t index) const {
            if (index >= GetArraySize()) return false;
            return m_data[index]->is<T>();
        }
    };
}





//===ListItem.cpp===

#include "ListItem.h"

using namespace TinySECSGem;


ListItem::ListItem()
    :BaseItem()
{
    m_eItemType = EnumSECSItemType::ItemType_LIST;
}

ListItem::ListItem(BaseItem* val)
    :BaseItem()
{
    m_eItemType = EnumSECSItemType::ItemType_LIST;
    push_back(val);
}

ListItem::ListItem(const ListItem& item)
{
    m_eItemType = EnumSECSItemType::ItemType_LIST;
    clear();
    for (int i = 0; i < item.GetArraySize(); i++)
    {
        push_back(item.get<BaseItem>(i)->clone());
    }
}

ListItem& ListItem::operator=(const ListItem& item)
{
    if (this == &item)
        return *this;
    clear();
    for (int i = 0; i < item.GetArraySize(); i++)
    {
        push_back(item.get<BaseItem>(i)->clone());
    }
    return *this;
}

ListItem& ListItem::operator=(BaseItem* val)
{
    if (val == this)
        return *this;
    clear();
    push_back(val);
    return *this;
}

ListItem::~ListItem()
{
    clear();
}


BaseItem* ListItem::clone()
{
    ListItem* item = new ListItem();
    item->clear();
    for (int i = 0; i < GetArraySize(); i++)
    {
        item->push_back(m_data[i]->clone());
    }
    return item;
}

size_t ListItem::totalByteSize() const
{
    size_t rtn = 1;
    if (GetArraySize() <= 0xFFU)
        rtn += 1;
    else if (GetArraySize() <= 0xFFFFU)
        rtn += 2;
    else if (GetArraySize() <= 0xFFFFFFU)
        rtn += 3;
    else
        rtn = 0;
    for (int i = 0; i < GetArraySize(); i++)
        rtn += m_data[i]->totalByteSize();
    return rtn;
}


int ListItem::Serialization(BYTE* buff, size_t buffSize)
{
    if (totalByteSize() > buffSize || totalByteSize() == 0)
        return -1; 
    size_t index = 0;
    int costSize = BaseItem::SerializationItemHeader(buff, buff + buffSize, m_eItemType, 1, GetArraySize());
    if (costSize < 0)
        return -1;
    index += costSize;
    for (int i = 0; i < GetArraySize(); i++)
    {
        const int childSize = m_data[i]->Serialization(buff + index, buffSize - index);
        if (childSize <= 0)
            return -1;
        index += static_cast<size_t>(childSize);
    }
    return totalByteSize();
}


ListItem* ListItem::Deserialization(BYTE* bufStart, BYTE* bufEnd)
{
    size_t index = 0;
    EnumSECSItemType type;
    size_t lengthByteSize = 0;
    size_t lengthByte = 0;
    if (!BaseItem::DeserializationItemHeader(bufStart, bufEnd, type, lengthByteSize, lengthByte))
        return nullptr;
    if (type != EnumSECSItemType::ItemType_LIST)
        return nullptr;
    if ((bufEnd - bufStart) < (1 + lengthByteSize + lengthByte))
        return nullptr;
    index += (1 + lengthByteSize);
    size_t length = 0; // size
    length = lengthByte;
    ListItem* item = new ListItem();
    for (int i = 0; i < length; i++)
    {
        BaseItem* val = nullptr;
        EnumSECSItemType itemType;
        size_t itemLengthByteSize = 0;
        size_t itemLengthByte = 0;
        if (!BaseItem::DeserializationItemHeader(bufStart + index, bufEnd, itemType, itemLengthByteSize, itemLengthByte))
        {
            delete item;
            return nullptr;
        }
        switch (itemType)
        {
        case EnumSECSItemType::ItemType_ASCII:
        {
            val = ASCIIItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_JIS:
        {
            val = JIS8Item::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_UNICODE:
        {
            val = UnicodeItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_BINARY:
        {
            val = BinaryItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_BOOLEAN:
        {
            val = BooleanItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_INT1:
        {
            val = Int1ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_INT2:
        {
            val = Int2ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_INT4:
        {
            val = Int4ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_INT8:
        {
            val = Int8ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_UINT1:
        {
            val = UInt1ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_UINT2:
        {
            val = UInt2ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_UINT4:
        {
            val = UInt4ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_UINT8:
        {
            val = UInt8ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_FLOAT4:
        {
            val = Float4ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_FLOAT8:
        {
            val = Float8ByteItem::Deserialization(bufStart + index, bufEnd);
            break;
        }
        case EnumSECSItemType::ItemType_LIST:
        {
            val = Deserialization(bufStart + index, bufEnd);
            break;
        }
        default:
            break;
        }

        if (!val)
        {
            delete item;
            return nullptr;
        }
        const size_t itemSize = val->totalByteSize();
        if (itemSize == 0)
        {
            delete item;
            return nullptr;
        }
        index += itemSize;
        item->push_back(val);
    }
    return item;
}

std::string ListItem::print(std::string frontStr /*= ""*/) const
{
    // "< L[2] 12 3 >"
    std::string formatStr = frontStr + "< L";
    formatStr += ("[" + std::to_string(GetArraySize()) + "]");
    for (int i = 0; i < GetArraySize(); i++)
        formatStr += ("\n" + m_data[i]->print("    " + frontStr));
    formatStr += ((GetArraySize() > 0 ? "\n" + frontStr : " ") + ">");
    return formatStr;
}


size_t ListItem::GetArraySize() const
{
    return m_data.size();
}


void ListItem::clear()
{
    for (int i = 0; i < GetArraySize(); i++)
    {
        delete m_data[i];
    }
    m_data.clear();
}

void ListItem::push_back(BaseItem* val)
{
    m_data.push_back(val);
}

void ListItem::pop_back()
{
    if (m_data.empty())
        return;
    delete m_data.back();
    m_data.pop_back();
}

void ListItem::set(BaseItem* val, size_t index /*= 0*/)
{
    if (index >= GetArraySize())
    {
        push_back(val);
    }
    else
    {
        delete m_data[index];
        m_data[index] = val;
    }
}

void ListItem::insert(size_t pos, BaseItem* val)
{
    if (pos > m_data.size())
        return;
    m_data.insert(m_data.begin() + pos, val);
}

void ListItem::erase(size_t pos)
{
    if (pos >= m_data.size())
        return;
    delete m_data[pos];
    m_data.erase(m_data.begin() + pos);
}


Snipaste_2026-05-07_21-24-25.png (383.07 KB, 下载次数: 1)

模拟器通信测试

模拟器通信测试

Snipaste_2026-05-07_21-23-38.png (56.85 KB, 下载次数: 0)

数据结构解析与组装

数据结构解析与组装

SECSComEnable0.zip

611.92 KB, 下载次数: 0, 下载积分: 吾爱币 -1 CB

SECS/GEM协议模拟器

免费评分

参与人数 1热心值 +1 收起 理由
xiaogao66 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| TokeyJs 发表于 2026-5-8 21:25 |楼主
jmtsui 发表于 2026-5-8 08:06
楼主辛苦!请问楼主AI检查哪家强啊?

只用过cc+DeepSeek、Codex。claude code的模型没用过,听网上说这个模型写代码应该是最强的。个人感觉Codex确实强,代码审查方面,和一些代码设计架构方面。DeepSeek现在也还行了,便宜。
推荐
 楼主| TokeyJs 发表于 2026-5-8 21:27 |楼主
wei363516609 发表于 2026-5-7 22:00
这个是干什么用的?

实现了部分半导体SECS/GEM标准协议的c++动态库。可以理解为一个实现了特定通信协议的开源cpp库,方便有需要的直接使用,就不需要去再看这些底层协议文档实现这个通信协议。
沙发
wei363516609 发表于 2026-5-7 22:00
3#
殇。默语 发表于 2026-5-7 22:43
虽然我用不来这个,但是为大佬的开源精神点赞
4#
allrand 发表于 2026-5-7 23:11
SEComSimulator .NET AIM Systems, Inc. 可否也分享一下?
5#
BrutusScipio 发表于 2026-5-7 23:20
话说这些平台一般多久跟进标准,26的静态反射似乎基本实现完成
6#
qq414816486 发表于 2026-5-7 23:59
底层协议
7#
jmtsui 发表于 2026-5-8 08:06
楼主辛苦!请问楼主AI检查哪家强啊?
8#
ITHM 发表于 2026-5-8 10:11
感谢分享,太厉害了
9#
苏紫方璇 发表于 2026-5-8 11:51
请在文中插入部分关键代码
本版块仅限分享编程技术和源码相关内容,发布帖子必须带上关键代码和具体功能介绍
10#
wupeiwupei 发表于 2026-5-8 11:57
不了解,但不耽误个给大佬点赞~!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-5-9 08:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表