diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..984c347101f288f66c4549f4430b6964d3f5d706 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +This project is licensed under the terms of the GPLv3, unless otherwise stated, especially in the external/ directory. + +See the individual files for more information. + + + +# Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0 + * external/rp_devices.py: Copyright (c) 2021 Jeremy P Bentham + * programs/adc_test.py based on https://github.com/jbentham/pico/blob/main/rp_adc_test.py, which is Copyright (c) 2021 Jeremy P Bentham diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000000000000000000000000000000000000..a4b2b4eef67f2b50bff083e793d7fff30fd46577 --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ +# To do + +## Life-sign support + +## Network errors +- Centralize network restart functionality. \ No newline at end of file diff --git a/umnp/protocol/compat/__init__.py b/external/__init__.py similarity index 100% rename from umnp/protocol/compat/__init__.py rename to external/__init__.py diff --git a/external/rp_devices.py b/external/rp_devices.py new file mode 100644 index 0000000000000000000000000000000000000000..f292b6d728fe0df748464466953f4db19298e3f3 --- /dev/null +++ b/external/rp_devices.py @@ -0,0 +1,177 @@ +# RP2040 uctype definitions for MicroPython +# See https://iosoft.blog/pico-adc-dma for description +# +# Copyright (c) 2021 Jeremy P Bentham +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from uctypes import BF_POS, BF_LEN, UINT32, BFUINT32, struct + +GPIO_BASE = 0x40014000 +GPIO_CHAN_WIDTH = 0x08 +GPIO_PIN_COUNT = 30 +PAD_BASE = 0x4001C000 +PAD_PIN_WIDTH = 0x04 +ADC_BASE = 0x4004C000 +DMA_BASE = 0x50000000 +DMA_CHAN_WIDTH = 0x40 +DMA_CHAN_COUNT = 12 + +# DMA: RP2040 datasheet 2.5.7 +DMA_CTRL_TRIG_FIELDS = { + "AHB_ERROR": 31 << BF_POS | 1 << BF_LEN | BFUINT32, + "READ_ERROR": 30 << BF_POS | 1 << BF_LEN | BFUINT32, + "WRITE_ERROR": 29 << BF_POS | 1 << BF_LEN | BFUINT32, + "BUSY": 24 << BF_POS | 1 << BF_LEN | BFUINT32, + "SNIFF_EN": 23 << BF_POS | 1 << BF_LEN | BFUINT32, + "BSWAP": 22 << BF_POS | 1 << BF_LEN | BFUINT32, + "IRQ_QUIET": 21 << BF_POS | 1 << BF_LEN | BFUINT32, + "TREQ_SEL": 15 << BF_POS | 6 << BF_LEN | BFUINT32, + "CHAIN_TO": 11 << BF_POS | 4 << BF_LEN | BFUINT32, + "RING_SEL": 10 << BF_POS | 1 << BF_LEN | BFUINT32, + "RING_SIZE": 6 << BF_POS | 4 << BF_LEN | BFUINT32, + "INCR_WRITE": 5 << BF_POS | 1 << BF_LEN | BFUINT32, + "INCR_READ": 4 << BF_POS | 1 << BF_LEN | BFUINT32, + "DATA_SIZE": 2 << BF_POS | 2 << BF_LEN | BFUINT32, + "HIGH_PRIORITY": 1 << BF_POS | 1 << BF_LEN | BFUINT32, + "EN": 0 << BF_POS | 1 << BF_LEN | BFUINT32, +} +# Channel-specific DMA registers +DMA_CHAN_REGS = { + "READ_ADDR_REG": 0x00 | UINT32, + "WRITE_ADDR_REG": 0x04 | UINT32, + "TRANS_COUNT_REG": 0x08 | UINT32, + "CTRL_TRIG_REG": 0x0C | UINT32, + "CTRL_TRIG": (0x0C, DMA_CTRL_TRIG_FIELDS), +} +# General DMA registers +DMA_REGS = { + "INTR": 0x400 | UINT32, + "INTE0": 0x404 | UINT32, + "INTF0": 0x408 | UINT32, + "INTS0": 0x40C | UINT32, + "INTE1": 0x414 | UINT32, + "INTF1": 0x418 | UINT32, + "INTS1": 0x41C | UINT32, + "TIMER0": 0x420 | UINT32, + "TIMER1": 0x424 | UINT32, + "TIMER2": 0x428 | UINT32, + "TIMER3": 0x42C | UINT32, + "MULTI_CHAN_TRIGGER": 0x430 | UINT32, + "SNIFF_CTRL": 0x434 | UINT32, + "SNIFF_DATA": 0x438 | UINT32, + "FIFO_LEVELS": 0x440 | UINT32, + "CHAN_ABORT": 0x444 | UINT32, +} + +# GPIO status and control: RP2040 datasheet 2.19.6.1.10 +GPIO_STATUS_FIELDS = { + "IRQTOPROC": 26 << BF_POS | 1 << BF_LEN | BFUINT32, + "IRQFROMPAD": 24 << BF_POS | 1 << BF_LEN | BFUINT32, + "INTOPERI": 19 << BF_POS | 1 << BF_LEN | BFUINT32, + "INFROMPAD": 17 << BF_POS | 1 << BF_LEN | BFUINT32, + "OETOPAD": 13 << BF_POS | 1 << BF_LEN | BFUINT32, + "OEFROMPERI": 12 << BF_POS | 1 << BF_LEN | BFUINT32, + "OUTTOPAD": 9 << BF_POS | 1 << BF_LEN | BFUINT32, + "OUTFROMPERI": 8 << BF_POS | 1 << BF_LEN | BFUINT32, +} +GPIO_CTRL_FIELDS = { + "IRQOVER": 28 << BF_POS | 2 << BF_LEN | BFUINT32, + "INOVER": 16 << BF_POS | 2 << BF_LEN | BFUINT32, + "OEOVER": 12 << BF_POS | 2 << BF_LEN | BFUINT32, + "OUTOVER": 8 << BF_POS | 2 << BF_LEN | BFUINT32, + "FUNCSEL": 0 << BF_POS | 5 << BF_LEN | BFUINT32, +} +GPIO_REGS = { + "GPIO_STATUS_REG": 0x00 | UINT32, + "GPIO_STATUS": (0x00, GPIO_STATUS_FIELDS), + "GPIO_CTRL_REG": 0x04 | UINT32, + "GPIO_CTRL": (0x04, GPIO_CTRL_FIELDS), +} + +# PAD control: RP2040 datasheet 2.19.6.3 +PAD_FIELDS = { + "OD": 7 << BF_POS | 1 << BF_LEN | BFUINT32, + "IE": 6 << BF_POS | 1 << BF_LEN | BFUINT32, + "DRIVE": 4 << BF_POS | 2 << BF_LEN | BFUINT32, + "PUE": 3 << BF_POS | 1 << BF_LEN | BFUINT32, + "PDE": 2 << BF_POS | 1 << BF_LEN | BFUINT32, + "SCHMITT": 1 << BF_POS | 1 << BF_LEN | BFUINT32, + "SLEWFAST": 0 << BF_POS | 1 << BF_LEN | BFUINT32, +} +PAD_REGS = {"PAD_REG": 0x00 | UINT32, "PAD": (0x00, PAD_FIELDS)} + +# ADC: RP2040 datasheet 4.9.6 +ADC_CS_FIELDS = { + "RROBIN": 16 << BF_POS | 5 << BF_LEN | BFUINT32, + "AINSEL": 12 << BF_POS | 3 << BF_LEN | BFUINT32, + "ERR_STICKY": 10 << BF_POS | 1 << BF_LEN | BFUINT32, + "ERR": 9 << BF_POS | 1 << BF_LEN | BFUINT32, + "READY": 8 << BF_POS | 1 << BF_LEN | BFUINT32, + "START_MANY": 3 << BF_POS | 1 << BF_LEN | BFUINT32, + "START_ONCE": 2 << BF_POS | 1 << BF_LEN | BFUINT32, + "TS_EN": 1 << BF_POS | 1 << BF_LEN | BFUINT32, + "EN": 0 << BF_POS | 1 << BF_LEN | BFUINT32, +} +ADC_FCS_FIELDS = { + "THRESH": 24 << BF_POS | 4 << BF_LEN | BFUINT32, + "LEVEL": 16 << BF_POS | 4 << BF_LEN | BFUINT32, + "OVER": 11 << BF_POS | 1 << BF_LEN | BFUINT32, + "UNDER": 10 << BF_POS | 1 << BF_LEN | BFUINT32, + "FULL": 9 << BF_POS | 1 << BF_LEN | BFUINT32, + "EMPTY": 8 << BF_POS | 1 << BF_LEN | BFUINT32, + "DREQ_EN": 3 << BF_POS | 1 << BF_LEN | BFUINT32, + "ERR": 2 << BF_POS | 1 << BF_LEN | BFUINT32, + "SHIFT": 1 << BF_POS | 1 << BF_LEN | BFUINT32, + "EN": 0 << BF_POS | 1 << BF_LEN | BFUINT32, +} +ADC_REGS = { + "CS_REG": 0x00 | UINT32, + "CS": (0x00, ADC_CS_FIELDS), + "RESULT_REG": 0x04 | UINT32, + "FCS_REG": 0x08 | UINT32, + "FCS": (0x08, ADC_FCS_FIELDS), + "FIFO_REG": 0x0C | UINT32, + "DIV_REG": 0x10 | UINT32, + "INTR_REG": 0x14 | UINT32, + "INTE_REG": 0x18 | UINT32, + "INTF_REG": 0x1C | UINT32, + "INTS_REG": 0x20 | UINT32, +} +DREQ_PIO0_TX0, DREQ_PIO0_RX0, DREQ_PIO1_TX0 = 0, 4, 8 +DREQ_PIO1_RX0, DREQ_SPI0_TX, DREQ_SPI0_RX = 12, 16, 17 +DREQ_SPI1_TX, DREQ_SPI1_RX, DREQ_UART0_TX = 18, 19, 20 +DREQ_UART0_RX, DREQ_UART1_TX, DREQ_UART1_RX = 21, 22, 23 +DREQ_I2C0_TX, DREQ_I2C0_RX, DREQ_I2C1_TX = 32, 33, 34 +DREQ_I2C1_RX, DREQ_ADC = 35, 36 + +DMA_CHANS = [ + struct(DMA_BASE + n * DMA_CHAN_WIDTH, DMA_CHAN_REGS) + for n in range(0, DMA_CHAN_COUNT) +] +DMA_DEVICE = struct(DMA_BASE, DMA_REGS) +GPIO_PINS = [ + struct(GPIO_BASE + n * GPIO_CHAN_WIDTH, GPIO_REGS) for n in range(0, GPIO_PIN_COUNT) +] +PAD_PINS = [ + struct(PAD_BASE + n * PAD_PIN_WIDTH, PAD_REGS) for n in range(0, GPIO_PIN_COUNT) +] +ADC_DEVICE = struct(ADC_BASE, ADC_REGS) +ADC_FIFO_ADDR = ADC_BASE + 0x0C + +GPIO_FUNC_SPI, GPIO_FUNC_UART, GPIO_FUNC_I2C = 1, 2, 3 +GPIO_FUNC_PWM, GPIO_FUNC_SIO, GPIO_FUNC_PIO0 = 4, 5, 6 +GPIO_FUNC_NULL = 0x1F + +# EOF diff --git a/programs/adc_test.py b/programs/adc_test.py new file mode 100644 index 0000000000000000000000000000000000000000..b4f6348c192139bbc786820106644e5f7db283ca --- /dev/null +++ b/programs/adc_test.py @@ -0,0 +1,67 @@ +# based on https://github.com/jbentham/pico/blob/main/rp_adc_test.py +# which is Copyright (c) 2021 Jeremy P Bentham and licensed under the Apache License, Version 2.0 + +import array +import asyncio + +import uctypes + +import external.rp_devices as devs + + +class DmaAdc: + def __init__(self, pin: int, sample_count: int = 1000, sampling_rate: int = 100000): + self._pin_number = pin + self._channel_number = pin - 26 + self._adc = devs.ADC_DEVICE + self._pin = devs.GPIO_PINS[pin] + self._pad = devs.PAD_PINS[pin] + self._pin.GPIO_CTRL_REG = devs.GPIO_FUNC_NULL + self._pad.PAD_REG = 0 + self._buffer = None + self._n_samples = sample_count + self.set_sample_count(sample_count) + self._sampling_rate = sampling_rate + self._dma_channel = devs.DMA_CHANS[self._channel_number] + self._dma = devs.DMA_DEVICE + self._ready = False + self._lock = asyncio.Lock() + + def set_sample_count(self, count: int): + self._n_samples = count + self._buffer = array.array("H", (0 for _ in range(self._n_samples))) + + async def sample(self): + with self._lock: + self._ready = False + self._adc.CS_REG = self._adc.FCS_REG = 0 + self._adc.CS.EN = 1 + self._adc.CS.AINSEL = self._channel_number + self._adc.FCS.EN = self._adc.FCS.DREQ_EN = 1 + self._adc.DIV_REG = (48000000 // self._sampling_rate - 1) << 8 + self._adc.FCS.THRESH = self._adc.FCS.OVER = self._adc.FCS.UNDER = 1 + + self._dma_channel.READ_ADDR_REG = devs.ADC_FIFO_ADDR + self._dma_channel.WRITE_ADDR_REG = uctypes.addressof(self._buffer) + self._dma_channel.TRANS_COUNT_REG = self._n_samples + + self._dma_channel.CTRL_TRIG_REG = 0 + self._dma_channel.CTRL_TRIG.CHAIN_TO = self._channel_number + self._dma_channel.CTRL_TRIG.INCR_WRITE = ( + self._dma_channel.CTRL_TRIG.IRQ_QUIET + ) = 1 + self._dma_channel.CTRL_TRIG.TREQ_SEL = devs.DREQ_ADC + self._dma_channel.CTRL_TRIG.DATA_SIZE = 1 + self._dma_channel.CTRL_TRIG.EN = 1 + + while self._adc.FCS.LEVEL: + _ = self._adc.FIFO_REG + + self._adc.CS.START_MANY = 1 + while self._dma_channel.CTRL_TRIG.BUSY: + await asyncio.sleep(10 / 1000) + + self._adc.CS.START_MANY = 0 + self._dma_channel.CTRL_TRIG.EN = 0 + self._ready = True + return [("%1.3f" % (val * 3.3 / 4096)) for val in self._buffer] diff --git a/programs/ae33.py b/programs/ae33.py index 1477b522596451ae4016674696884abc6ac4c83b..936931148410ee1006075e8169673a8407e544f6 100644 --- a/programs/ae33.py +++ b/programs/ae33.py @@ -5,7 +5,7 @@ from umnp.microcontroller.devices.network.ethernet_w5500 import EthernetW5500 from umnp.microcontroller.devices.network.udp import UDPSender, UDPReceiver from umnp.microcontroller.measurementdevice import MeasurementDevice from umnp.microcontroller.tasks.periodictask import PeriodicTask -from umnp.protocol.common import UDP_DATA_PORT, UDP_CMD_PORT +from umnp.proto.common import UDP_DATA_PORT, UDP_CMD_PORT if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences diff --git a/programs/base_program.py b/programs/base_program.py index 47002bcc650d128620a7592a3f7e6709914f7913..96db56c841c1f4c4777c4fe1999791d0a9ae76a5 100644 --- a/programs/base_program.py +++ b/programs/base_program.py @@ -5,7 +5,7 @@ from umnp.microcontroller.devices.network.ethernet_w5500 import EthernetW5500 from umnp.microcontroller.devices.network.udp import UDPSender, UDPReceiver from umnp.microcontroller.measurementdevice import MeasurementDevice from umnp.microcontroller.tasks.periodictask import PeriodicTask -from umnp.protocol.common import UDP_DATA_PORT, UDP_CMD_PORT +from umnp.proto.common import UDP_DATA_PORT, UDP_CMD_PORT if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences diff --git a/programs/umnp-rhtp-local.py b/programs/umnp-rhtp-local.py index 742e8af276eda1dbff7daf777e7cc35195b15a39..b7bd1263ef0c0b28a49f08927c3c4c80862fdee9 100644 --- a/programs/umnp-rhtp-local.py +++ b/programs/umnp-rhtp-local.py @@ -6,7 +6,7 @@ from umnp.microcontroller.measurementdevice import MeasurementDevice from umnp.microcontroller.sensors.lps28dfw import LPS28DFW from umnp.microcontroller.sensors.sht45 import SHT45 from umnp.microcontroller.tasks.periodictask import PeriodicTask -from umnp.protocol.data_message import DataMessage +from umnp.proto.data_message import DataMessage if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences @@ -47,54 +47,39 @@ async def aggregate_and_send( p, p_t = await p_sensor.measure() data = "{:2.2f},{:2.2f},{:2.2f},{:2.2f}".format(t, rh, p, p_t) print("Sending: '{}'".format(data)) - msg = DataMessage(data, device.identifier_raw, device.device_type) + if comm.network_error: - print("Network error") - spi: machine.SPI = device.spi - if spi: - print("SPI::deinit()") - spi.deinit() - spi = machine.SPI(0, SPI_BAUD, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK) - print("SPI::new()") - device.add_spi(spi) - print("SPI::added()") - dev_mac = device.generated_mac_raw() - device.network.deactivate() - print("ETH:new()") - ether = EthernetW5500(spi, ETH_CS, ETH_RST, dev_mac, ETH_USE_DHCP) - print("ETH:set()") - ether.set_network(ETH_IP, ETH_SUBNET, ETH_GATEWAY, ETH_DNS) - print("ETH:added()") - device.add_network_adapter(ether) - comm.clear_network_error() + await device.reset_network() + if not comm.network_error: + msg = DataMessage(data, device.identifier_raw, device.device_type) await comm.send_message(msg) - msg = None + msg = None + gc.collect() async def main(): # configure network device = MeasurementDevice(device_type=DEVICE_TYPE_RHTP) - spi = machine.SPI(0, SPI_BAUD, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK) - device.add_spi(spi) - - i2c = machine.I2C(id=1, scl=I2C_SCL, sda=I2C_SDA, timeout=10000) - device.add_i2c(i2c) + spi = device.add_spi(0, SPI_BAUD, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK) + i2c = device.add_i2c(i2c_id=1, scl=I2C_SCL, sda=I2C_SDA, timeout=10000) dev_mac = device.generated_mac_raw() ether = EthernetW5500(spi, ETH_CS, ETH_RST, dev_mac, ETH_USE_DHCP) ether.set_network(ETH_IP, ETH_SUBNET, ETH_GATEWAY, ETH_DNS) - device.add_network_adapter(ether) - device.add_i2c(i2c) + comm = device.create_communicator() sht45 = SHT45(i2c) p_sensor = LPS28DFW(i2c, i2c_address=0x5C) - task = PeriodicTask(aggregate_and_send, None, 1000, device, sht45, p_sensor) - comm.add_task(task, "aggregate_and_send") + comm.add_task( + PeriodicTask(aggregate_and_send, None, 1000, device, sht45, p_sensor), + "aggregate_and_send", + ) + comm.add_task(PeriodicTask(device.send_life_sign, None, 5000), "life_sign") asyncio.run(comm.start()) diff --git a/programs/umnp-rhtp.py b/programs/umnp-rhtp.py index e09c853b7e94d7ecea4a14ad5c6e41b2f8822546..89bf20d75733bfc2ea8462bbc396897a628cfa12 100644 --- a/programs/umnp-rhtp.py +++ b/programs/umnp-rhtp.py @@ -6,7 +6,7 @@ from umnp.microcontroller.measurementdevice import MeasurementDevice from umnp.microcontroller.sensors.lps28dfw import LPS28DFW from umnp.microcontroller.sensors.sht45 import SHT45 from umnp.microcontroller.tasks.periodictask import PeriodicTask -from umnp.protocol.data_message import DataMessage +from umnp.proto.data_message import DataMessage if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences @@ -47,45 +47,27 @@ async def aggregate_and_send( p, p_t = await p_sensor.measure() data = "{:2.2f},{:2.2f},{:2.2f},{:2.2f}".format(t, rh, p, p_t) print("Sending: '{}'".format(data)) - msg = DataMessage(data, device.identifier_raw, device.device_type) + if comm.network_error: - print("Network error") - spi: machine.SPI = device.spi - if spi: - print("SPI::deinit()") - spi.deinit() - spi = machine.SPI(0, SPI_BAUD, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK) - print("SPI::new()") - device.add_spi(spi) - print("SPI::added()") - dev_mac = device.generated_mac_raw() - device.network.deactivate() - print("ETH:new()") - ether = EthernetW5500(spi, ETH_CS, ETH_RST, dev_mac, ETH_USE_DHCP) - print("ETH:set()") - ether.set_network(ETH_IP, ETH_SUBNET, ETH_GATEWAY, ETH_DNS) - print("ETH:added()") - device.add_network_adapter(ether) - comm.clear_network_error() + await device.reset_network() + if not comm.network_error: + msg = DataMessage(data, device.identifier_raw, device.device_type) await comm.send_message(msg) - msg = None + msg = None + gc.collect() async def main(): # configure network device = MeasurementDevice(device_type=DEVICE_TYPE_RHTP) - spi = machine.SPI(0, SPI_BAUD, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK) - device.add_spi(spi) - - i2c = machine.I2C(id=1, scl=I2C_SCL, sda=I2C_SDA, timeout=10000) - device.add_i2c(i2c) + spi = device.add_spi(0, SPI_BAUD, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK) + i2c = device.add_i2c(i2c_id=1, scl=I2C_SCL, sda=I2C_SDA, timeout=10000) dev_mac = device.generated_mac_raw() ether = EthernetW5500(spi, ETH_CS, ETH_RST, dev_mac, ETH_USE_DHCP) ether.set_network(ETH_IP, ETH_SUBNET, ETH_GATEWAY, ETH_DNS) - device.add_network_adapter(ether) device.add_i2c(i2c) comm = device.create_communicator() @@ -93,8 +75,11 @@ async def main(): sht45 = SHT45(i2c) p_sensor = LPS28DFW(i2c) - task = PeriodicTask(aggregate_and_send, None, 1000, device, sht45, p_sensor) - comm.add_task(task, "aggregate_and_send") + comm.add_task( + PeriodicTask(aggregate_and_send, None, 1000, device, sht45, p_sensor), + "aggregate_and_send", + ) + comm.add_task(PeriodicTask(device.send_life_sign, None, 5000), "life_sign") asyncio.run(comm.start()) diff --git a/syntheticdata/__init__.py b/syntheticdata/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3da0fcd322110bcefbe2a2630d9c543fc24d0d12 --- /dev/null +++ b/syntheticdata/__init__.py @@ -0,0 +1,70 @@ +import datetime +import random + + +class SyntheticDatum: + def __init__(self): + self.__fields = [] + + def get_datum(self, sep=", "): + return sep.join(self.__fields) + + def add_value(self, value): + self.__fields.append(str(value)) + + def add_values(self, values: list | tuple): + for field in values: + self.__fields.append(str(field)) + + def add_time(self, ts: datetime.datetime | None = None): + if ts is None: + ts = datetime.datetime.now(tz=datetime.UTC) + ts = round_to_second(ts) + self.__fields.append(str(ts.strftime("%H:%M:%S"))) + + def add_date(self, ts: datetime.datetime | None = None, fmt="%Y-%m-%d"): + if ts is None: + ts = datetime.datetime.now(tz=datetime.UTC) + ts = round_to_second(ts) + self.__fields.append(str(ts.strftime(fmt))) + + def add_integer( + self, + min_val: int = 0, + max_val: int = 999, + count=1, + ): + + for i in range(count): + value = random.randint(min_val, max_val) + self.__fields.append(str(value)) + + def add_float( + self, min_val: float = 0.0, max_val: float = 1.0, fmt: str = "0.2f", count=1 + ): + + for i in range(count): + value = random.uniform(min_val, max_val) + self.__fields.append(f"{value:{fmt}}") + + def add_room_temperature(self, fmt: str = "0.2f", count=1): + for i in range(count): + value = random.uniform(15, 20) + self.__fields.append(f"{value:{fmt}}") + + def add_pressure_pa(self, fmt: str = ".0f", count=1): + for i in range(count): + value = random.uniform(100000 * 0.95, 100000 * 1.05) + self.__fields.append(f"{value:{fmt}}") + + +def round_to_second(when: datetime.datetime | None = None) -> datetime.datetime: + + if when is None: + when = datetime.datetime.now(tz=datetime.timezone.utc) + if not isinstance(when, datetime.datetime): + raise ValueError(f"Timestamp {when} is not a datetime.datetime") + if when.microsecond >= 500 * 1000: + when = when + datetime.timedelta(seconds=1) + now = when.replace(microsecond=0) + return now diff --git a/umnp-daq.py b/umnp-daq.py index a8d20b5858329e35640897f9ce6a83d3bfba0f9d..341035277809b5c8c9130e51cc852098a771a8c3 100644 --- a/umnp-daq.py +++ b/umnp-daq.py @@ -3,8 +3,8 @@ import socket from umnp.daq.file_daq import FileDAQ from umnp.microcontroller.devices.network.udp import DEFAULT_UMNP_DATA_IN_PORT -from umnp.protocol import DataMessage -from umnp.protocol.message import Message +from umnp.proto import DataMessage, DeviceMessage +from umnp.proto.message import Message sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -21,6 +21,10 @@ def main(): now = datetime.datetime.now(tz=datetime.timezone.utc) if isinstance(msg, DataMessage): print(f"{now},{msg.sender_id},{msg.payload()}") + elif isinstance(msg, DeviceMessage): + print( + f"{now},{msg.sender_id},{msg.get_message_type_string},{msg.payload()}" + ) files.save_message(msg) diff --git a/umnp/daq/file_daq.py b/umnp/daq/file_daq.py index ffaaf0d75238f902e844cd89f02fede99b509be8..c768f70c4ba75e81e9626c00eee5b25731a79eb4 100644 --- a/umnp/daq/file_daq.py +++ b/umnp/daq/file_daq.py @@ -2,8 +2,13 @@ import datetime import os from umnp.devices import get_device_type_name -from umnp.protocol.headers import MESSAGE_HEADERS -from umnp.protocol.message import Message +from umnp.proto import DataMessage, DeviceMessage +from umnp.proto.headers import DEVICE_HEADERS +from umnp.proto.message import Message + + +def clean(field: str) -> str: + return field.replace(",", ";") class FileDAQ: @@ -27,9 +32,19 @@ class FileDAQ: self.__open_files[file_id] = open(filename, "w") f = self.__open_files[file_id] self.__open_fns[file_id] = filename - header = MESSAGE_HEADERS.get(msg.sender_type, {}).get(msg.type) + headers = ["receive-time", "sender-id"] + if isinstance(msg, DataMessage): + headers.extend(DEVICE_HEADERS.get(msg.sender_type, {}).get(msg.type)) + + elif isinstance(msg, DeviceMessage): + headers.extend(msg.header_fields) + + else: + headers = ["# unknown"] + headers = [header.replace(",", ";") for header in headers] + header = ",".join(headers) if header: - f.write("receive-time,sender-id," + ",".join(header) + "\n") + f.write(header + "\n") return f def save_message(self, msg: Message): @@ -61,5 +76,13 @@ class FileDAQ: f.flush() if f: - f.write(f"{when},{msg.sender_id},{msg.payload()}\n") + if isinstance(msg, DataMessage): + payload = clean(msg.payload()) + f.write(f"{when},{msg.sender_id},{payload}\n") + elif isinstance(msg, DeviceMessage): + payload = clean(msg.payload()) + msg_type = clean(msg.get_message_type_string) + f.write(f"{when},{msg.sender_id},{msg_type},{payload}\n") + else: + f.write(msg.payload + "\n") f.flush() diff --git a/umnp/microcontroller/communication/udp_communicator.py b/umnp/microcontroller/communication/udp_communicator.py index c9346cc07df6f6529885cb52d3429012b0604193..a713209cfe11185d5d107d6259f07f41e421bb5b 100644 --- a/umnp/microcontroller/communication/udp_communicator.py +++ b/umnp/microcontroller/communication/udp_communicator.py @@ -3,7 +3,7 @@ import time from umnp.microcontroller.devices.network.udp import UDPSender, UDPReceiver from umnp.microcontroller.tasks.periodictask import PeriodicTask -from umnp.protocol.message import Message +from umnp.proto.message import Message if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences diff --git a/umnp/microcontroller/devices/network/ethernet_w5500.py b/umnp/microcontroller/devices/network/ethernet_w5500.py index 01e6b8c9d0df3e1198f2cd22fd589f038df574b0..711ed48339c5f021dabaaf916632a49bef43464f 100644 --- a/umnp/microcontroller/devices/network/ethernet_w5500.py +++ b/umnp/microcontroller/devices/network/ethernet_w5500.py @@ -9,7 +9,7 @@ if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences import network - import umnp.protocol.compat.logging as logging + import umnp.proto.compat.logging as logging else: from umnp.microcontroller.umock import machine, network @@ -26,16 +26,43 @@ class EthernetW5500(EthernetAdapter): dhcp=False, ): super().__init__() + self._dhcp = dhcp self._spi = spi + self._mac = mac self._pin1 = pin_cs self._pin2 = pin_rst + self._nic = None + self._ip = None + self._subnet = None + self._gateway = None + self._dns = None + self._init(spi) + + # self._nic = network.WIZNET5K(spi, self._pin1, self._pin2) + # self._nic.active(True) + + # self._nic.config(mac=self._mac) + # if self._dhcp: + # self.enable_dhcp() + + def _init(self, spi: machine.SPI): self._nic = network.WIZNET5K(spi, self._pin1, self._pin2) self._nic.active(True) - self._nic.config(mac=mac) - if dhcp: + self._nic.config(mac=self._mac) + if self._dhcp: self.enable_dhcp() + def reinit(self, spi: machine.SPI): + self._init(spi) + self.set_network( + ip=self._ip, subnet_mask=self._subnet, gateway=self._gateway, dns=self._dns + ) + def set_network(self, ip: str, subnet_mask: str, gateway: str, dns: str): + self._ip = ip + self._subnet = subnet_mask + self._gateway = gateway + self._dns = dns self._nic.ifconfig((ip, subnet_mask, gateway, dns)) def enable_dhcp(self): diff --git a/umnp/microcontroller/devices/network/udp.py b/umnp/microcontroller/devices/network/udp.py index ef956206a3006be3c551b5162263b328a6c288a7..53955be1abb353ae88705da2c4216ba9b9f49148 100644 --- a/umnp/microcontroller/devices/network/udp.py +++ b/umnp/microcontroller/devices/network/udp.py @@ -10,7 +10,7 @@ from umnp.microcontroller.devices.network import ( if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences import uasyncio as asyncio - import umnp.protocol.compat.logging as logging + import umnp.proto.compat.logging as logging else: import logging diff --git a/umnp/microcontroller/measurementdevice.py b/umnp/microcontroller/measurementdevice.py index 9a1ab8f94c7e8cb00e77f3bcb5b93b79474f889a..72aba1739ac974904463b06a52952883443c7772 100644 --- a/umnp/microcontroller/measurementdevice.py +++ b/umnp/microcontroller/measurementdevice.py @@ -10,7 +10,9 @@ from umnp.microcontroller.devices.network.udp import ( DEFAULT_UMNP_DATA_IN_PORT, DEFAULT_UMNP_COMMAND_IN_PORT, ) -from umnp.protocol.constants import MSG_STRING_ENCODING +from umnp.proto import DeviceMessage +from umnp.proto.constants import MSG_STRING_ENCODING +from umnp.proto.device_message import MSG_TYPE_LIFE_SIGN, MSG_TYPE_INFO if sys.implementation.name == "micropython": # noinspection PyUnresolvedReferences @@ -39,6 +41,7 @@ class MeasurementDevice: self._type = device_type self._i2c = None self._spi = None + self._spi_params = None @property def device_type(self): @@ -48,15 +51,49 @@ class MeasurementDevice: def boot_time(self): return self._boot_time - def add_i2c(self, i2c: machine.I2C): - self._i2c = i2c - @property def spi(self): return self._spi - def add_spi(self, spi: machine.SPI): - self._spi = spi + def spi_reinit(self) -> machine.SPI: + if len(self._spi_params) == 0: + return + + if self._spi: + print("SPI::reinit()") + self._spi.deinit() + self._spi = machine.SPI( + self._spi_params["id"], + self._spi_params["baud"], + mosi=self._spi_params["mosi"], + miso=self._spi_params["miso"], + sck=self._spi_params["sck"], + ) + return self._spi + + def add_spi( + self, + spi_id: int, + baudrate: int, + mosi: machine.Pin, + miso: machine.Pin, + sck: machine.Pin, + ) -> machine.SPI: + + self._spi_params = { + "id": spi_id, + "baud": baudrate, + "mosi": mosi, + "miso": miso, + "sck": sck, + } + + self._spi = self.spi_reinit() + return self._spi + + def add_i2c(self, i2c_id: int, scl: machine.Pin, sda: machine.Pin, timeout: int): + self._i2c = machine.I2C(id=i2c_id, scl=scl, sda=sda, timeout=timeout) + return self._i2c @property def i2c(self): @@ -65,9 +102,23 @@ class MeasurementDevice: def add_network_adapter(self, adapter): self._network = adapter - def reset_network_adapter(self): - if self._network: - self._network.reset() + async def reset_network(self): + print("Network error") + if self.spi: + self.spi_reinit() + # dev_mac = device.generated_mac_raw() + self.network.deactivate() + self.network.reinit(self.spi) + self.communicator.clear_network_error() + + info_msg = DeviceMessage( + "restarted network", + MSG_TYPE_INFO, + self.identifier_raw, + self.device_type, + ) + await self.communicator.send_message(info_msg) + info_msg = None @property def network(self): @@ -118,3 +169,21 @@ class MeasurementDevice: @property def communicator(self) -> UDPCommunicator | None: return self._communicator + + async def send_life_sign(self): + if not self.communicator: + return + if self.communicator.network_error: + return + + now = time.time() + seconds_since_boot = now - self.boot_time + + msg = DeviceMessage( + f"{seconds_since_boot}", + MSG_TYPE_LIFE_SIGN, + self.identifier_raw, + self.device_type, + ) + + await self.communicator.send_message(msg) diff --git a/umnp/microcontroller/sensors/lps28dfw/__init__.py b/umnp/microcontroller/sensors/lps28dfw/__init__.py index 11e55adf1fa97a16bbe3413cdb6f0f0921e6093a..4e10bdc058008cdcb06b27bbac71c835b878afc0 100644 --- a/umnp/microcontroller/sensors/lps28dfw/__init__.py +++ b/umnp/microcontroller/sensors/lps28dfw/__init__.py @@ -9,7 +9,7 @@ except ImportError: from umnp.microcontroller.umock.machine import I2C if sys.implementation.name == "micropython": - import umnp.protocol.compat.logging as logging + import umnp.proto.compat.logging as logging else: def const(x): diff --git a/umnp/microcontroller/sensors/sht45/__init__.py b/umnp/microcontroller/sensors/sht45/__init__.py index 40da97fbe67a4927cf6ae38aba770d79a49b7102..845b519570f8f0e5a921c24fd983495105526ebd 100644 --- a/umnp/microcontroller/sensors/sht45/__init__.py +++ b/umnp/microcontroller/sensors/sht45/__init__.py @@ -7,7 +7,7 @@ except ImportError: if sys.implementation.name == "micropython": - import umnp.protocol.compat.logging as logging + import umnp.proto.compat.logging as logging else: def const(x): diff --git a/umnp/microcontroller/umock/machine/__init__.py b/umnp/microcontroller/umock/machine/__init__.py index 178916d411c8f464f1aa0de2c247413c83ec2cea..7203546222d120ad1eb374d9cbb5e6a793f37ef6 100644 --- a/umnp/microcontroller/umock/machine/__init__.py +++ b/umnp/microcontroller/umock/machine/__init__.py @@ -1,7 +1,7 @@ import datetime import uuid -from umnp.protocol.message_header import MSG_BYTE_ORDER +from umnp.proto.message_header import MSG_BYTE_ORDER def unique_id() -> bytes: diff --git a/umnp/proto/__init__.py b/umnp/proto/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bd3c4af2ccc6f22f38ae7f39f4987dde74534473 --- /dev/null +++ b/umnp/proto/__init__.py @@ -0,0 +1,7 @@ +from umnp.proto.data_message import DataMessage +from umnp.proto.device_message import DeviceMessage +from umnp.proto.messagetype import MessageType +from umnp.proto.register_messages import register_messages + +register_messages(MessageType.MSG_DEVICE_DATA, DataMessage, "data") +register_messages(MessageType.MSG_DEVICE_INFO, DeviceMessage, "info") diff --git a/umnp/protocol/common/__init__.py b/umnp/proto/common/__init__.py similarity index 100% rename from umnp/protocol/common/__init__.py rename to umnp/proto/common/__init__.py diff --git a/umnp/protocol/common/timestamp.py b/umnp/proto/common/timestamp.py similarity index 96% rename from umnp/protocol/common/timestamp.py rename to umnp/proto/common/timestamp.py index 0240240112bedf0cb0ee294a206d0e59bf3c361f..aff9f031775c5f915267de0f007732a35a6c624e 100644 --- a/umnp/protocol/common/timestamp.py +++ b/umnp/proto/common/timestamp.py @@ -1,6 +1,6 @@ import sys -from umnp.protocol.umnp_time import seconds_since_epoch +from umnp.proto.umnp_time import seconds_since_epoch if sys.implementation.name == "micropython": pass diff --git a/programs/test.py b/umnp/proto/compat/__init__.py similarity index 100% rename from programs/test.py rename to umnp/proto/compat/__init__.py diff --git a/umnp/protocol/compat/logging.py b/umnp/proto/compat/logging.py similarity index 100% rename from umnp/protocol/compat/logging.py rename to umnp/proto/compat/logging.py diff --git a/umnp/protocol/constants.py b/umnp/proto/constants.py similarity index 100% rename from umnp/protocol/constants.py rename to umnp/proto/constants.py diff --git a/umnp/protocol/data_message.py b/umnp/proto/data_message.py similarity index 79% rename from umnp/protocol/data_message.py rename to umnp/proto/data_message.py index b59994a116af0c9acba8a09d5fd706d55b03eb89..8640733a26414b1707f969bba0a92fc02370aa52 100644 --- a/umnp/protocol/data_message.py +++ b/umnp/proto/data_message.py @@ -1,7 +1,7 @@ -from umnp.protocol.common.timestamp import TimeStamp -from umnp.protocol.constants import MSG_STRING_ENCODING -from umnp.protocol.message import Message, MessageHeader -from umnp.protocol.messagetype import MessageType +from umnp.proto.common.timestamp import TimeStamp +from umnp.proto.constants import MSG_STRING_ENCODING +from umnp.proto.message import Message, MessageHeader +from umnp.proto.messagetype import MessageType class DataMessage(Message): diff --git a/umnp/protocol/device.py b/umnp/proto/device.py similarity index 100% rename from umnp/protocol/device.py rename to umnp/proto/device.py diff --git a/umnp/proto/device_message.py b/umnp/proto/device_message.py new file mode 100644 index 0000000000000000000000000000000000000000..5e6128580859b93e69958d8d7f4aa6906a1d2014 --- /dev/null +++ b/umnp/proto/device_message.py @@ -0,0 +1,68 @@ +from umnp.proto.common.timestamp import TimeStamp +from umnp.proto.constants import MSG_STRING_ENCODING +from umnp.proto.message import Message, MessageHeader, MSG_BYTE_ORDER +from umnp.proto.messagetype import MessageType + +MSG_TYPE_UNKNOWN = 0 +MSG_TYPE_ERROR = 1 +MSG_TYPE_INFO = 2 +MSG_TYPE_LIFE_SIGN = 3 + + +_MSG_TYPE_DICT = { + MSG_TYPE_ERROR: "error", + MSG_TYPE_INFO: "info", + MSG_TYPE_LIFE_SIGN: "seconds since boot", +} + + +class DeviceMessage(Message): + def __init__( + self, + data: str, + msg_type: int, + sender_id: bytes, + sender_type: int, + send_time: TimeStamp = None, + ): + self._msg_type = msg_type + self._payload = data + _msg_type = msg_type.to_bytes(1, MSG_BYTE_ORDER) + self._encoded_data = _msg_type + data.encode(MSG_STRING_ENCODING) + super().__init__( + MessageType.MSG_DEVICE_INFO, + self._encoded_data, + sender_id, + sender_type, + send_time, + ) + + @staticmethod + def _decode_payload(transferred_data): + return transferred_data.decode(MSG_STRING_ENCODING) + + @property + def get_message_type_string(self): + return _MSG_TYPE_DICT.get(self._msg_type, "unknown") + + @property + def message_type(self): + return self._msg_type + + def payload(self) -> str: + return self._payload + + @classmethod + def decode(cls, payload: bytes, header: MessageHeader) -> "DeviceMessage": + decoded_payload = cls._decode_payload(payload[1:]) + return cls( + decoded_payload, + payload[0], + header.sender_id, + header.sender_type, + header.timestamp, + ) + + @property + def header_fields(self): + return ["message-type", "message"] diff --git a/umnp/protocol/device_types.py b/umnp/proto/device_types.py similarity index 100% rename from umnp/protocol/device_types.py rename to umnp/proto/device_types.py diff --git a/umnp/protocol/headers.py b/umnp/proto/headers.py similarity index 63% rename from umnp/protocol/headers.py rename to umnp/proto/headers.py index d868e09b4aa50d589defdecf6e8506f20e2d2f5f..3441dd1a10d917e952b0001f7c60897dea660261 100644 --- a/umnp/protocol/headers.py +++ b/umnp/proto/headers.py @@ -1,6 +1,6 @@ from umnp.devices import DEVICE_TYPE_RHTP -from umnp.protocol.messagetype import MessageType +from umnp.proto.messagetype import MessageType -MESSAGE_HEADERS = { +DEVICE_HEADERS = { DEVICE_TYPE_RHTP: {MessageType.MSG_DEVICE_DATA: ["T", "rH", "p", "T(p)"]} } diff --git a/umnp/protocol/message.py b/umnp/proto/message.py similarity index 93% rename from umnp/protocol/message.py rename to umnp/proto/message.py index f18431f9982b2b8f4135f42b6e2d67df98a1f225..afbc8da7a08cd9d7eaa4f5a9e03107aa48031743 100644 --- a/umnp/protocol/message.py +++ b/umnp/proto/message.py @@ -7,12 +7,12 @@ except ImportError: try: import logging except ImportError: - import umnp.protocol.compat.logging as logging + from umnp.proto.compat import logging -from umnp.protocol.common.timestamp import TimeStamp -from umnp.protocol.constants import MSG_BYTE_ORDER, MSG_LEN_PAYLOAD_SIZE -from umnp.protocol.message_header import MessageHeader +from umnp.proto.common.timestamp import TimeStamp +from umnp.proto.constants import MSG_BYTE_ORDER, MSG_LEN_PAYLOAD_SIZE +from umnp.proto.message_header import MessageHeader class Message: diff --git a/umnp/protocol/message_header.py b/umnp/proto/message_header.py similarity index 96% rename from umnp/protocol/message_header.py rename to umnp/proto/message_header.py index e13a2f6b81879d1a2a96396924c9b2f26d2dab5b..bdda79c46fc3b6b6c956c691d08f9dc31e5b43e9 100644 --- a/umnp/protocol/message_header.py +++ b/umnp/proto/message_header.py @@ -1,5 +1,5 @@ -from umnp.protocol.common.timestamp import TimeStamp, valid_timestamp -from umnp.protocol.constants import ( +from umnp.proto.common.timestamp import TimeStamp, valid_timestamp +from umnp.proto.constants import ( MSG_PROTOCOL_VERSION, MSG_LEN_PROTOCOL_VERSION, MSG_BYTE_ORDER, @@ -12,7 +12,7 @@ from umnp.protocol.constants import ( try: import logging except ImportError: - import umnp.protocol.compat.logging as logging + from umnp.proto.compat import logging try: # noinspection PyUnresolvedReferences diff --git a/umnp/protocol/messagetype.py b/umnp/proto/messagetype.py similarity index 72% rename from umnp/protocol/messagetype.py rename to umnp/proto/messagetype.py index b180fd99ead62f6528c8ff060b28eeb787c39ed3..077f10283f09b5aa9e9f6e3063c8851f4996f153 100644 --- a/umnp/protocol/messagetype.py +++ b/umnp/proto/messagetype.py @@ -3,11 +3,11 @@ class MessageType: MSG_DEVICE_DATA = 1 - MSG_TYPE_INFO = 16 + MSG_DEVICE_INFO = 16 MSG_TYPE_ERROR = 32 MSG_TYPE_UNKNOWN = 65535 - _allowed_message_types = [MSG_DEVICE_DATA, MSG_TYPE_UNKNOWN] + _allowed_message_types = [MSG_DEVICE_DATA, MSG_TYPE_UNKNOWN, MSG_DEVICE_INFO] @staticmethod def valid_message_type(msg_type: int): diff --git a/umnp/protocol/register_messages.py b/umnp/proto/register_messages.py similarity index 85% rename from umnp/protocol/register_messages.py rename to umnp/proto/register_messages.py index 3e8c8dce7b43ac741d37206012ed651f125ea1a6..b29898bac2149b7d39477f4239fcbcdde1b7ccd9 100644 --- a/umnp/protocol/register_messages.py +++ b/umnp/proto/register_messages.py @@ -3,7 +3,7 @@ try: import typing except ImportError: pass -from umnp.protocol.message import Message +from umnp.proto.message import Message MESSAGE_NAMES = {} diff --git a/umnp/protocol/umnp_time.py b/umnp/proto/umnp_time.py similarity index 100% rename from umnp/protocol/umnp_time.py rename to umnp/proto/umnp_time.py diff --git a/umnp/protocol/__init__.py b/umnp/protocol/__init__.py deleted file mode 100644 index a7f0d18c8257f43157f4dbb7517ee04769b7c9fe..0000000000000000000000000000000000000000 --- a/umnp/protocol/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from umnp.protocol.data_message import DataMessage -from umnp.protocol.error_message import ErrorMessage -from umnp.protocol.info_message import InfoMessage -from umnp.protocol.messagetype import MessageType -from umnp.protocol.register_messages import register_messages - -register_messages(MessageType.MSG_DEVICE_DATA, DataMessage, "data") -register_messages(MessageType.MSG_TYPE_INFO, InfoMessage, "info") -register_messages(MessageType.MSG_TYPE_ERROR, ErrorMessage, "error") diff --git a/umnp/protocol/error_message.py b/umnp/protocol/error_message.py deleted file mode 100644 index 314332f45e76a8d7e67af3d50a5984c321cdd8d6..0000000000000000000000000000000000000000 --- a/umnp/protocol/error_message.py +++ /dev/null @@ -1,33 +0,0 @@ -from umnp.protocol.common.timestamp import TimeStamp -from umnp.protocol.constants import MSG_STRING_ENCODING -from umnp.protocol.message import Message, MessageHeader -from umnp.protocol.messagetype import MessageType - - -class ErrorMessage(Message): - def __init__( - self, data: str, sender_id: bytes, sender_type: int, send_time: TimeStamp = None - ): - self._payload = data - self._encoded_data = data.encode(MSG_STRING_ENCODING) - super().__init__( - MessageType.MSG_DEVICE_ERROR, - self._encoded_data, - sender_id, - sender_type, - send_time, - ) - - @staticmethod - def _decode_payload(transferred_data): - return transferred_data.decode(MSG_STRING_ENCODING) - - def payload(self) -> str: - return self._payload - - @classmethod - def decode(cls, payload: bytes, header: MessageHeader) -> "ErrorMessage": - decoded_payload = cls._decode_payload(payload) - return cls( - decoded_payload, header.sender_id, header.sender_type, header.timestamp - ) diff --git a/umnp/protocol/info_message.py b/umnp/protocol/info_message.py deleted file mode 100644 index b8a45b2ef4f1c4bbd87c05b080f15eca58d9fdde..0000000000000000000000000000000000000000 --- a/umnp/protocol/info_message.py +++ /dev/null @@ -1,33 +0,0 @@ -from umnp.protocol.common.timestamp import TimeStamp -from umnp.protocol.constants import MSG_STRING_ENCODING -from umnp.protocol.message import Message, MessageHeader -from umnp.protocol.messagetype import MessageType - - -class InfoMessage(Message): - def __init__( - self, data: str, sender_id: bytes, sender_type: int, send_time: TimeStamp = None - ): - self._payload = data - self._encoded_data = data.encode(MSG_STRING_ENCODING) - super().__init__( - MessageType.MSG_DEVICE_INFO, - self._encoded_data, - sender_id, - sender_type, - send_time, - ) - - @staticmethod - def _decode_payload(transferred_data): - return transferred_data.decode(MSG_STRING_ENCODING) - - def payload(self) -> str: - return self._payload - - @classmethod - def decode(cls, payload: bytes, header: MessageHeader) -> "InfoMessage": - decoded_payload = cls._decode_payload(payload) - return cls( - decoded_payload, header.sender_id, header.sender_type, header.timestamp - )