How to access DAO enumeration constants in PowerShell? - powershell

In PowerShell, how do you access DAO enumeration constants, such as RecordsetTypeEnum dbOpenTable (1) or DataTypeEnum adVarNumeric (139)? Right now, I'm simply putting them in as magic numbers, but it would be much cleaner and easier to read to refer to the proper constants.

You could define a custom enum type with the names needed:
enum DAODataType {
adBigInt = 0x14
adBinary = 0x80
adBoolean = 0x0B
adBSTR = 0x08
adChapter = 0x88
adChar = 0x81
adCurrency = 0x06
adDate = 0x07
adDBDate = 0x85
adDBTime = 0x86
adDBTimeStamp = 0x87
adDecimal = 0x0E
adDouble = 0x05
adEmpty = 0x00
adError = 0x0A
adFileTime = 0x40
adGUID = 0x48
adIDispatch = 0x09
adInteger = 0x03
adIUnknown = 0x0D
adLongVarBinary = 0xCD
adLongVarChar = 0xC9
adLongVarWChar = 0xCB
adNumeric = 0x83
adPropVariant = 0x8A
adSingle = 0x04
adSmallInt = 0x02
adTinyInt = 0x10
adUnsignedBigInt = 0x15
adUnsignedInt = 0x13
adUnsignedSmallInt = 0x12
adUnsignedTinyInt = 0x11
adUserDefined = 0x84
adVarBinary = 0xCC
adVarChar = 0xC8
adVariant = 0x0C
adVarNumeric = 0x8B
adVarWChar = 0xCA
adWChar = 0x82
}
Then pass [DAODataType]::adVarNumeric instead of 139

For RecordsetTypeEnum dbOpenTable (which comes from Access), you can use:
[Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Access.Dao") | Out-null
[int][Microsoft.Office.Interop.Access.Dao.RecordsetTypeEnum]::dbOpenTable
For DataTypeEnum adVarNumeric (which comes from ADODB, not Access) you can use:
[Reflection.Assembly]::LoadWithPartialName("ADODB") | Out-null
[int][ADODB.DataTypeEnum]::adVarNumeric

Related

Implementing AD7606 driver for Raspberry Pi 4b

I am trying to implement ADC AD7606 device driver for Linux on Raspberry Pi 4B+ to make possible to read data from all channels as fast as it possible via SPI. The kernel version is v5.10.83 and the kernel was compiled and installed with support both AD7606 and AD7606_SPI as modules (make menuconfig).
The device tree overlay was created by using example on Analog Devices https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad7606 and now it is like this:
/dts-v1/;
/plugin/;
#include <../include/dt-bindings/gpio/gpio.h>
#include <../include/dt-bindings/interrupt-controller/irq.h>
/ {
compatible = "brcm,bcm2835";
fragment#0 {
target = <&spi0>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
adc0: adc#0 {
compatible = "adi,ad7606-8";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>,
<&gpio 23 GPIO_ACTIVE_HIGH>,
<&gpio 26 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
adi,sw-mode;
};
};
};
};
The overlay is activated in /boot/config.txt and reverted DT section for SPI is like this:
spi#7e204000 {
compatible = "brcm,bcm2835-spi";
clocks = < 0x08 0x14 >;
status = "okay";
#address-cells = < 0x01 >;
interrupts = < 0x00 0x76 0x04 >;
cs-gpios = < 0x07 0x08 0x01 0x07 0x07 0x01 >;
#size-cells = < 0x00 >;
dma-names = "tx\0rx";
phandle = < 0x33 >;
reg = < 0x7e204000 0x200 >;
pinctrl-0 = < 0x0e 0x0f >;
dmas = < 0x0c 0x06 0x0c 0x07 >;
pinctrl-names = "default";
adc#0 {
spi-cpol;
compatible = "adi,ad7606-8";
adi,conversion-start-gpios = < 0x07 0x11 0x00 >;
spi-cpha;
adi,first-data-gpios = < 0x07 0x16 0x00 >;
adi,oversampling-ratio-gpios = < 0x07 0x12 0x00 0x07 0x17 0x00 0x07 0x1a 0x00 >;
interrupt-parent = < 0x07 >;
interrupts = < 0x19 0x02 >;
reset-gpios = < 0x07 0x1b 0x00 >;
phandle = < 0xe9 >;
standby-gpios = < 0x07 0x18 0x01 >;
reg = < 0x00 >;
adi,sw-mode;
spi-max-frequency = < 0xf4240 >;
};
spidev#1 {
compatible = "spidev";
#address-cells = < 0x01 >;
#size-cells = < 0x00 >;
phandle = < 0xb0 >;
reg = < 0x01 >;
spi-max-frequency = < 0x7735940 >;
};
spidev#0 {
compatible = "spidev";
#address-cells = < 0x01 >;
#size-cells = < 0x00 >;
phandle = < 0xaf >;
reg = < 0x00 >;
spi-max-frequency = < 0x7735940 >;
};
};
During kernel boot with activated this overlay I have kernel message:
[ 5.171792] spi-bcm2835 fe204000.spi: chipselect 0 already in use
[ 5.171827] spi_master spi0: spi_device register error /soc/spi#7e204000/spidev#0
[ 5.171861] spi_master spi0: Failed to create SPI device for /soc/spi#7e204000/spidev#0
How to resolve this problem or make troubleshooting?

When approaching the gpio register address of RaspberryPi, why is the result different between unsigned int* and char*?

Using mmap(), I am going to write a value to the GPIO register address of the Raspberry Pi.
I thought the register value would have the same when reading mapped GPIO address in unsigned int * or char *, but it was not. I compared the results for both cases.
This is my code.
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#define GPIO_BASE 0x3F200000
#define GPFSEL1 0x04
#define GPSET0 0x1C
#define GPCLR0 0x28
int main()
{
int fd = open("/dev/mem", O_RDWR|O_SYNC);
// Error Handling
if (fd < 0) {
printf("Can't open /dev/mem \n");
exit(1);
}
// Map pages of memory
char *gpio_memory_map = (char*)mmap(0, 4096, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, GPIO_BASE);
// Error Handling
if (gpio_memory_map == MAP_FAILED) {
printf("Error : mmap \n");
exit(-1);
}
// GPIO18
//volatile unsigned int *gpio = (volatile unsigned int*)gpio_memory_map;
//gpio[GPFSEL1/4] = (1<<24);
volatile char *gpio = (volatile char *)gpio_memory_map;
int i;
for (i = 0; i < 16; i++)
printf("gpio[%d](%#x) = %#0x\n", i, &gpio[i], gpio[i]);
/*
for (i = 0; i < 5; i++) {
gpio[GPCLR0 / 4] = (1 << 18);
sleep(1);
gpio[GPSET0 / 4] = (1 << 18);
sleep(1);
}
*/
// Unmap pages of memory
munmap(gpio_memory_map, 4096);
return 0;
}
And those below are the results.
volatile unsigned int *gpio = (volatile unsigned int *)gpio_memory_map;
gpio[0](0x76f12000) = 0x1
gpio[1](0x76f12004) = 0x1000000
gpio[2](0x76f12008) = 0
gpio[3](0x76f1200c) = 0x3fffffc0
gpio[4](0x76f12010) = 0x24000924
gpio[5](0x76f12014) = 0x924
gpio[6](0x76f12018) = 0
gpio[7](0x76f1201c) = 0x6770696f
gpio[8](0x76f12020) = 0x6770696f
gpio[9](0x76f12024) = 0x6770696f
gpio[10](0x76f12028) = 0x6770696f
gpio[11](0x76f1202c) = 0x6770696f
gpio[12](0x76f12030) = 0x6770696f
gpio[13](0x76f12034) = 0x2ffbbfff
gpio[14](0x76f12038) = 0x3ef4ff
gpio[15](0x76f1203c) = 0
volatile char *gpio = (volatile char *)gpio_memory_map;
As the result #1 above, I thought gpio[1], gpio[2], gpio[3] should be 0. But it was different. And even if I try to write a new value on gpio[1] or gpio[2] or gpio[3], it stays the same. Why are the results different when approaching char * and unsigned char *?
gpio[0](0x76f47000) = 0x1
gpio[1](0x76f47001) = 0x69
gpio[2](0x76f47002) = 0x70
gpio[3](0x76f47003) = 0x67
gpio[4](0x76f47004) = 0
gpio[5](0x76f47005) = 0x69
gpio[6](0x76f47006) = 0x70
gpio[7](0x76f47007) = 0x67
gpio[8](0x76f47008) = 0
gpio[9](0x76f47009) = 0x69
gpio[10](0x76f4700a) = 0x70
gpio[11](0x76f4700b) = 0x67
gpio[12](0x76f4700c) = 0xc0
gpio[13](0x76f4700d) = 0x69
gpio[14](0x76f4700e) = 0x70
gpio[15](0x76f4700f) = 0x67

Checking the 13th-bit (shadow setting) from registry item (reg_binary)?

Using the following PowerShell code:
$RegConnect = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"CurrentUser", "$env:COMPUTERNAME")
$RegCursors = $RegConnect.OpenSubKey("Control Panel\Desktop", $true)
$myVal = $RegCursors.GetValue("UserPreferencesMask")
write-output $myVal
$RegCursors.Close()
$RegConnect.Close()
It returns:
190
30
7
128
18
1
0
0
From the MS help on UserPreferencesMask, the bit I'm after is the 13th, Cursor shadow.
13 Cursor shadow -- 1 Default
Cursor shadow is enabled. This effect only appears if the system has a color depth of more than 256 colors.
How can I extract the boolean for the current mouse shadow from this?
Here's the values in the on and off state.
on = "UserPreferencesMask"=hex:be,3e,07,80,12,01,00,00
off = "UserPreferencesMask"=hex:be,1e,07,80,12,01,00,00
It looks like you're adding 32 or 0x20 to the second byte to turn it on:
$myval[1] += 32 # on
$myval[1] -= 32 # off
Bitwise, "or" to set, "and" with "bit complement (not)" to unset.
0x1e -bor 0x20 # on
62
0x3e -band -bnot 0x20 # off
30
Maybe you could make a flags enum for all the settings, but you'd have to convert the byte array to one large int.
EDIT: Oh, if you just want to check that a bit is set:
$shadowbit = 0x20
if (0x3e -band $shadowbit ) { 'yep' } else { 'nope' } # 32
yep
if (0x1e -band $shadowbit ) { 'yep' } else { 'nope' } # 0
nope
See also How do you set, clear, and toggle a single bit?
EDIT:
I went a little overboard. Having this in preperation:
[Flags()] enum UserPreferencesMask {
ActiveWindowTracking = 0x1
MenuAnimation = 0x2
ComboBoxAnimation = 0x4
ListBoxSmoothScrolling = 0x8
GradientCaptions = 0x10
KeybordCues = 0x20
ActiveWindowTrackingZOrder = 0x40
HotTracking = 0x80
Reserved8 = 0x100
MenuFade = 0x200
SelectionFade = 0x400
ToolTipAnimation = 0x800
ToolTipFade = 0x1000
CursorShadow = 0x2000 # 13
Reserved14 = 0x4000
Reserved15 = 0x8000
Reserved16 = 0x10000
Reserved17 = 0x20000
Reserved18 = 0x40000
Reserved19 = 0x80000
Reserved20 = 0x100000
Reserved21 = 0x200000
Reserved22 = 0x400000
Reserved23 = 0x800000
Reserved24 = 0x1000000
Reserved25 = 0x2000000
Reserved26 = 0x4000000
Reserved27 = 0x8000000
Reserved28 = 0x10000000
Reserved29 = 0x20000000
Reserved30 = 0x40000000
UIEffects = 0x80000000 # 31
}
You can do:
$myVal = get-itemproperty 'HKCU:\Control Panel\Desktop' UserPreferencesMask |
% UserPreferencesMask
$b = [bitconverter]::ToInt32($myVal,0)
'0x{0:x}' -f $b
0x80073e9e
[UserPreferencesMask]$b
MenuAnimation, ComboBoxAnimation, ListBoxSmoothScrolling,
GradientCaptions, HotTracking, MenuFade, SelectionFade,
ToolTipAnimation, ToolTipFade, CursorShadow, Reserved16, Reserved17,
Reserved18, UIEffects
[UserPreferencesMask]$b -band 'CursorShadow'
CursorShadow
if ([UserPreferencesMask]$b -band 'CursorShadow') { 'yes' }
yes
Note that 3 undocumented reserved bits are already in use in my Windows 10. This is with "show shadows under mouse pointer" checked under "performance options" (advanced system) in the control panel
OR, getting simple without the enums:
$b = [bitconverter]::ToInt32($myVal,0) # 4 bytes from reg_binary to int
if ($b -band [math]::pow(2,13)) { 'cursor shadow' }
I've noticed that that registry entry is actually 8 bytes long, but bringing in all 8 bytes doesn't change the answer, even if some of those extra bits are set in windows 10.
To find the specific bit:
You need to calculate the byte index (starting from 0) by dividing the absolute bit index by 8:
[math]::floor(13 / 8) → byte 1 for the absolute bit 13
*Note: as #mklement0 pointed out, you can't use [Int] for this as is doesn't round down, see: division and rounding
Then calculate the relative bit index in that byte by finding the remainder (modulo) of the division:
$BitIndex - 8 * $ByteIndex → 13 - (8 * 1) = 5
*Note: I am not using the arithmetic operator (%) for the modulus due to the modulo operation with negative numbers issue and I used [math]::floor vs [math]::truncate for rounding. This way, the function also supports negative bit indices, with -1 referring to the most significant bit
Then create a byte mask from the relative bit:
[Byte][math]::pow(2, <relative bit>) → 25 = 32 (20h)
And finally mask (-bAnd) the concerned byte:
[Bool]($ByteArray[$ByteIndex] -bAnd $ByteMask) → 62 bAnd 32 = 32 (true), 30 bAnd 32 = 0 (false)
To make this more clear, I have put this in a Test-Bit function:
Function Test-Bit([Int]$BitIndex, [Byte[]]$ByteArray) {
$ByteIndex = [math]::floor($BitIndex / 8)
$ByteMask = [Byte][math]::pow(2, ($BitIndex - 8 * $ByteIndex))
[Bool]($ByteArray[$ByteIndex] -bAnd $ByteMask)
}
*Note: the Test-Bit function is based on little-endian byte order (see: Endianness)
Test:
Test-Bit 13 ([Byte[]](0xbe, 0x3e, 0x07, 0x80, 0x12, 0x01, 0x00, 0x00)) # True
Test-Bit 13 ([Byte[]](0xbe, 0x1e, 0x07, 0x80, 0x12, 0x01, 0x00, 0x00)) # False
Specific to your question:
$RegConnect = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"CurrentUser", "$env:COMPUTERNAME")
$RegCursors = $RegConnect.OpenSubKey("Control Panel\Desktop", $true)
$MyVal = $RegCursors.GetValue("UserPreferencesMask")
$State = Test-Bit 13 $MyVal
If ($State) {
# Cursor shadow is enabled
} Else {
# Cursor shadow is disabled
}
$RegCursors.Close()
$RegConnect.Close()

How to read data from MPU6050 using STM32F4

I need to monitorate the acelleration of a object. I'm using the MPU6050(accelerometer and gyroscope) and the controller STM32F401RBT6. The code below is the solution that i'm using for this.
#define MPU6050_ADDR 0xD0
#define SMPLRT_DIV_REG 0x19
#define GYRO_CONFIG_REG 0x1B
#define ACCEL_CONFIG_REG 0x1C
#define ACCEL_XOUT_H_REG 0x3B
#define TEMP_OUT_H_REG 0x41
#define GYRO_XOUT_H_REG 0x43
#define PWR_MGMT_1_REG 0x6B
#define WHO_AM_I_REG 0X75
uint16_t Accel_X_RAW,Accel_Y_RAW,Accel_Z_RAW;
uint16_t Ax,Ay,Az;
char buffer[10];
void MPU6050_Init(void)
{
uint8_t check, data;
HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,WHO_AM_I_REG,1,&check,1,100);
if(check == 104)
{
data = 0x07;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,SMPLRT_DIV_REG,1,&data,1,50);
HAL_Delay(50);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,ACCEL_CONFIG_REG,1,&data,1,50);
HAL_Delay(50);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,GYRO_CONFIG_REG,1,&data,1,50);
HAL_Delay(50);
data = 0;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,PWR_MGMT_1_REG,1,&data,1,50);
HAL_Delay(50);
}
}
void MPU6050_Read_Accel(void)
{
uint8_t recData[6];
for(int i=0;i<6;i++) recData[i] = 0;
HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,ACCEL_XOUT_H_REG,I2C_MEMADD_SIZE_8BIT,recData,6,100);
HAL_Delay(50);
uint16_t dataConvert1,dataConvert2;
dataConvert1 = (uint16_t)(0x0000 | recData[0]) << 8;
dataConvert2 = (uint16_t)(0x0000 | recData[1]);
Accel_X_RAW = dataConvert1 | dataConvert2;
dataConvert1 = (uint16_t)(0x0000 | recData[2]) << 8;
dataConvert2 = (uint16_t)(0x0000 | recData[3]);
Accel_Y_RAW = dataConvert1 | dataConvert2;
dataConvert1 = (uint16_t)(0x0000 | recData[4]) << 8;
dataConvert2 = (uint16_t)(0x0000 | recData[5]);
Accel_Z_RAW = dataConvert1 | dataConvert2;
Ax = (uint16_t)(Accel_X_RAW / 16384);
Ay = (uint16_t)(Accel_Y_RAW / 16384);
Az = (uint16_t)(Accel_Z_RAW / 16384);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_I2C3_Init();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
MPU6050_Init();
while (1)
{
MPU6050_Read_Accel();
sprintf(buffer, "%d / ", Accel_X_RAW);
CDC_Transmit_FS((char*)buffer,10);
}
}
I already did it on ATMEL Controler (Arduino) and it worked, but not on STM32.
I am trying to read the value of X Axis and show it using the USB CDC. This code sets a value for the `` `Accel_X_RAW```` variable between 0 and 65535. In Arduino, the reference value was 32768 when the object was stopped, but reading with STM32 remains at the maximum value (65535) if don't have movement. I don't know what's wrong with this code, I tried many options, but it still doesn't work. Can you help me please.
According to the MPU6050 datasheet, the 16-bit values for acceleration and gyroscope are returned in the signed 2's complement form (it detects acceleration values in the range +-g). As you are receiving signed data in the unsigned variables, the result is not what you expect. Therefore, replace all uint16_t datatypes with int16_t.
The reason why you are getting 65535 value; the hex value of -1 in signed int16_t form is 0xFFFF. However, if you store it in the uint16_t variable, it will be read as 65535. I am assuming that the default acceleration value at rest is -1g.
#include <stdlib.h> /* For using memset */
#define MPU6050_ADDR 0xD0
#define SMPLRT_DIV_REG 0x19
#define GYRO_CONFIG_REG 0x1B
#define ACCEL_CONFIG_REG 0x1C
#define ACCEL_XOUT_H_REG 0x3B
#define TEMP_OUT_H_REG 0x41
#define GYRO_XOUT_H_REG 0x43
#define PWR_MGMT_1_REG 0x6B
#define WHO_AM_I_REG 0X75
int16_t Accel_X_RAW,Accel_Y_RAW,Accel_Z_RAW;
int16_t Ax,Ay,Az;
char buffer[10];
void MPU6050_Init(void)
{
uint8_t check, data;
HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,WHO_AM_I_REG,1,&check,1,100);
if(check == 104)
{
data = 0x07;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,SMPLRT_DIV_REG,1,&data,1,50);
HAL_Delay(50);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,ACCEL_CONFIG_REG,1,&data,1,50);
HAL_Delay(50);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,GYRO_CONFIG_REG,1,&data,1,50);
HAL_Delay(50);
data = 0;
HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,PWR_MGMT_1_REG,1,&data,1,50);
HAL_Delay(50);
}
}
void MPU6050_Read_Accel(void)
{
uint8_t recData[6];
//for(int i=0;i<6;i++) recData[i] = 0;
memset(recData, 0, sizeof(recData));
HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,ACCEL_XOUT_H_REG,I2C_MEMADD_SIZE_8BIT,recData,6,100);
HAL_Delay(50);
Accel_X_RAW = (int16_t)(recData[0] << 8 | recData[1]);
Accel_Y_RAW = (int16_t)(recData[2] << 8 | recData[3]);
Accel_Z_RAW = (int16_t)(recData[4] << 8 | recData[5]);
Ax = (int16_t)(Accel_X_RAW / 16384);
Ay = (int16_t)(Accel_Y_RAW / 16384);
Az = (int16_t)(Accel_Z_RAW / 16384);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_I2C3_Init();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
MPU6050_Init();
while (1)
{
MPU6050_Read_Accel();
sprintf(buffer, "%d / ", Accel_X_RAW);
CDC_Transmit_FS((char*)buffer,10);
}
}

How to convert hex string to byte array in CAPL?

Considering having, for example, this type of hex string:
char hex_str[100] = "0x01 0x03 0x04 0x0A";
How to get out of this string the byte array representation in CAPL, like:
byte hex_str_as_byte_arr[4] = {0x01, 0x03, 0x04, 0x0A};
EDIT: Only Vector CANoe supported data types/functions are allowed!
Use strtok to split the character array into separate hex strings, then use long strtol( const char *restrict str, char **restrict str_end, int base ) to convert each hex string to an integral value.
Thanks to all...
Actually I've found a solution myself:
char hex_str[100] = "0x01 0x03 0x04 0x0A";
long data[4];
dword pos = 0;
pos = strtol(hex_str, pos, data[0]);
pos = strtol(hex_str, pos, data[1]);
pos = strtol(hex_str, pos, data[2]);
pos = strtol(hex_str, pos, data[3]);
write("0x%02x,0x%02x,0x%02x, 0x%02x", data[0], data[1], data[2], data[3]);
Now it's a simple cast: (byte) data[0]
We can use sscanf() to convert the numbers to unsigned char. In a loop, we'll need to also use a %n conversion to determine the reading position for the next iteration.
Here's a simple example (in real life, you'll need some range checking to make sure you don't overrun the output buffer):
#include <stdio.h>
int main(void)
{
const char hex_str[100] = "0x01, 0x03, 0x04, 0x0A";
unsigned char bytes[4];
{
int position;
unsigned char *b = bytes;
for (const char *input = hex_str; sscanf(input, "%hhi, %n", b, &position) == 1; ++b) {
input += position;
}
}
/* prove we did it */
for (size_t i = 0; i < sizeof bytes; ++i) {
printf("%hhu ", bytes[i]);
}
puts("");
}