64

帖子

0

TA的资源

一粒金砂(初级)

21
 
引用 19 楼 sxy_9761 的回复:
其实我下午也一直在看这个问题,目前还没有理清楚。现在得知的一些信息是(因为我是用的eboot),在IMAGE_START_BLOCK第一个扇区放写分区表信息,名括起始地址与大小等。默认是支持四个分区。内核怎么读的,我觉得是可能跟注册表的配置、驱动(mspart.dll)和FAL有关。

我不想再跟下去了,太辛苦了,花了一天时间把这些从头到尾跟理了一遍。楼主得知道答案后,希望也可以共享一下,谢谢了。



-------------------好的,放心,我发的帖子都是长贴,因为我自己通常会把自己理解的过程贴出来。不然在这里问问题就太不厚道了。睡觉了。明天找妞儿去。要广泛撒网,现在好解决问题了。以前大学错过了好多美好的女孩,现在惆怅不已。你辛苦了哦。放假不去玩玩吗?
===================对于这个不开源的微软来说,如果没有高人出来指点的话,估计要点时间才能了解。这方面的东西资料甚少。

回复

75

帖子

0

TA的资源

一粒金砂(初级)

22
 
http://www.cnblogs.com/yakin/articles/232639.html
BINFS的调试过程

http://www.cnblogs.com/yakin/articles/206435.html

http://www.cnblogs.com/yakin/articles/217068.html
 
 

回复

88

帖子

0

TA的资源

一粒金砂(初级)

23
 
这个topic有点意思,不过放假没心思追了,假后再议。
PS: windows mobile其实一直默认就是用这套的。
 
 
 

回复

87

帖子

0

TA的资源

一粒金砂(初级)

24
 
This function opens or creates a partition.

HANDLE BP_OpenPartition(
  DWORD dwStartSector,
  DWORD dwNumSectors,
  DWORD dwPartType,
  BOOL fActive,
  DWORD dwCreationFlags
);
Parameters
dwStartSector
[in] Logical sector to the start of the partition. This value should be set to NEXT_FREE_LOC if no sector is specified. This parameter is ignored if an existing partition is opened.
dwNumSectors
[in] Number of logical sectors of the partition. This value can be set to USE_REMAINING_SPACE to indicate that the remaining space on the flash for the partition should be used. The USE_REMAINING_SPACE value should only be used when creating an extended partition. This parameter is ignored if an existing partition is opened.
dwPartType
[in] Type of partition to open or create. The following table shows the possible values for dwPartType. Value Description
PART_BOOTSECTION Creates a boot section that can be used to store boot arguments. All flash blocks in the partition are marked as read-only.
PART_BINFS Creates a BinFS partition. All flash blocks in the partition are marked as read-only.
PART_EXTENDED Creates an extended partition that can be used to store one or more data partitions, such as FATFS. If dwStartSector is not on a block boundary then it is incremented to start at the next block boundary.

fActive
[in] Set to TRUE to indicate that the partition is active. Set to FALSE for inactive.
dwCreationFlags
[in] Value that stores information for opening or creating a partition. The following table shows the possible values for dwCreationFlags. Value Description
PART_CREATE_NEW Creates a partition. Fails if a partition already exists.
PART_OPEN_EXISTING Opens an existing partition. Fails if the partition does not exist.
PART_OPEN_ALWAYS Creates a partition if it does not exist or opens a partition if it does exist.

Return Values
Returns a handle to the partition on success. Returns INVALID_HANDLE_VALUE on an error.

Requirements
OS Versions: Windows CE .NET 4.2 and later.
Header: Bootpart.h
Link Library: Bootpart.lib

-----------------------------------------------其实这个PB帮助文档还是比较有用的。
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

25
 
Windows CE Features > File Systems and Data Store > File Systems and Data Store OS Design Development > File Systems > Binary Rom Image File System (BinFS)

The boot loader uses the Bootpart library to create a partition that enables BinFS and another file system, such as FAT, to be located on the same flash memory. The boot loader can use Bootpart to create the BinFS partition as well as a second partition. The second partition can either be a specific partition such as TFAT, or an extended partition. The second partition must be an extended partition if multiple data partitions are to be used. An extended partition also provides the flexibility to create one or more data partitions through the operating system (OS) using OS utilities.

Bootpart can also create a boot partition to store boot arguments. The flash blocks that contain the master boot record section, BinFS region, and the boot arguments partition are read-only and you cannot modify them. In addition, the BinFS and Boot partitions are marked as read-only so that you cannot format or delete the partitions themselves.

In order for MSPART to recognize the BinFS partition, you must add the following registry keys to the partition table.

[HKEY_LOCAL_MACHINE\System\StorageManager\PartitionTable]
    "20"="BOOT"
    "21"="BINFS"
See Also
Binary Rom Image File System (BinFS)

 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

26
 
Windows CE Features > File Systems and Data Store > File Systems and Data Store OS Design Development > File Systems
The binary ROM Image File System (BinFS) is a file system that reads the binary image (.bin) file format generated by Romimage.exe. The .bin file format organizes data into specific sections. Each section contains a section header that specifies the starting address, length, and checksum values for that section. Romimage.exe writes data organized by logical sections, such as an application's text or .data region, to the .bin file.
To load BinFS on top of a block driver, you must enter the appropriate registry keys in the storage profile of your block driver. For Windows CE 5.0 and later, the following code example shows the registry keys you can add to the storage profile of your block driver to specify that BinFS is the default file system.
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\MSFlash]
    "DefaultFileSystem"="BINFS"
    "PartitionDriver"="mspart.dll"
    "MountHidden"=dword:1
    "MountAsROM"=dword:1
    "Folder"="NAND Flash"
    "Name"= "FLASH Disk Block Device"
[HKEY_LOCAL_MACHINE\System\StorageManager\BinFS]
    "FriendlyName"="BIN Filesystem"
    "Dll"="binfs.dll"
    "Paging"=dword:1
For versions of Windows CE earlier than 5.0, replace the entries for MountHidden and MountAsROM with the following single value for MountFlags:
    "MountFlags"=dword:11
For more information about replacements for the MountFlags registry value, see XXXX.
In addition to the registry settings shown, you must add a registry key to the FAT file system settings within the storage profile. The default setting for FATFS is for the mount point to be visible to the user. In order to hide the mount point from the user you must add a registry key to prevent the FAT file system from shadowing the Windows directory. The following registry key prevents the FAT file system from attempting to shadow the Windows directory.
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\MSFlash\FATFS]
    "MountFlags"=dword:0
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

27
 
具体请看CreateMBR()BINFS创建了一个类似FAT的MBR
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

28
 
引用 26 楼 guetcw 的回复:
具体请看CreateMBR()BINFS创建了一个类似FAT的MBR


C:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BOOTPART\bootpart.cpp(113):static BOOL CreateMBR()
//------------------------------------------------------------------------------
static BOOL CreateMBR()
{
    // This, plus a valid partition table, is all the CE partition manager needs to recognize
    // the MBR as valid. It does not contain boot code.

    memset (g_pbMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);
    g_pbMBRSector[0] = 0xE9;
    g_pbMBRSector[1] = 0xfd;
    g_pbMBRSector[2] = 0xff;
    g_pbMBRSector[SECTOR_SIZE-2] = 0x55;
    g_pbMBRSector[SECTOR_SIZE-1] = 0xAA;

    // Zero out partition table so that mspart treats entries as empty.
    memset (g_pbMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);

    return WriteMBR();

}  
C:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BOOTPART\bootpart.cpp(80):static BOOL WriteMBR()
//------------------------------------------------------------------------------
static BOOL WriteMBR()
{
    DWORD dwMBRBlockNum = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;

    RETAILMSG(1, (TEXT("WriteMBR: MBR block = 0x%x.\r\n"), dwMBRBlockNum));

    memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);
    memset (g_pSectorInfoBuf, 0xff, sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);
        
    // No need to check return, since a failed read means data hasn't been written yet.
    ReadBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf);

    if (!FMD_EraseBlock (dwMBRBlockNum)) {
        RETAILMSG (1, (TEXT("CreatePartition: error erasing block 0x%x\r\n"), dwMBRBlockNum));
        return FALSE;
    }

    memcpy (g_pbBlock + (g_dwMBRSectorNum % g_FlashInfo.wSectorsPerBlock) * g_FlashInfo.wDataBytesPerSector, g_pbMBRSector, g_FlashInfo.wDataBytesPerSector);
    g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;
    g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;
    g_pSectorInfoBuf->dwReserved1 = 0;

    if (!WriteBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf)) {
        RETAILMSG (1, (TEXT("CreatePartition: could not write to block 0x%x\r\n"), dwMBRBlockNum));
        return FALSE;
    }

    return TRUE;
   
}
----------------------这两个函数是在eboot调用的。但是我的ADS BOOT没有类似功能代码。

 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

29
 
不过在内核代码的地方也有类似的代码
C:\WINCE500\PRIVATE\WINCEOS\COREOS\STORAGE\DOSPART\helper.cpp(747):BOOL WriteMBR(DriverState *state, SECTORNUM snSectorNum, SECTORNUM snNumSectors, BYTE fileSysType, BOOL bCreateMBR)

/*****************************************************************************
*  WriteMBR - adds a partition entry to the master boot record. The partition
*  table is traversed to find the placement for this partition.  Entries within
*  the MBR are sorted by the start sector.
*
*  Input:  state - structure for this store
*          snSectorNum - start sector number for this partition
*          snNumSectors - number of sectors in this partition
*          fileSysType - partition type
*          bCreateMBR - TRUE to generate a new MBR, FALSE to add to the
*                       existing MBR
*
*  Output: none
*
*  Return: TRUE if successfully written, FALSE for failures, ERROR_DISK_FULL
*          will be set if no room in the MBR
*
*****************************************************************************/
BOOL WriteMBR(DriverState *state, SECTORNUM snSectorNum, SECTORNUM snNumSectors, BYTE fileSysType, BOOL bCreateMBR)
{

    PBYTE       buffer = NULL;
    PPARTENTRY  tmpbuffer, tmpbuffer1;
    BOOL        bResult;
    int         i, partIndex, partNum = -1;

    // don't create the MBR, it already exists so use it
    if (!bCreateMBR)
    {
        bResult = ReadSectors (state, 0, 1, &buffer);
        if (!bResult)
            return FALSE;

        for (i = 0, partIndex = 0, tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET); i < 4; i++, tmpbuffer++)
        {
            if (tmpbuffer->Part_TotalSectors == 0)
            {
                partNum = i;
                break;
            }

            // find the index of the partition located just before this one
            if (snSectorNum > tmpbuffer->Part_StartSector)
                partIndex = i + 1;
        }

        if (partNum == -1)
        {
            // we return this error code so the caller can tell that there's no room in the MBR
            LocalFree(buffer);
            SetLastError(ERROR_DISK_FULL);
            return FALSE;
        }

        // these indexes would be equal if we are adding to the end of the table
        if (partIndex != partNum)
        {
            // this partition needs to be added in the order that it appears on the disk - so this may involve
            //  shifting some of the existing partition entries to open up the partition entry where this belongs
            tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET + (partNum * sizeof(PARTENTRY)));
            tmpbuffer1 = (PPARTENTRY)(buffer + PARTTABLE_OFFSET + ((partNum -1) * sizeof(PARTENTRY)));

            for (; partNum > partIndex; partNum--)
            {
                memcpy(tmpbuffer, tmpbuffer1, sizeof(PARTENTRY));
                tmpbuffer--;
                tmpbuffer1--;
            }
        }
    }
    else
    {
        buffer = (PBYTE)LocalAlloc(LMEM_ZEROINIT, state->diskInfo.di_bytes_per_sect);
        if (!buffer)
            return FALSE;

        // add header and trailer info to the MBR
        *(WORD *)(buffer + BOOT_SIGNATURE) = BOOTSECTRAILSIGH;
        buffer[0] = 0xE9;
        buffer[1] = 0xfd;
        buffer[2] = 0xff;
        partNum = 0;
    }

    tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET + partNum * (int)sizeof(PARTENTRY));

    // create the partition entry for the extended partition
    bResult = ConvertLBAtoCHS (state, snSectorNum, &tmpbuffer->Part_FirstTrack, &tmpbuffer->Part_FirstHead, &tmpbuffer->Part_FirstSector);

    tmpbuffer->Part_FileSystem = fileSysType;
    tmpbuffer->Part_StartSector = (DWORD)snSectorNum;
    tmpbuffer->Part_TotalSectors = (DWORD)snNumSectors;

    bResult = ConvertLBAtoCHS (state, tmpbuffer->Part_StartSector + tmpbuffer->Part_TotalSectors -1, &tmpbuffer->Part_LastTrack, &tmpbuffer->Part_LastHead, &tmpbuffer->Part_LastSector);

    bResult = WriteSectors(state, 0, 1, buffer);
    LocalFree(buffer);

    return bResult;

}

---------------这里在内核启动的时候会检测有没有MBR,有就用以前的,没有就创建一个。难怪我的ADS代码没有出现MBR功能的代码。
 
 
 

回复

63

帖子

0

TA的资源

一粒金砂(初级)

30
 
C:\WINCE500\PRIVATE\WINCEOS\COREOS\STORAGE\DOSPART\helper.cpp(747):BOOL WriteMBR(DriverState *state, SECTORNUM snSectorNum, SECTORNUM snNumSectors, BYTE fileSysType, BOOL bCreateMBR)
/*****************************************************************************
*  WriteMBR - adds a partition entry to the master boot record. The partition
*  table is traversed to find the placement for this partition.  Entries within
*  the MBR are sorted by the start sector.
*
*  Input:  state - structure for this store
*          snSectorNum - start sector number for this partition
*          snNumSectors - number of sectors in this partition
*          fileSysType - partition type
*          bCreateMBR - TRUE to generate a new MBR, FALSE to add to the
*                       existing MBR
*
*  Output: none
*
*  Return: TRUE if successfully written, FALSE for failures, ERROR_DISK_FULL
*          will be set if no room in the MBR
*
*****************************************************************************/
BOOL WriteMBR(DriverState *state, SECTORNUM snSectorNum, SECTORNUM snNumSectors, BYTE fileSysType, BOOL bCreateMBR)
{

    PBYTE       buffer = NULL;
    PPARTENTRY  tmpbuffer, tmpbuffer1;
    BOOL        bResult;
    int         i, partIndex, partNum = -1;

    // don't create the MBR, it already exists so use it
    if (!bCreateMBR)
    {
        bResult = ReadSectors (state, 0, 1, &buffer);
        if (!bResult)
            return FALSE;

        for (i = 0, partIndex = 0, tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET); i < 4; i++, tmpbuffer++)
        {
            if (tmpbuffer->Part_TotalSectors == 0)
            {
                partNum = i;
                break;
            }

            // find the index of the partition located just before this one
            if (snSectorNum > tmpbuffer->Part_StartSector)
                partIndex = i + 1;
        }

        if (partNum == -1)
        {
            // we return this error code so the caller can tell that there's no room in the MBR
            LocalFree(buffer);
            SetLastError(ERROR_DISK_FULL);
            return FALSE;
        }

        // these indexes would be equal if we are adding to the end of the table
        if (partIndex != partNum)
        {
            // this partition needs to be added in the order that it appears on the disk - so this may involve
            //  shifting some of the existing partition entries to open up the partition entry where this belongs
            tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET + (partNum * sizeof(PARTENTRY)));
            tmpbuffer1 = (PPARTENTRY)(buffer + PARTTABLE_OFFSET + ((partNum -1) * sizeof(PARTENTRY)));

            for (; partNum > partIndex; partNum--)
            {
                memcpy(tmpbuffer, tmpbuffer1, sizeof(PARTENTRY));
                tmpbuffer--;
                tmpbuffer1--;
            }
        }
    }
    else
    {
        buffer = (PBYTE)LocalAlloc(LMEM_ZEROINIT, state->diskInfo.di_bytes_per_sect);
        if (!buffer)
            return FALSE;

        // add header and trailer info to the MBR
        *(WORD *)(buffer + BOOT_SIGNATURE) = BOOTSECTRAILSIGH;
        buffer[0] = 0xE9;
        buffer[1] = 0xfd;
        buffer[2] = 0xff;
        partNum = 0;
    }

    tmpbuffer = (PPARTENTRY)(buffer + PARTTABLE_OFFSET + partNum * (int)sizeof(PARTENTRY));

    // create the partition entry for the extended partition
    bResult = ConvertLBAtoCHS (state, snSectorNum, &tmpbuffer->Part_FirstTrack, &tmpbuffer->Part_FirstHead, &tmpbuffer->Part_FirstSector);

    tmpbuffer->Part_FileSystem = fileSysType;
    tmpbuffer->Part_StartSector = (DWORD)snSectorNum;
    tmpbuffer->Part_TotalSectors = (DWORD)snNumSectors;

    bResult = ConvertLBAtoCHS (state, tmpbuffer->Part_StartSector + tmpbuffer->Part_TotalSectors -1, &tmpbuffer->Part_LastTrack, &tmpbuffer->Part_LastHead, &tmpbuffer->Part_LastSector);

    bResult = WriteSectors(state, 0, 1, buffer);
    LocalFree(buffer);

    return bResult;

}

-----------这些都是创建分区之后做的事情,我要找出创建分区的函数在哪里,估计也会在这里。
 
 
 

回复

79

帖子

0

TA的资源

一粒金砂(初级)

31
 
BINFS会调用CreateMBR()创建一个符合FAT的MBR,如果你不知道MBR的作用和结构请参考微软的FAT32白皮书。
BINFS将FLASH格式化后调用这个函数。然后eboot用CreatePartition()或BP_OpenPartition()创建一个主分区,用于存放wince的影像。然后在某处还会调用这两个函数创建一个扩展分区,并将扩展分区的信息写进MBR以便支持FAT文件系统。FAT文件系统就是在这个分区上的
 
 
 

回复

60

帖子

0

TA的资源

一粒金砂(初级)

32
 
引用 30 楼 guetcw 的回复:
BINFS会调用CreateMBR()创建一个符合FAT的MBR,如果你不知道MBR的作用和结构请参考微软的FAT32白皮书。
BINFS将FLASH格式化后调用这个函数。然后eboot用CreatePartition()或BP_OpenPartition()创建一个主分区,用于存放wince的影像。然后在某处还会调用这两个函数创建一个扩展分区,并将扩展分区的信息写进MBR以便支持FAT文件系统。FAT文件系统就是在这个分区上的


哈哈,chenwei你也跑来了。关键时刻,校友帮忙,THANKS!
C:\WINCE500\PRIVATE\WINCEOS\COREOS\STORAGE\INC------------这里有大量文件系统相关的头文件。
C:\WINCE500\PRIVATE\WINCEOS\COREOS\STORAGE\STOREMGR\store.cpp(104):BOOL CStore::GetPartitionDriver(HKEY hKeyStorage, HKEY hKeyProfile)

-------------从这个函数的参数以及名字可以看出,作用是加载分区的驱动,并且和注册表相关,虽然微软很少注释,但是它的命名方式使人很容易理解程序。
C:\WINCE500\PRIVATE\WINCEOS\COREOS\STORAGE\INC\storemain.h(31):BOOL   WINAPI STG_CreatePartition(PSTOREHANDLE pStoreHandle, LPCTSTR szPartitionName, DWORD dwPartType, DWORD dwHighSec, DWORD dwLowSec, BOOL bAuto);
========================================

BOOL   WINAPI STG_CreatePartition(PSTOREHANDLE pStoreHandle, LPCTSTR szPartitionName, DWORD dwPartType, DWORD dwHighSec, DWORD dwLowSec, BOOL bAuto);

----------这个函数应该是创建BINFS和FAT分区的。但是我找不到它在哪里被调用,难道是在内核包装起来,看不见的?



 
 
 

回复

79

帖子

0

TA的资源

一粒金砂(初级)

33
 
先看两天微软FAT白皮书先,然后再来做个总结,
高人请来留笔
两天后结贴。
 
 
 

回复

65

帖子

0

TA的资源

一粒金砂(初级)

34
 
我晕,你是啊赖?,哈哈
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(初级)

35
 
引用 33 楼 guetcw 的回复:
我晕,你是啊赖?,哈哈


-------------------------------很少见你回帖啊。还没有和XXX确立关系?不行啊,见到有美女头像的才回帖。你的还没有搞定?
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(初级)

36
 
哈哈,还是你激情高昂,我的暂时放下
 
 
 

回复

65

帖子

0

TA的资源

一粒金砂(初级)

37
 
介绍一下我们的实现:
1.在烧写的时候,需要通过BP_OpenPartition建立三个分区,RAW,Binfs和Fatfs;
2.分别将RAW和Binfs的数据烧进去,同时,要注意将这些Sector标成ReadOnly;
3.注册表里要置上这些文件系统的相应信息;
4.Config.bib里有留有Binfs Chain的位置;
5.要将IPLMain修改一下,在初始化的时候,去检查读出MBR,找到Rawfs的位置,将其拷入RAM运行;
6.要将bootpart.cpp中CreatePartition调用WriteLogicalNumbers的一段去掉,防止系统写入错误的逻辑扇区号;
 
 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

38
 
引用 36 楼 bearbrotherji 的回复:
介绍一下我们的实现:
1.在烧写的时候,需要通过BP_OpenPartition建立三个分区,RAW,Binfs和Fatfs;
2.分别将RAW和Binfs的数据烧进去,同时,要注意将这些Sector标成ReadOnly;
3.注册表里要置上这些文件系统的相应信息;
4.Config.bib里有留有Binfs Chain的位置;
5.要将IPLMain修改一下,在初始化的时候,去检查读出MBR,找到Rawfs的位置,将其拷入RAM运行;
6.要将bootpart.cpp中CreatePartition调用WriteLogic…


多谢分享。
 
 
 

回复

58

帖子

0

TA的资源

一粒金砂(初级)

39
 
SD卡看得有点眉目了,估计下周又可以看这个了。
 
 
 

回复

63

帖子

0

TA的资源

一粒金砂(初级)

40
 
建议你研究一下微软的源码,从WINCE500\private\winceos\coreos\storage\storemgr中的Storemain.cpp里的InitStorageManager开始看起,跟踪整个流程,你就会清楚BinFS以及FAT文件系统的建立流程以及文件系统和分区驱动、块设备驱动之间的关系。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条
电源解决方案和技术 | DigiKey 应用探索站
当月好物、电源技术资源、特色活动、DigiKey在线实用工具,干货多多~

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表