除了Stephen Lechner 的回答,您可以使用外部程序生成字符串描述符(和其他类似程序),输出 C 源文件以包含在实现中。仅当您有很多常量需要按摩时,这才有意义。
uint16_t
请注意,您可以使用USB 字符串描述符数组,而不是结构。(您只需要知道架构上的字节顺序,因此字节长度字节也是内存中的第一个字节:它是大端架构的高字节,小端架构的低字节 -字节序架构。)
例如,考虑以下 awk 脚本constants.awk:
#!/usr/bin/awk -f
BEGIN {
# 0 = little endian, least significant byte first
# 1 = big endian, most significant byte first
BYTEORDER = 1
RS = "[\t\v\f ]*(\r\n|\n\r|\r|\n)[\t\v\f ]*"
FS = "[\t\v\f ]+"
split("", codepoint)
for (i = 1; i < 128; i++)
codepoint[sprintf("%c", i)] = i
# Note: Could add unicode code points U+00A0 to U+FFFF
# to codepoint[] array.
printf "#ifndef CONSTANTS_H\n"
printf "#define CONSTANTS_H\n"
printf "\n"
printf "/* Do not edit this file; edit constants.in instead.\n"
printf " This file is automatically generated by constants.awk.\n"
printf "*/\n\n"
}
$1 == "usb_string_descriptor" && NF >= 3 {
name = $2
value = $0
sub(/^[^"]*"/, "", value) # Remove everything before first "
sub(/"[^"]*$/, "", value) # Remove everything after last "
valuelen = length(value)
type = 3
printf "#define %s_size %d\n", name, 2*valuelen + 2
printf "#define %s_type %d\n", name, type
printf "#define %s_len %d\n", name, valuelen
printf "static const uint16_t %s[%d] = {\n", name, valuelen + 1
printf " /* \"%s\" */\n", value
if (BYTEORDER == 1)
printf " 0x%02x%02x, /* length = %d bytes, type = 0x%02x */", 2*valuelen + 2, type, 2*valuelen + 2, type
else
printf " 0x%02x%02x, /* length = %d bytes, type = 0x%02x */", type, 2*valuelen + 2, 2*valuelen + 2, type
for (i = 1; i <= valuelen; i++) {
if ((i % 8) == 1)
printf "\n "
printf "0x%04x, ", codepoint[substr(value, i, 1)]
}
printf "\n};\n\n"
}
END {
printf "#endif /* CONSTANTS_H */\n"
}
假设您有一个文件,例如constants.in
,描述了上述脚本应定义的一些常量:
usb_string_descriptor manufacturer_string_1 "My Cool Product"
usb_string_descriptor manufacturer_string_2 "My Other Cool Product"
让您的构建机器运行,例如awk -f constants.awk constants.in > constants.h
。如果你使用 Makefiles,那么
AWK := awk
constants.h: constants.in
$(AWK) -f constants.h constants.in > constants.h
应该做的伎俩。(它甚至会导致constant.h
重新生成头文件,如果您编辑constants.in
在实际的 C 源文件实现中,您只需#include "constants.h"
.
以上将输出
#ifndef CONSTANTS_H
#define CONSTANTS_H
/* Do not edit this file; edit constants.in instead.
This file is automatically generated by constants.awk.
*/
#define manufacturer_string_1_size 32
#define manufacturer_string_1_type 3
#define manufacturer_string_1_len 15
static const uint16_t manufacturer_string_1[16] = {
/* "My Cool Product" */
0x2003, /* length = 32 bytes, type = 0x03 */
0x004d, 0x0079, 0x0020, 0x0043, 0x006f, 0x006f, 0x006c, 0x0020,
0x0050, 0x0072, 0x006f, 0x0064, 0x0075, 0x0063, 0x0074,
};
#define manufacturer_string_2_size 44
#define manufacturer_string_2_type 3
#define manufacturer_string_2_len 21
static const uint16_t manufacturer_string_2[22] = {
/* "My Other Cool Product" */
0x2c03, /* length = 44 bytes, type = 0x03 */
0x004d, 0x0079, 0x0020, 0x004f, 0x0074, 0x0068, 0x0065, 0x0072,
0x0020, 0x0043, 0x006f, 0x006f, 0x006c, 0x0020, 0x0050, 0x0072,
0x006f, 0x0064, 0x0075, 0x0063, 0x0074,
};
#endif /* CONSTANTS_H */
(注意:我似乎记得 USB 字符串描述符不需要终止 NUL 字符(0)。我可能记错了。)
我使用了 awk,因为它适用于各种风格的所有平台——不仅是 GNU awk,还有 nawk、mawk等等。你会想要使用一种脚本语言来生成易于维护的脚本;上述版本旨在可扩展到 USB 字符串描述符以外的其他类型。
我怀疑 Python 脚本从长远来看可能更容易维护,因为它比 awk(或 Perl,另一种用于这种预处理的典型脚本语言)更受欢迎。另外,Python 具有ord()
您可以使用的内置函数,并允许您在 USB 字符串描述符中使用非 ASCII Unicode 字符。