Класс BinaryPrimitives в .NET. Замена для BitConverter

Оказывается, ещё начиная с .NET Standard в сборку System.Memory в нейсмпейс System.Buffers.Binary завезли класс BinaryPrimitives — расширенный аналог System.BitConverter. У BitConverter было два основных недостатка:

  1. BitConverter всегда конвертировал данные в соответствии c Endianess текущего процессора. Например, если приложение запущено на процессоре Intel x86 (amd64)-совместимой архитектуры, то порядок байт будеn Little-endian.
  2. BitConverter не умеет работать со Span<byte>.

Лично мне нужна была поддержка Big-endian и Span<T> и приходилось писать свои конверторы. Теперь можно пользоваться методами из BinaryPrimitives.

Например:

using System.Buffers.Binary;

public static ushort GetYear(ReadOnlySpan<byte> dateTime)
{
  return BinaryPrimitives.ReadUInt16BigEndian(dateTime.Slice(2));
}

Костыли в коде

Причины для костылей:

  1. Ошибка в ПО нижнего уровня. Решение этой ошибки перекладывается по ПО верхнего уровня. 
  2. Добавление функциональности, которая не предполагается текущей архитектурой ПО.

Если причина №1, то нужно следовать золотому правило костылизации: знание о костыле должно быть минимизировано (костыль должен подставляться максимально близко к месту проблемы, порождающего необходимость в костыле).

Если причина №2, то нужно следовать принципу инкостыляции (аллюзия на инкапсуляцию): код, связанный с костылём должен быть собран в одно место (один файл, один класс, и т.п.). Далее этот код вызывается из нужных мест в программе. 

Visual Studio C# Snippets

Code Snippet — очень удобная штука для автоматической генерации фрагментов кода в Visual Studio по коротким аббревиатурам.

например вводите в редакторе кода

cw

Нажимате два раза Tab, и получаете:

Console.WriteLine();

Очень упрощает труд наборщика 🙂

Как написать свой snippet. Краткий обзор:

  1. Краткое руководство, которое поможет быстро написать свой первый сниппет.
  2. Примеры от Microsoft
  3. Справочник от Microsoft

 

Протокол HDLC + DLMC\COSEM. Основы

Пишу, чтобы не забыть.

Протокол HDLC — канального уровня. Внутри информационного поля, содержит сообщения протокола DLMS\COSEM.

Литература:

HDLC (High-Level Data Link Control) — бит-ориентированный протокол
высокоуровневого управления каналом передачи данных, описанный в ISO/IEC 13239. Протокол имеет 2 подуровня:

  • LLC (Logical Link Control) — управление логической связью, т.е. управление
    передачей данных и контроль правильности передачи данных;
  • MAC (Media Access Control) — управление доступом к среде передачи.

Наш пациент — MAC (Media Access Control)

Формат фрейма (кадра) HDLC MAC типа 3

Flag — байт 0x7E открывает и закрывает каждый кадр. Источники утверждают, что если в поле Information встречается байт 0x7E, то он должен быть заменён на что-то другое. Я это не проверял.

Format определяет тип кадра, наличие сегментации кадров, длину кадра.

Поле Format в HDLC кадре

Бит S, установленный в «1», говорит о необходимости принять этот и последующие фреймы, как единый блок. В последнем фрейме блока бит S должен быть сброшен в «0».
Длина фрейма включает в себя все поля, кроме флагов.

Продолжение следует…

P.S. Я начал писать этот текст год назад, когда начал разбираться в HDLC, читая Green Book. Дописать не успел. Сейчас я всё забыл напрочь 🙂 
Разбирайтесь сами.

P.P.S. Кто-то нафигачил хорошую статью по DLMS COSEM протоколу https://habr.com/ru/post/650579/

 

Формат фрейма DLMS

Допустим, что тебе нужно обратиться к электросчётчику, который умеет разговаривать на DLMS\COSEM. Чтобы понять основы смотри, например, синюю книгу. (можешь скачать её на рутрекере)

И спросил ты у счётчика, например, таблицу специальных дней (интерфейсный класс 11). И ответил тебе счётчик. В синей книге описан формат ответа:

array spec_day_entry
spec_day_entry ::= structure
{
index: long-unsigned,
specialday_date: octet-string,
day_id: unsigned
}
Where:
- specialday_date formatting follows the rules set in 4.1.6.1 for date;
- the range of the day_id shall match the length of the bit-string exec_specdays in the related object of IC “Schedule”.

Что это значит?

array spec_day_entry

Ответ содержит array, внутри которого структуры spec_day_entry, формат структуры

spec_day_entry ::= structure 
{ 
index: long-unsigned, 
specialday_date: octet-string, 
day_id: unsigned 
}

рамерность и прочее описание этих типов данных смотрите в той же синей книге.

Но это не всё. Смотрим на ответ счётчика:

01 0B 02 03 12 00 01 09 05 07 E2 01 01 FF 11 02 02 03 12 00
02 09 05 07 E2 01 02 FF 11 02 02 03 12 00 03 09 05 07 E2 01
03 FF 11 02 02 03 12 00 04 09 05 07 E2 01 14 FF 11 01 02 03
12 00 05 09 05 07 E2 02 0A FF 11 01 02 03 12 00 06 09 05 07
E2 02 17 FF 11 02 02 03 12 00 07 09 05 07 E2 03 08 FF 11 02
02 03 12 00 08 09 05 07 E2 03 09 FF 11 02 02 03 12 00 09 09
05 07 E2 05 01 FF 11 02 02 03 12 00 0A 09 05 07 E2 05 02 FF
11 02 02 03 12 00 0B 09 05 07 E2 05 09 FF 11 02

Для того чтобы объяснить на примере, разобью байты

01 0B
  02 03
    12 	00 01 
    09 05 	07 E2 01 01 FF 
    11 	02 
  02 03 
    12 	00 02 
    09 05	07 E2 01 02 FF 
    11 	02 
  02 03 
    12 	00 03 
    09 05 	07 E2 01 03 FF 
    11 	02 
  02 03 
    12	00 04
    09 05	07 E2 01 14 FF
    11 	01

Объясняю:

//1 байт - тип данных (01 - это array)
//2 байт в случае массива - это длина массива (0B - 11 элементов)
01 0B
  //далее идут элементы массива

  //02 - тип данных (структура)
  //03 - кол-во элементов струкруты (в нашем случае - три элемента (index, date, day_id)
  02 03
    //далее идут элементы структуры
    //12 - тип данных (unsigned long - так называется двухбайтное целое без знака)
    //00 01 - значение
    12 	00 01 

    //09 - тип данных (octet byte string - набор байтов (такой тип данных для даты))
    //05 - длина octet byte string (5 байт)
    //07 E2 01 01 FF - сама байтовая строка. Нам нужно её интерпертировать как Date (формат описан в синей книге)
    09 05 	07 E2 01 01 FF 

    //11 - тип данных unsigned (целое 8 бит без знака)
    //02 - значение
    11 	02 

  //и так далее...
  02 03 
    12 	00 02 
    09 05	07 E2 01 02 FF 
    11 	02 
  02 03 
    12 	00 03 
    09 05 	07 E2 01 03 FF 
    11 	02 
  02 03 
    12	00 04
    09 05	07 E2 01 14 FF
    11 	01

 

 

Convert RSSI GSM Signal Strength to dBM

Термины

RSSI (received signal strength indicator) — Показатель уровня принимаемого сигнала.

RSSI index (он же GSM singnal strength) — индекс уровня принимаемого сигнала. Может принимать значения:

RSSI index RSSI in dBm
0  113 dBm or less
1 111 dBm
2…30 109… 53 dBm
31 51 dBm or greater
99 not known or not detectable

Формулы для конвертации

(1) percentage = rssi * 100 / max_rssi

rssi — RSSI как индекс (от 0 до 31)
max_rssi = 31
percentage = процентный показатель уровня принимаемого сигнала

(2) dBm = 2 * rssi — 113

Подсмотрел здесь:
https://together.jolla.com/question/117679/how-can-one-retrieve-rxlev-dbm-signal-strength-value/
http://m2msupport.net/m2msupport/atcsq-signal-quality/

Счётчик жизни

До окончательной старости осталось: