BellWin UP520US USB Power Splitter 介绍

最近在研究一款USB控制的排插:BellWin 出品的带有USB接口的排插(USB Power Splitter)型号是:UP520US。它带有五个插孔,一个用于控制插孔供电的USB接口和一个供电开关。这款排插不是给家用设计的,上面的的插孔和插头都是专门为机房这种特别场合设计的,在家用环境中必须使用转接头才能工作。

电器特性如下【参考1】:

输入:220V,20A

输入频率:50/60Hz

功耗:5W

每一路最高可支持15A,五组最大支持输出20A

工作温度:0-25℃

接口:IEC60320 C13

认证:RoHS,IPC,CUS

首先,测试一下它自带的控制程序。

用户可以通过下面的按钮控制每一路的开关。

接下来,使用 USB Package Viewer 设备抓取USB 数据包。USB Package Viewer(简称UPV)是一款国产的USB数据逻辑分析仪,能够抓取从 Low Speed 到 High Speed的数据包。有兴趣的朋友可以在【参考2】看到之前我的开箱视频。这个仪器有一个比较大的优点是能够实时显示,这个在分析研究数据量不大的USB设备时非常有用。比如,上位机进行一个动作立刻能够在分析软件上看到数据,这样便于对应数据和操作。

从设备管理器上也可以看出,这个设备使用USB HID 协议。

按下试验软件上的开关两次之后,在UPV中可以看到抓到了2个数据包:

经过多次试验,总结数据如下:

操作抓到的数据,总长度64Bytes
Port1 设置为 OFF0B 00 00 00 00 00 00 5A……5A
Port2 设置为OFF0B 00 00 00 00 01 00 5A……5A
Port3 设置为OFF0B 00 00 00 00 02 00 5A……5A
Port4 设置为OFF0B 00 00 00 00 03 00 5A……5A
Port5 设置为OFF0B 00 00 00 00 04 00 5A……5A
Port1 设置为 ON0B 00 00 00 00 00 01 5A……5A
Port2 设置为ON0B 00 00 00 00 01 01 5A……5A
Port3 设置为ON0B 00 00 00 00 02 01 5A……5A
Port4 设置为ON0B 00 00 00 00 03 01 5A……5A
Port5 设置为ON0B 00 00 00 00 04 01 5A……5A

需要注意的是,上面的数据末端,使用0x5A 填充,实际上使用任意数据进行填充都可以, USB 排插以前面的有效数据为准。

根据上述表格,很容易编写一个控制这个排插开关的代码(VS2019):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <setupapi.h>
 
extern "C" {
 
    void __stdcall
        HidD_GetHidGuid(
            OUT   LPGUID   HidGuid
        );
 
    typedef struct _HIDD_ATTRIBUTES {
        ULONG   Size; // = sizeof (struct _HIDD_ATTRIBUTES)
 
                      //
        // Vendor ids of this hid device
        //
        USHORT  VendorID;
        USHORT  ProductID;
        USHORT  VersionNumber;
 
        //
        // Additional fields will be added to the end of this structure.
        //
    } HIDD_ATTRIBUTES, * PHIDD_ATTRIBUTES;
 
    BOOLEAN __stdcall
        HidD_GetAttributes(
            IN  HANDLE              HidDeviceObject,
            OUT PHIDD_ATTRIBUTES    Attributes
        );
 
    BOOLEAN __stdcall
        HidD_SetFeature(
            _In_    HANDLE   HidDeviceObject,
            _In_reads_bytes_(ReportBufferLength) PVOID ReportBuffer,
            _In_    ULONG    ReportBufferLength
        );
}
 
#pragma comment( lib, "hid.lib" )
#pragma comment( lib, "setupapi.lib" )
 
void SetAll(HANDLE hUsb, bool AllOn)
{
    BOOL Result;
    UCHAR WriteReportBuffer[65];
 
    for (int i = 0; i < 8; i++) {
        WriteReportBuffer[i] = 0x00;
    }
    for (int i = 8; i < 65; i++) {
        WriteReportBuffer[i] = 0x5a;
    }
 
    WriteReportBuffer[1] = 0x0b;
    for (byte i = 0; i < 5; i++) {
        WriteReportBuffer[6] = i;
        if (AllOn) {
            WriteReportBuffer[7] = 0x01;
        }
 
        DWORD lpNumberOfBytesWritten;
 
        Result = WriteFile(hUsb,
            WriteReportBuffer,
            65,
            &lpNumberOfBytesWritten,
            NULL);
        //printf("Written %d bytes Result [%d]\n", lpNumberOfBytesWritten, Result);
    }
 
 
}
 
int main()
{
    GUID HidGuid;
    BOOL Result;
    int  counter = -1;
 
 
    HidD_GetHidGuid(&HidGuid);
    printf("HID GUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n"
        , HidGuid.Data1, HidGuid.Data2, HidGuid.Data3
        , HidGuid.Data4[0], HidGuid.Data4[1], HidGuid.Data4[2], HidGuid.Data4[3], HidGuid.Data4[4]
        , HidGuid.Data4[5], HidGuid.Data4[6], HidGuid.Data4[7]);
 
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&HidGuid, NULL, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (INVALID_HANDLE_VALUE != hDevInfo)
    {
        SP_DEVICE_INTERFACE_DATA strtInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
        for (DWORD index = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &HidGuid, index, &strtInterfaceData); ++index)
        {
 
            char buf[1000];
            SP_DEVICE_INTERFACE_DETAIL_DATA& strtDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA&)buf[0];
            strtDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
            if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &strtInterfaceData, &strtDetailData, _countof(buf), NULL, NULL))
            {
                printf("[%d] path: %ls\n", index, strtDetailData.DevicePath);
 
                HANDLE hUsb = CreateFile(strtDetailData.DevicePath,
                    NULL, FILE_SHARE_WRITE,
                    NULL, OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    NULL);
 
                HIDD_ATTRIBUTES strtAttrib = { sizeof(HIDD_ATTRIBUTES) };
                Result = HidD_GetAttributes(hUsb, &strtAttrib);
                CloseHandle(hUsb);
 
                if (TRUE == Result)
                {
                    if ((0x04D8 == strtAttrib.VendorID) &&
                        (0xFEDC == strtAttrib.ProductID))       //ÕÒµ½ÎÒÃÇ×Ô¼ºµÄÉ豸
                    {
                        printf("VendorID : %hX\n", strtAttrib.VendorID);
                        printf("ProductID: %hX\n", strtAttrib.ProductID);
                        printf("VerNumber: %hX\n", strtAttrib.VersionNumber);
 
                        hUsb = CreateFile(strtDetailData.DevicePath,
                            GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE,
                            NULL, OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL, NULL);
 
                        //Switch(hUsb); GetData(hUsb);
                        SetAll(hUsb,TRUE);
                        Sleep(3000);
                        SetAll(hUsb, FALSE);
 
                        CloseHandle(hUsb);
 
                    }//if ((0x8888==strtAttrib.VendorID) &&
                }            //if(TRUE==Result)
            } // if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )
        }    //for( DWORD index=0;
 
        if (GetLastError() != ERROR_NO_MORE_ITEMS)
        {
            printf("No more items!\n");
        }
 
        SetupDiDestroyDeviceInfoList(hDevInfo);
 
    //if( INVALID_HANDLE_VALUE != hDevInfo )
    system("PAUSE");
    return 0;
}

这个代码没有使用厂家提供的API (厂家提供了 DLL)而是直接对 HID设备编程,这样做的好处是无需外挂文件,一个 EXE 都可以搞定。坏处是,没有实现厂家API 提供的诸如取得序列号这样的功能,如果有需求还需要另外研究编写。但是无论如何,能够实现控制端口开关已经足够了。

综上所述:BellWin的UP520US是一款可以通过USB控制的排插,满足实验室安规要求。有需要的朋友可以进一步研究。

参考:

  1. http://powersplitter.bellwin.com.tw/UP520US.html
  2. https://www.bilibili.com/video/BV1CG4y1H7Xk/ USBPacketViewer

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注