4 последовательных байта в буфере в unsigned long
Интересно, есть ли более умный способ получить эти 4 последовательных байта из буфера, объединенных в unsigned long.
// временная метка начинается с байта 40 принятого пакета и составляет четыре байта,
// или два слова, длинные. Сначала извлеките два слова:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// объединить четыре байта (два слова) в длинное целое число
// это время NTP (секунды с 1 января 1900 г.):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print("Seconds since Jan 1 1900 = ");
Serial.println(secsSince1900);
Мне кажется, это излишество, поскольку эти 4 байта уже идут подряд в буфере.
Результат должен быть неизменным, т.е. иметь значение в переменной.
@neurino, 👍0
Обсуждение3 ответа
Лучший ответ:
В итоге я сделал это:
unsigned long ntp_time = 0;
for (byte i = 0; i < 4; i++){
ntp_time = ntp_time << 8 | (byte) packetBuffer[40 + i];
}
Это то, что я бы использовал на языке высокого уровня, и моя первая попытка до того, как спросить, — которая не удалась, потому что в ней не было приведения к байту.
Мне все еще нужно понять, почему это не удалось, поскольку packetBuffer был объявлен как
const byte *packetBuffer
что, как мне кажется, уже адресует байты...
Спасибо Majenko за помощь, его решение по-прежнему преобразует все байты буфера в 4 байта, я предпочитаю свой, который ограничивается байтами.
Приведение к byte бесполезно. Если без приведения тип не работает, это, вероятно, связано с какой-то не связанной с этим проблемой, которую вы исправили примерно в то же время, когда добавили приведение. В таких ситуациях может помочь программа отслеживания версий., @Edgar Bonet
Если бы они были в том же порядке байтов, что и long (в Arduino — в порядке байтов от младшего к старшему, чего, судя по всему, не происходит), вы могли бы просто указать на них:
uint32_t *l = (uint32_t *)&packetBuffer[40];
Затем используйте *l для доступа к содержимому как к длинному.
Однако, поскольку они выглядят в порядке big-endian, это не так просто. Самое простое, что вы можете сделать, это просто объединить их заново с помощью битового сдвига:
uint32_t l = ((uint32_t)packetBuffer[40] << 24) | ((uint32_t)packetBuffer[41] << 16) |
((uint32_t)packetBuffer[42] << 8) | (uint32_t)packetBuffer[43];
Если я добавлю последнюю строку вашего кода, а затем выполню Serial.println(secsSince1900, HEX); Serial.println(secsSince1900, HEX);, я получу DEAAC142 и FFFFC142. Есть подсказка?, @neurino
На самом деле, на небольшом 8-битном изображении может потребоваться приводить значения к 32-битному перед сдвигом битов, чтобы избежать клиппинга. Давно я не пользовался такими маленькими чипами., @Majenko
Действительно. Если и int, и тип packetBuffer[40] меньше 32 бит, то packetBuffer[40] << 24 вызывает неопределённое поведение., @Edgar Bonet
Спасибо за ваши ответы, вы помогли мне найти ошибку в моем коде., @neurino
Альтернативой является использование union и struct, и предоставление компилятору возможности выполнить работу:
static inline uint32_t bswap32(uint32_t x)
{
union {
uint32_t x;
struct {
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t d;
} s;
} in, out;
in.x = x;
out.s.a = in.s.d;
out.s.b = in.s.c;
out.s.c = in.s.b;
out.s.d = in.s.a;
return out.x;
}
uint32_t sinceEpoch = bswap32(*(uint32_t*) &packetBuffer[40]);
Ссылка http://lists.nongnu.org/archive/html/avr-gcc-list/2006-12/msg00076.html
Чистая переписывание буфера пакетов будет выглядеть так:
static inline uint32_t bswap32(uint8_t* buf)
{
union {
uint32_t x;
struct {
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t d;
} s;
} in, out;
out.s.a = buf[3];
out.s.b = buf[2];
out.s.c = buf[1];
out.s.d = buf[0];
return out.x;
}
uint32_t sinceEpoch = bswap32(&packetBuffer[40]);
Вот версия машинного кода AVR:
inline uint32_t bswap32(uint32_t value)
{
asm volatile("mov __tmp_reg__, %A0" "\n\t"
"mov %A0, %D0" "\n\t"
"mov %D0, __tmp_reg__" "\n\t"
"mov __tmp_reg__, %B0" "\n\t"
"mov %B0, %C0" "\n\t"
"mov %C0, __tmp_reg__" "\n\t"
: "=r" (value)
: "0" (value)
);
return (value);
}
Ссылка. Cosa/Types.h, https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/Types.h#L553 и Cosa-NTP/NTP.cpp, https://github.com/mikaelpatel/Cosa-NTP/blob/master/NTP.cpp#L56
- Как перевести float в четыре байта?
- Проблемы с преобразованием byte[] в String
- Шестнадцатеричное/Байтовое реверсирование и преобразование
- Как поменять порядок байтов местами
- Отправка многобайтовых данных по I2C между разными процессорами
- Как преобразовать 6 байт необработанных данных в тип long long?
Это зависит от того, находятся ли они в том же порядке байтов (то есть в порядке от младшего к старшему), что и тип данных Long в Arduino. Судя по вашему текущему методу, это не так., @Majenko