"""
Lab002. Формирование и разбор первого цифрового пакета.

Пакет содержит:
- маркер начала;
- версию протокола;
- тип сообщения;
- порядковый номер;
- длину полезных данных;
- полезные данные.
"""

import struct


# ============================================================
# Константы протокола
# ============================================================

SYNC_WORD = 0xAA55
PROTOCOL_VERSION = 1

MESSAGE_TYPE_TEXT = 1


# ============================================================
# Исходные данные
# ============================================================

message = "ПРИВЕТ SDR"
payload = message.encode("utf-8")

sequence_number = 1
message_type = MESSAGE_TYPE_TEXT
payload_length = len(payload)


# ============================================================
# Формирование заголовка
# ============================================================

# Формат:
# >  — порядок байтов от старшего к младшему, big-endian
# H  — беззнаковое целое число размером 2 байта
# B  — беззнаковое целое число размером 1 байт
# B  — ещё одно число размером 1 байт
# H  — порядковый номер размером 2 байта
# H  — длина данных размером 2 байта
HEADER_FORMAT = ">HBBHH"

header = struct.pack(
    HEADER_FORMAT,
    SYNC_WORD,
    PROTOCOL_VERSION,
    message_type,
    sequence_number,
    payload_length,
)

packet = header + payload


# ============================================================
# Вывод сформированного пакета
# ============================================================

print("Исходное сообщение:")
print(message)

print("\nПолезная нагрузка PAYLOAD:")
print(payload)

print("\nДлина PAYLOAD:")
print(payload_length, "байт")

print("\nЗаголовок пакета:")
print(header)

print("\nПолный пакет:")
print(packet)

print("\nПакет в шестнадцатеричном виде:")
print(packet.hex(" "))

print("\nОбщая длина пакета:")
print(len(packet), "байт")


# ============================================================
# Разбор пакета на стороне приёмника
# ============================================================

header_size = struct.calcsize(HEADER_FORMAT)

received_header = packet[:header_size]
received_payload = packet[header_size:]

(
    received_sync,
    received_version,
    received_type,
    received_sequence,
    received_length,
) = struct.unpack(HEADER_FORMAT, received_header)


print("\n--- Разбор принятого пакета ---")

print("SYNC:")
print(hex(received_sync))

print("\nВерсия протокола:")
print(received_version)

print("\nТип сообщения:")
print(received_type)

print("\nПорядковый номер:")
print(received_sequence)

print("\nДлина из заголовка:")
print(received_length, "байт")

print("\nФактически принято данных:")
print(len(received_payload), "байт")


# ============================================================
# Проверки
# ============================================================

assert received_sync == SYNC_WORD
assert received_version == PROTOCOL_VERSION
assert received_type == MESSAGE_TYPE_TEXT
assert received_sequence == sequence_number
assert received_length == len(received_payload)

restored_message = received_payload.decode("utf-8")

assert restored_message == message


print("\nВосстановленное сообщение:")
print(restored_message)

print("\nПроверка пройдена: пакет сформирован и разобран без ошибок.")