Как выделить байты из битового массива со словами по 10 бит?

Весь массив DecoderData выглядит как набор бит:

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1

Формат такой: первый "0" - это стартовый бит 10-битного слова. Затем 8 бит данных - их я пробую достать. Затем стоповый бит "1".

В общем, каждые 10 бит начиная с первого нуля - это слова.

По коду...
Ищу первый элемент с 0, потом следующие 8 бит копирую в другой массив, потом перехожу к следующей десятке и снова копирую 8 бит в другой массив. Но почему-то копирование не происходит.

for (var i = 0; i < DecoderData.length; ++i) {
    if (DecoderData[i] == 0) {
        finaldata.push + DecoderData.slice(i + 1, i + 10);
        // console.log('959: ',i ,finaldata[i]);  
        i += 10;
    }
}

Ответы (2 шт):

Автор решения: maestro

Протокол последовательного порта устроен так. При простое уровень всегда высокий. Когда начинается передача, уровень сигнала падает до нуля и длится один бит (стартовый бит). Затем передаются 8 информационных бит. Затем передаётся стоповый бит. Стоповых бит может быть 1, 1.5 или 2.

Длинную последовательность единиц в начале массива рассматриваем как тишину. Только увидев первый нуль берём его за стартовый бит. И далее декодируем информационные биты. Если после стопового бита попадаются единицы, то рассматриваем их как тишину.

Этот код выдаёт ошибку формата кадра. Но это уж такие данные вы нам предоставили. То, что получилось декодировать, код выводит в шестнадцатеричном и текстовом виде. В текстовом виде непечатные символы заменяются на точку.

const b = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1]
//        |   ^^^         тишина      ^^^            | ^-- первый стартовый бит
DecoderData = Array.from(b);

for (let i = 0; i < DecoderData.length; i++) {
  if (DecoderData[i] !== 0 && DecoderData[i] !== 1) {
    console.error(`Ошибка: недопустимое значение ${DecoderData[i]} на позиции ${i}`);
    DecoderData[i] = 0; // исправим для продолжения разбора
  }
}

let bytes = [];
let i = 0;

// Пропускаем ведущие единицы (простой)
while (i < DecoderData.length && DecoderData[i] === 1) i++;

while (i < DecoderData.length) {
  if (DecoderData[i] !== 0) {
    console.error(`Ошибка: ожидался стартовый бит (0), позиция ${i}`);
    break;
  }
  i++; // стартовый бит

  if (i + 8 >= DecoderData.length) {
    console.error(`Ошибка: неполный байт в конце, позиция ${i}`);
    break;
  }

  // читаем 8 бит данных (LSB first)
  let byteVal = 0;
  for (let bit = 0; bit < 8; bit++) {
    const bitVal = DecoderData[i++];
    byteVal |= (bitVal << bit);
  }

  // Проверяем стоп-бит
  if (i >= DecoderData.length) {
    console.error(`Ошибка: отсутствует стоп-бит после байта ${bytes.length}, позиция ${i}`);
    break;
  }
  const stopBit = DecoderData[i++];
  if (stopBit !== 1) {
    console.error(`Ошибка: стоп-бит должен быть 1, найдено ${stopBit} на позиции ${i - 1}`);
    break;
  }

  bytes.push(byteVal);

  // Пропускаем промежуточные "тишины" (единицы)
  while (i < DecoderData.length && DecoderData[i] === 1) i++;
}

// Вывод результата
if (bytes.length > 0) {
  const hex = bytes.map(b => b.toString(16).padStart(2, '0')).join(' ');
  const ascii = bytes.map(b => {
    const c = String.fromCharCode(b);
    return (b >= 32 && b <= 126) ? c : '.';
  }).join('');

  console.log("HEX:", hex);
  console.log("ASCII:", ascii);
} else {
  console.log("Не удалось декодировать ни одного байта.");
}

→ Ссылка
Автор решения: Solt

Приведу свой вариант. Все комментарии в коде.

Я предусмотрел варианты, когда валидация стоп-бита сдвигает на бит и на весь байт.

Также предусмотрен альтернативный вариант для BE/LE.

Вывод - в массив с байтами и их текстовыми бинарными представлениями.

Алгоритм реализует подход, принятый при программировании микроконтроллеров - всё в единственном цикле.

const b = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1]

let
reading=0, //Признак чтения байта.
bit=0, //Номер бита
byte=0, //Собираемый байт
byte_txt='', //Текстовое представление байта
bytes=[]; //Массив для результата

for (let i = 0; i < b.length; i++){
  log(i,b[i])
  if(!reading && b[i]) continue; //Тишина
  if(!reading){ //Старт чтения
    log('старт');
    if(!b?.[i+9]){ //Кривой стоп, или данных не хватило
      log('Кривой стоп');
      //Считаем, что старт-бит был неправильный и двигаемся дальше
      //Если надо отбросить весь байт
      //i+=9;
      continue;
    }
    reading=1;
    bit=0;
    byte_txt='';
    byte=0;
    i++; // Сдвигаемся и идём читать первый бит. Можно заменить на continue
  }
  if(bit>7){ //Конец байта
    log('Байт: ',byte,byte_txt)
    bytes.push([byte,byte_txt])
    reading=0;
    i++; //Проскакиваем стоп-бит
    continue;
  }
  //Little Endian - младшие биты в конце
  byte_txt=b[i]+byte_txt;
  byte+=b[i]<<(bit++);
  
  //Big Endian - старшие биты в конце
  //byte_txt+=b[i];
  //byte+=(b[i]*128)>>(bit++);

}

log(bytes)

function log(...a){
  console.log(...a)
}

→ Ссылка