Невозможно прочитать двоичные данные в виде строки на приемном конце передачи SerialPort - PullRequest
0 голосов
/ 07 ноября 2019

Все еще не уверен, что заголовок для этого вопроса ...

Я использую .Net Framework, используя serialPort.ReadExisting() (который возвращает строку), а не serialPort.Read() (которыйвозвращает байтовый массив). Я делаю это потому, что serialPort.ReadExisting() дает мне доступ к данным потока, которые еще не находятся в буфере, вместе с буфером SerialPort. Однако этот метод требует, чтобы я считывал данные в виде строки, но, похоже, нет способа сообщить последовательному порту «Привет, используйте кодировку base64», и вместо этого я могу выбрать ASCII, UTF8 и т. Д. serialPort.Encoding = Encoding.ASCII;. Теперь я знаю, что мои данные не проблема, потому что этот ТЕСТ работает:

                string a = Convert.ToBase64String(transmitBytes, Base64FormattingOptions.None);
                byte[] b = Convert.FromBase64String(a);
                SHA256 sha256 = SHA256.Create();
                byte[] hash1 = sha256.ComputeHash(transmitBytes);
                byte[] hash2 = sha256.ComputeHash(b);
                if (CompareHash(hash1, hash2))
                    Console.WriteLine("good check");
            }
            private static bool CompareHash(byte[] a1, byte[] a2)
            {
                for (int i = 0; i < a1.Length; i++)
                {
                    if (a1[i] != a2[i])
                        return false;
                }
                return true;
            }

Но если я отправляю свои данные по проводам, у меня возникают проблемы. Моя теория состоит в том, что это происходит потому, что метод ReadExisting () пытается прочитать биты как 7-битные значения ascii, и многие части данных будут вне диапазона 6-битовых символов base64: такие вещи, как [, _ и| может вызвать проблему, которая может возникнуть, если принимающая сторона пытается прочитать 7 бит, а не 6.

Я попытался настроить последовательную связь в среде с низким уровнем шума, и я 'мы пробовали несколько комбинаций длин данных для отправки на последовательное сообщение.

Ниже приведен соответствующий код, вызывающий нарушение (последняя строка выдает исключение):

    // sending machine is working I think
    serialPort.DataBits = 8; //also tried (6 and 7) many many times)
    _serialPort.Write(Convert.ToBase64String(transmitBytes, Base64FormattingOptions.None));

    // receiver machine is trowing the format exception
    serialPort.DataBits = 8; // also tried (6 and 7) many many times)
    byte[] BigBuffer = new byte[_serialPort.ReadBufferSize];
    // read data then discard buffer to get new data from the transmitting machine
    BigBuffer = Convert.FromBase64String(_serialPort.ReadExisting()); // throws exception

Любая идея, как я могу отлаживать, и, надеюсь,исправить то, что происходит? Я не хочу прибегать к serialPort.Read ()

exception.Message = "The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters."

Дополнительный тестовый сценарий: я отправил небольшую нереалистичную строку значений для целей отладки и получил то же исключение. Я ДОЛЖЕН ИМЕТЬ ПЕРЕДАЧУ ПЕРЕДАТЧИКА ЕГО ОТПРАВЛЯТЬ, ПОЭТОМУ ОНА ОТПРАВЛЯЕТ ЭТО ЗНАЧЕНИЕ НЕСКОЛЬКО РАЗ, ПРЕЖДЕ ЧЕМ ПРИЕМЧИК ХИТ ИСКЛЮЧЕНИЕ. Вот исходная строка base64:

utz+EDJUdpgLAAAATG9yZSBpbXBzdW3UAPpp4FQlifaZAzUzyh25062szzbhSyVs3ehe6nU+UYlnRSMB782r

Вот строка, полученная от ReadExisting () (я предполагаю, что это ASCII, поскольку serialPort установлен в кодировку ASCII). Эта строка вызывает исключение при передаче в Convert.FromBase64String ()

dW3UAPpp4FQlifaZAzUzyh25062szzbhSyVs3ehe6nU+UYlnRSMB782rutz+EDJUdpgLAAAATG9yZSBpbXBzdW3UAPpp4FQlifaZAzUzyh25062szzbhSyVs3ehe6nU+UYlnRSMB782rutz+EDJUdpgLAAAATG9yZSBpbXBzdW3UAPpp4FQlifaZAzUzyh25062szzbhSyVs3ehe6nU+UYlnR

Ответы [ 3 ]

0 голосов
/ 07 ноября 2019

Я ДОЛЖЕН ИМЕТЬ ПЕТЛЯ ПЕРЕДАЧИ ЕГО ОТПРАВЛЯЕТ, ЧТО ЭТО ОТПРАВЛЯЕТ ЭТО ЗНАЧЕНИЕ НЕСКОЛЬКО РАЗ, ПРЕЖДЕ ЧЕМ ПРИЕМЧИК ХИТ ИСКЛЮЧЕНИЕ.

Тогда это проблема с Обнаружением / Исправлением ошибок. Фактически, то, что вы делаете здесь, работает непосредственно на уровнях 2-4 модель OSI . Тип слоев, с которыми вы обычно не работаете. Среднестатистический программист имеет дело только со слоями 7, 6 и (для HTTP) 5.

На самом деле во всем стеке есть несколько уровней предотвращения, исправления и обнаружения ошибок. Есть только 2 реальных варианта:

  1. Хватит пытаться работать на этом уровне. Найдите кого-нибудь еще проверенный код, чтобы вы могли вернуться к слою 7-5, среднему рабочему пространству программистов.
  2. Переопределите все эти функции обнаружения, предотвращения и исправления ошибок самостоятельно. Это намного сложнее, чем просто старая посылка.
0 голосов
/ 08 ноября 2019

Сообщение об ошибке, вероятно, не подходит.
Однако верно, что строка параметра, переданная в Convert.FromBase64String(), не соответствует спецификации base64.

Если последняя заданная вами строка является именно тем параметром, который вы передали Convert.FromBase64String(), его длина равна 217 , она не кратна 4 и соответствуетне соответствует спецификации base64.

Следовательно, это могло вызвать исключение.

Метод Convert.FromBase64String (String)

Исключения
FormatException
Длинаs, игнорируя пробелы, не является нулем или кратным 4.

-или-

Формат s недопустим. s содержит не базовый 64-символ, более двух символов заполнения или непустой пробел среди символов заполнения.

Вместо того, чтобы просто преобразовывать двоичные данные в base64 и отправлять / получать их, добавьте некоторые данные, которые могут проверить, все ли данные были получены, или разделите длинные данные на короткие блоки и прикрепите проверочные данные втаким же образом, пожалуйста, придумайте, такие как отправка и получение

0 голосов
/ 07 ноября 2019

Я бы просто записал байты в последовательный порт.

var yourBytes = Encoding.UTF8.GetBytes(base64Str); // or transmitBytes directly without encoding
_serialPort.Write(yourBytes, 0, yourBytes.Length);

Затем прочитал байты.

var myBuffer = new byte[yourBytes.Length];
_serialPort.Read(myBuffer, 0, myBuffer.Length);

Затем вы можете выполнить любое из следующих действий

Convert.ToBase64String
Convert.FromBase64String
Encoding.UTF8.GetString
Encoding.UTF8.GetBytes
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...