diff --git a/.github/workflows/python_syntax.yaml b/.github/workflows/python_syntax.yaml new file mode 100644 index 00000000..aa5775f4 --- /dev/null +++ b/.github/workflows/python_syntax.yaml @@ -0,0 +1,44 @@ +name: Pylint Check + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + pylint_check: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.11' + + - name: Install dependencies + run: pip install pylint + + - name: Run pylint + run: | + py_files=$(find tools -name "*.py") + total_errors=0 + + for file in $py_files; do + errors=$(pylint --max-line-length=120 $file | wc -l) + if [[ $errors -gt 1 ]]; then + total_errors=$((total_errors + errors - 1)) + fi + done + + if [[ $total_errors -gt 0 ]]; then + echo "Too many errors ($total_errors), failing the build." + exit 1 + else + echo "Acceptable number of errors ($total_errors)." + fi diff --git a/.github/workflows/python_unittest.yaml b/.github/workflows/python_unittest.yaml new file mode 100644 index 00000000..3fe24dfd --- /dev/null +++ b/.github/workflows/python_unittest.yaml @@ -0,0 +1,43 @@ +name: Python Unit Test + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r tools/sensors_data_display_api/requirements.txt + python3 -m pip install coverage + + - name: Run unit tests + run: | + cd tools/sensors_data_display_api/tests/ + coverage run -m unittest discover -s . -v + - name: Check Code Coverage + run: | + cd tools/sensors_data_display_api/tests/ + coverage_report=$(coverage report -m) + total_coverage=$(echo "$coverage_report" | grep "TOTAL" | awk '{print $NF}' | tr -d '%') # Usuwanie procentu + echo "Całkowita procentowa pokrywalność kodu: $total_coverage%" + if [ $total_coverage -lt 75 ]; then + echo "Zbyt małe pokrycie kodu" + exit 1 + fi + shell: bash diff --git a/.gitignore b/.gitignore index e3e6daaf..a4b9948e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ bazel-* .vscode +.pyc +__pycache__ +.coverage MODULE.bazel.lock diff --git a/tools/pylint/pylint.sh b/tools/pylint/pylint.sh new file mode 100755 index 00000000..6606becf --- /dev/null +++ b/tools/pylint/pylint.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +py_files=$(find tools -name "*.py") +total_errors=0 + +for file in $py_files; do + errors=$(pylint --max-line-length=120 $file | wc -l) + if [[ $errors -gt 1 ]]; then + total_errors=$((total_errors + errors - 1)) + fi +done + +if [[ $total_errors -gt 0 ]]; then + echo "Too many errors ($total_errors), failing the build." + exit 1 +else + echo "Acceptable number of errors ($total_errors)." +fi diff --git a/tools/sensors_data_display_api/app.py b/tools/sensors_data_display_api/app.py new file mode 100644 index 00000000..af3f1b33 --- /dev/null +++ b/tools/sensors_data_display_api/app.py @@ -0,0 +1,230 @@ +import csv +import datetime +import threading +import time +import tkinter as tk +from tkinter import messagebox +import logging + +from data import Data +from data_reader import DataReader +from data_sender import DataSender + + +class App(tk.Tk): + def __init__(self): + super().__init__() + + # set properties of the window + self.title("Engine") + self.window_width = 600 + self.window_height = 600 + self.screen_width = self.winfo_screenwidth() + self.screen_height = self.winfo_screenheight() + self.padding = 5 + + center_x = int(self.screen_width / 2 - self.window_width / 2) + center_y = int(self.screen_height / 2 - self.window_height / 2) + + self.geometry(f'{self.window_width}x{self.window_height}+{center_x}+{center_y}') + # self.configure(background='#B9B4C7') + + # variables + label_width = 20 + button_padding = 2 + self.stop_reading = False + self.saving = False + self.data_reader_thread = None + self.saving_thread = None + self.data_to_save = Data() + self.collection_time = 10 + + # measurements + temperature_up_frame = tk.Frame(self) + temperature_up_label = tk.Label(temperature_up_frame, text='Temperature up:', width=label_width) + self.temperature_up = tk.Label(temperature_up_frame, text='0', width=label_width) + self.temperature_up.config(state=tk.DISABLED) + + temperature_down_frame = tk.Frame(self) + temperature_down_label = tk.Label(temperature_down_frame, text='Temperature down:', width=label_width) + self.temperature_down = tk.Label(temperature_down_frame, text='0', width=label_width) + self.temperature_down.config(state=tk.DISABLED) + + temperature_middle_frame = tk.Frame(self) + temperature_middle_label = tk.Label(temperature_middle_frame, text='Temperature middle:', width=label_width) + self.temperature_middle = tk.Label(temperature_middle_frame, width=label_width, text='0') + self.temperature_middle.config(state=tk.DISABLED) + + tank_pressure_frame = tk.Frame(self) + tank_pressure_label = tk.Label(tank_pressure_frame, text='Tank pressure', width=label_width) + self.tank_pressure = tk.Label(tank_pressure_frame, width=label_width, text='0') + self.tank_pressure.config(state=tk.DISABLED) + + jet_pressure_frame = tk.Frame(self) + jet_pressure_label = tk.Label(jet_pressure_frame, text='Jet pressure', width=label_width) + self.jet_pressure = tk.Label(jet_pressure_frame, width=label_width, text='0') + self.jet_pressure.config(state=tk.DISABLED) + + pressure_difference_frame = tk.Frame(self) + pressure_difference_label = tk.Label(pressure_difference_frame, text='Pressure difference:', width=label_width) + self.pressure_difference = tk.Label(pressure_difference_frame, width=label_width, text='0') + self.pressure_difference.config(state=tk.DISABLED) + + main_valve_frame = tk.Frame(self) + main_valve_label = tk.Label(main_valve_frame, text='Main valve:', width=label_width) + self.main_valve = tk.Label(main_valve_frame, width=label_width, text='not given') + self.main_valve.config(state=tk.DISABLED) + + vent_frame = tk.Frame(self) + vent_label = tk.Label(vent_frame, text='Vent:', width=label_width) + self.vent = tk.Label(vent_frame, width=label_width, text='not given') + self.vent.config(state=tk.DISABLED) + + # buttons + start_stop_saving_button_frame = tk.Frame(self) + self.start_saving_button = tk.Button(start_stop_saving_button_frame, text="Start saving data", command=lambda: self.start_save_to_file()) + self.stop_saving_button = tk.Button(start_stop_saving_button_frame, text="Stop saving data", command=lambda: self.stop_save_to_file()) + + main_valve_button_frame = tk.Frame(self) + main_valve_set_1_button = tk.Button(main_valve_button_frame, text="Main valve: set 1", command=lambda: self.set_main_valve(value=1)) + main_valve_set_0_button = tk.Button(main_valve_button_frame, text="Main valve: set 0", command=lambda: self.set_main_valve(value=0)) + + vent_button_frame = tk.Frame(self) + vent_set_1_button = tk.Button(vent_button_frame, text="Vent: set 1", command=lambda: self.set_vent(self, value=1)) + vent_set_0_button = tk.Button(vent_button_frame, text="Vent: set 0", command=lambda: self.set_vent(self, value=0)) + + launch_rocket_button_frame = tk.Frame(self) + launch_rocket_button = tk.Button(launch_rocket_button_frame, text="Launch rocket", command=lambda: self.launch_rocket(value=1)) + stop_launch_rocket_button = tk.Button(launch_rocket_button_frame, text="Stop launch rocket", command=lambda: self.launch_rocket(value=0)) + + exit_button = tk.Button(self, text="Exit", command=lambda: self.exit()) + + # pack on screen + # pack measurements + temperature_up_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + temperature_up_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.temperature_up.pack(side=tk.LEFT, pady=self.padding, fill='both') + + temperature_middle_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + temperature_middle_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.temperature_middle.pack(side=tk.LEFT, pady=self.padding, fill='both') + + temperature_down_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + temperature_down_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.temperature_down.pack(side=tk.LEFT, pady=self.padding, fill='both') + + tank_pressure_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + tank_pressure_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.tank_pressure.pack(side=tk.LEFT, pady=self.padding, fill='both') + + jet_pressure_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + jet_pressure_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.jet_pressure.pack(side=tk.LEFT, pady=self.padding, fill='both') + + pressure_difference_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + pressure_difference_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.pressure_difference.pack(side=tk.LEFT, pady=self.padding, fill='both') + + main_valve_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + main_valve_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.main_valve.pack(side=tk.LEFT, pady=self.padding, fill='both') + + vent_frame.pack(side=tk.TOP, pady=self.padding, fill='both') + vent_label.pack(side=tk.LEFT, pady=self.padding, fill='both') + self.vent.pack(side=tk.LEFT, pady=self.padding, fill='both') + + # pack buttons + main_valve_button_frame.pack(side=tk.TOP, pady=button_padding, fill='both') + main_valve_set_1_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + main_valve_set_0_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + + vent_button_frame.pack(side=tk.TOP, pady=button_padding, fill='both') + vent_set_1_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + vent_set_0_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + + start_stop_saving_button_frame.pack(side=tk.TOP, pady=button_padding, fill='both') + self.start_saving_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + self.stop_saving_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + self.stop_saving_button.config(state=tk.DISABLED) + + launch_rocket_button_frame.pack(side=tk.TOP, pady=button_padding, fill='both') + launch_rocket_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + stop_launch_rocket_button.pack(side=tk.LEFT, pady=button_padding, fill='both', expand=True) + + exit_button.pack(side=tk.TOP, fill='both') + + self.data_reader = DataReader(gui=self) + self.read_data() + + # initiate variable sender + self.data_sender = DataSender(self.data_reader.ip, self.data_reader.port) + + def read_data(self): + self.data_reader_thread = threading.Thread(target=self.data_reader.read_data, daemon=True) + self.data_reader_thread.start() + + def start_save_to_file(self): + self.saving = True + self.start_saving_button.config(state=tk.DISABLED) + self.stop_saving_button.config(state=tk.NORMAL) + self.saving_thread = threading.Thread(target=self._save_to_file, daemon=True) + self.saving_thread.start() + + def stop_save_to_file(self): + self.saving = False + self.start_saving_button.config(state=tk.NORMAL) + self.stop_saving_button.config(state=tk.DISABLED) + self.saving_thread.join() + + def _save_to_file(self): + timestamp = datetime.datetime.now() + filename = f"data_{timestamp.hour}_{timestamp.minute}_{timestamp.second}.csv" + with open(file=filename, mode='w', encoding='UTF-8') as csvFile: + writer = csv.writer(csvFile, delimiter=",") + writer.writerow(['TIMESTAMP', 'TEMPERATURE_UP', 'TEMPERATURE_DOWN', 'TEMPERATURE_MIDDLE', 'TANK_PRESSURE', 'JET_PRESSURE', 'PRESSURE_DIFFERENCE', 'MAIN_VALVE', 'VENT']) + start = time.time() + while self.saving: + logging.info("SAVING....") + collection_time_difference = time.time() - start + logging.info(f"Collection time difference: {collection_time_difference}") + if (self.data_to_save.is_none() is False) or collection_time_difference > self.collection_time: + logging.info("SAVED") + timestamp = datetime.datetime.now() + start = time.time() + with open(filename, 'a', encoding='UTF-8', newline='') as csvFile: + writer = csv.writer(csvFile, delimiter=",") + writer.writerow([timestamp, self.data_to_save.temperature_up, self.data_to_save.temperature_down, self.data_to_save.temperature_middle, + self.data_to_save.tank_pressure, self.data_to_save.jet_pressure, self.data_to_save.pressure_difference, + self.data_to_save.main_valve, self.data_to_save.vent]) + self.data_to_save.temperature_up = None + self.data_to_save.temperature_down = None + self.data_to_save.temperature_middle = None + self.data_to_save.tank_pressure = None + self.data_to_save.jet_pressure = None + self.data_to_save.pressure_difference = None + self.data_to_save.main_valve = None + self.data_to_save.vent = None + else: + logging.info("NOT SAVED") + + def launch_rocket(self, value): + req_method="PC_APP/EngineStart" + if value == 1: + result = messagebox.askyesno('Launch rocket', 'Are you sure you want to launch rocket?') + if result: + self.data_sender.send_data(value=value, method_id=self.get_method_id(req_method), service_id=self.get_service_id(req_method)) + else: + self.data_sender.send_data(value=value, method_id=self.get_method_id(req_method), service_id=self.get_service_id(req_method)) + + def set_main_valve(self, value): + req_method="PC_APP/setServoValue" + self.data_sender.send_data(value=value, method_id=self.get_method_id(req_method), service_id=self.get_service_id(req_method)) + + def set_vent(self, value): + req_method="PC_APP/setVentValue" + self.data_sender.send_data(value=value, method_id=self.get_method_id(req_method), service_id=self.get_service_id(req_method)) + + def exit(self): + self.stop_reading = True + self.saving = False + self.destroy() diff --git a/tools/sensors_data_display_api/data.py b/tools/sensors_data_display_api/data.py new file mode 100644 index 00000000..ee726d04 --- /dev/null +++ b/tools/sensors_data_display_api/data.py @@ -0,0 +1,16 @@ +class Data: + def __init__(self): + self.temperature_up: float = None + self.temperature_middle: float = None + self.temperature_down: float = None + self.tank_pressure: float = None + self.pressure_difference: float = None + self.main_valve: int = None + # not given as for now + self.jet_pressure: float = None + self.vent: int = None + + def is_none(self): + if self.temperature_up is None or self.temperature_middle is None or self.temperature_down is None or self.tank_pressure is None or self.main_valve is None or self.pressure_difference is None: + return True + return False diff --git a/tools/sensors_data_display_api/data_reader.py b/tools/sensors_data_display_api/data_reader.py new file mode 100644 index 00000000..8c026013 --- /dev/null +++ b/tools/sensors_data_display_api/data_reader.py @@ -0,0 +1,96 @@ +import json +import logging +import struct +import time +import socket + +from some_ip_header import SomeIPHeader + + +class DataReader: + def __init__(self, gui, filename="someip.json"): + self.gui = gui + self.data = 0 + with open(filename, encoding='UTF-8') as f: + self.config = json.load(f) + self.lookup_table = self._prepare_lookup_table() + self.ip = self.config["interface"][0].get('ip') + self.port = self.config["interface"][0].get("port") + + def _prepare_lookup_table(self): + lookup_table = {} + for key, value in self.config['req_events'].items(): + service_id = value.get('service_id') + method_id = value.get('event_id') + lookup_table[(service_id, method_id)] = key + return lookup_table + + def get_service_id(self, request_name): + req_methods = self.config.get('req_methods', {}) + if request_name in req_methods: + return req_methods[request_name]['service_id'] + return None, None + + def get_method_id(self, request_name): + req_methods = self.config.get('req_methods', {}) + if request_name in req_methods: + return req_methods[request_name]['method_id'] + return None, None + + def read_data(self): + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: + try: + sock.bind((self.ip, self.port)) + except: + logging.critical("Port is taken") + while True: + if self.gui.stop_reading: + break + data = sock.recv(150) + if len(data) == 0: + break + some_ip_header = SomeIPHeader() + some_ip_header.read(data) + + # get service_id, method_id and payload + service_id = some_ip_header.service_id + method_id = some_ip_header.methode_id + payload = some_ip_header.raw_payload + + # get data type + data_type = self.lookup_table.get((service_id, method_id)) + print(f'service_id: {service_id}, method_id: {method_id}, payload: {payload}, data_type: {data_type}') + if data_type is not None: + if data_type == 'PC_APP/newTempEvent_1': + # temperature up + temperature_up = float(struct.unpack(' str: + return f""" + service_id:{self.service_id} + method_id:{self.methode_id} + lenght:{self.length} + msg_type:{self.msg_typ} + payload:{self.raw_payload}""" + + def __init__(self, service_id=None, methode_id=None, msg_typ=0x01) -> None: + self.raw_payload = None + self.service_id = service_id + self.methode_id = methode_id + self.payload = [] + self.length = 0x0008 + self.client_id = 0x0001 + self.session = 0x0001 + self.msg_typ = msg_typ + self.msg_return = 0x00 + + def read(self, hex_data) -> None: + self.service_id = int.from_bytes(hex_data[0:2], byteorder="big", signed=False) + self.methode_id = int.from_bytes(hex_data[2:4], byteorder="big", signed=False) + self.length = int.from_bytes(hex_data[4:8], byteorder="big", signed=False) + self.msg_typ = hex_data[14] + self.raw_payload = hex_data[16:] + + def set_payload(self, payload) -> None: + self.payload = payload + self.length = 0x8 + len(payload) + + def get_some_ip_data(self): + res = [] + temp_res = [] + size = 0 + for item in self.payload: + if (item <= 255): + size = size + 1 + temp_res.append(item.to_bytes(sizeof(c_uint8), byteorder="little")) + else: + size = size + 2 + temp_res.append(item.to_bytes(sizeof(c_uint16), byteorder="little")) + self.length = 0x8 + size + res.append(self.service_id.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(self.methode_id.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(self.length.to_bytes(sizeof(c_uint32), byteorder="big")) + res.append(self.client_id.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(self.session.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(0x01.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(0x01.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(self.msg_typ.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(self.msg_return.to_bytes(sizeof(c_uint8), byteorder="big")) + for item in temp_res: + res.append(item) + + return res + + def get_some_ip_data_payload(self, payload): + res = [] + self.length = 0x8 + len(payload) + res.append(self.service_id.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(self.methode_id.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(self.length.to_bytes(sizeof(c_uint32), byteorder="big")) + res.append(self.client_id.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(self.session.to_bytes(sizeof(c_uint16), byteorder="big")) + res.append(0x01.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(0x01.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(self.msg_typ.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(self.msg_return.to_bytes(sizeof(c_uint8), byteorder="big")) + res.append(payload) + return res diff --git a/tools/sensors_data_display_api/someip.json b/tools/sensors_data_display_api/someip.json new file mode 100644 index 00000000..7a4e0ce3 --- /dev/null +++ b/tools/sensors_data_display_api/someip.json @@ -0,0 +1,153 @@ +{ + "service_id": 1, + "interface": [ + { + "ip": "127.0.0.1", + "port": 10101 + } + ], + "pub_methods": {}, + "pub_event": {}, + "req_methods": { + "PC_APP/setServoValue": { + "service_id": 515, + "method_id": 1 + }, + "PC_APP/setVentValue": { + "service_id": 515, + "method_id": 3 + }, + "PC_APP/startPrime": { + "service_id": 516, + "method_id": 3 + }, + "PC_APP/EngineStart": { + "service_id": 518, + "method_id": 1 + }, + "PC_APP/EngineSetMode": { + "service_id": 518, + "method_id": 2 + }, + "PC_APP/SetVentValue": { + "service_id": 515, + "method_id": 3 + }, + "PC_APP/EC_diagMethodRequestJob": { + "service_id": 513, + "method_id": 1 + }, + "PC_APP/EC_diagMethodRequestRead": { + "service_id": 513, + "method_id": 2 + }, + "PC_APP/EC_diagMethodRequestWrite": { + "service_id": 513, + "method_id": 3 + }, + "PC_APP/FC_diagMethodRequestJob": { + "service_id": 512, + "method_id": 1 + }, + "PC_APP/FC_diagMethodRequestRead": { + "service_id": 512, + "method_id": 2 + }, + "PC_APP/FC_diagMethodRequestWrite": { + "service_id": 512, + "method_id": 3 + }, + "PC_APP/LoggerStart": { + "service_id": 517, + "method_id": 1 + }, + "PC_APP/LoggerStop": { + "service_id": 517, + "method_id": 2 + } + }, + "req_events": { + "PC_APP/servoVentStatusEvent": { + "service_id": 515, + "event_id": 32770 + }, + "PC_APP/servoStatusEvent": { + "service_id": 515, + "event_id": 32769 + }, + "PC_APP/newTempEvent_1": { + "service_id": 514, + "event_id": 32769 + }, + "PC_APP/newTempEvent_2": { + "service_id": 514, + "event_id": 32770 + }, + "PC_APP/newTempEvent_3": { + "service_id": 514, + "event_id": 32771 + }, + "PC_APP/newTempEvent_4": { + "service_id": 514, + "event_id": 32772 + }, + "PC_APP/newPressEvent": { + "service_id": 514, + "event_id": 32773 + }, + "PC_APP/newNozzlePressEvent": { + "service_id": 514, + "event_id": 32773 + }, + "PC_APP/newDPressEvent": { + "service_id": 514, + "event_id": 32774 + }, + "PC_APP/primeStatusEvent": { + "service_id": 516, + "event_id": 32769 + }, + "PC_APP/EC_newDTCEvent": { + "service_id": 513, + "event_id": 32769 + }, + "PC_APP/FC_currentCPUMode": { + "service_id": 512, + "event_id": 32770 + }, + "PC_APP/currentMode": { + "service_id": 518, + "event_id": 32769 + } + }, + "db": { + "515": { + "ip": "192.168.10.101", + "port": 1515 + }, + "516": { + "ip": "192.168.10.101", + "port": 1516 + }, + "518": { + "ip": "192.168.10.101", + "port": 1518 + }, + "513": { + "ip": "192.168.10.101", + "port": 1513 + }, + "512": { + "ip": "192.168.10.102", + "port": 1512 + }, + "517": { + "ip": "192.168.10.101", + "port": 1517 + }, + "514": { + "ip": "192.168.10.101", + "port": 1514 + } + } +} \ No newline at end of file diff --git a/tools/sensors_data_display_api/test.py b/tools/sensors_data_display_api/test.py new file mode 100644 index 00000000..7a20c446 --- /dev/null +++ b/tools/sensors_data_display_api/test.py @@ -0,0 +1,51 @@ +import socket +import struct +import random +import time +import ctypes + +from some_ip_header import SomeIPHeader + + +first = True +HOST = "127.0.0.1" +PORT = 10101 + +with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: + sock.connect((HOST, PORT)) + i = 0 + while True: + i += 1 + # temperature up + hdr = SomeIPHeader(514, 32769) + payload = struct.pack('H',int(random.uniform(20, 25)*10)) + print(payload) + msg = b''.join(hdr.get_some_ip_data_payload(payload)) + sock.sendto(msg, (HOST, PORT)) + # temperature down + hdr = SomeIPHeader(514, 32770) + payload = struct.pack('H',int(random.uniform(10, 15)*10)) + msg = b''.join(hdr.get_some_ip_data_payload(payload)) + sock.sendto(msg, (HOST, PORT)) + # temperature middle + hdr = SomeIPHeader(514, 32771) + payload = struct.pack('H',int(random.uniform(0, 5)*10)) + msg = b''.join(hdr.get_some_ip_data_payload(payload)) + sock.sendto(msg, (HOST, PORT)) + # tank pressure + hdr = SomeIPHeader(514, 32773) + payload = struct.pack('f', random.uniform(1, 3.3)) + msg = b''.join(hdr.get_some_ip_data_payload(payload)) + sock.sendto(msg, (HOST, PORT)) + # main valve + hdr = SomeIPHeader(515, 32769) + payload = f"test{i}".encode("UTF-8") + msg = b''.join(hdr.get_some_ip_data_payload(payload)) + sock.sendto(msg, (HOST, PORT)) + # pressure difference + hdr = SomeIPHeader(514, 32774) + payload = struct.pack('f', random.uniform(20, 25)) + msg = b''.join(hdr.get_some_ip_data_payload(payload)) + sock.sendto(msg, (HOST, PORT)) + + time.sleep(0.1) diff --git a/tools/sensors_data_display_api/tests/__gui.py b/tools/sensors_data_display_api/tests/__gui.py new file mode 100644 index 00000000..3ebaf9e6 --- /dev/null +++ b/tools/sensors_data_display_api/tests/__gui.py @@ -0,0 +1,43 @@ +import unittest + +from app import App +import logging + +import sys +from pathlib import Path +import tkinter as tk +from unittest.mock import MagicMock + +sys.path.append(str(Path(__file__).resolve().parent.parent)) + +logging.disable(60) + +class TestAppInitialization(unittest.TestCase): + + def setUp(self): + self.app = App() + + def test_window_properties(self): + self.assertEqual(self.app.title(), "Engine") + self.assertEqual(self.app.window_width, 600) + self.assertEqual(self.app.window_height, 600) + + def test_elements_existence(self): + self.assertIsNotNone(self.app.temperature_up) + self.assertIsNotNone(self.app.temperature_down) + self.assertIsNotNone(self.app.temperature_middle) + self.assertIsNotNone(self.app.tank_pressure) + self.assertIsNotNone(self.app.jet_pressure) + self.assertIsNotNone(self.app.pressure_difference) + self.assertIsNotNone(self.app.main_valve) + self.assertIsNotNone(self.app.vent) + self.assertIsNotNone(self.app.start_saving_button) + + def test_start_to_save_file(self): + self.app.start_save_to_file() + self.assertTrue(self.app.saving_thread.is_alive()) + + def test_stop_save_to_file(self): + self.app.start_save_to_file() + self.app.stop_save_to_file() + self.assertFalse(self.app.saving_thread.is_alive()) diff --git a/tools/sensors_data_display_api/tests/runTest.sh b/tools/sensors_data_display_api/tests/runTest.sh new file mode 100755 index 00000000..29a57c48 --- /dev/null +++ b/tools/sensors_data_display_api/tests/runTest.sh @@ -0,0 +1,3 @@ +python3-coverage run -m unittest discover -s . + +python3-coverage report -m \ No newline at end of file diff --git a/tools/sensors_data_display_api/tests/someip.json b/tools/sensors_data_display_api/tests/someip.json new file mode 100644 index 00000000..fbdc2bd3 --- /dev/null +++ b/tools/sensors_data_display_api/tests/someip.json @@ -0,0 +1,41 @@ +{ + "service_id": 1, + "interface": [ + { + "ip": "127.0.0.1", + "port": 10101 + } + ], + "pub_methods": {}, + "pub_event": {}, + "req_methods": { + "PC_APP/setServoValue": { + "service_id": 515, + "method_id": 1 + }, + "PC_APP/readServoValue": { + "service_id": 515, + "method_id": 2 + } + }, + "req_events": { + "PC_APP/servoStatusEvent": { + "service_id": 515, + "event_id": 32769 + }, + "PC_APP/newTempEvent_1": { + "service_id": 514, + "event_id": 32769 + } + }, + "db": { + "515": { + "ip": "192.168.10.101", + "port": 1515 + }, + "514": { + "ip": "192.168.10.101", + "port": 1514 + } + } +} \ No newline at end of file diff --git a/tools/sensors_data_display_api/tests/test_data.py b/tools/sensors_data_display_api/tests/test_data.py new file mode 100644 index 00000000..ba10c10b --- /dev/null +++ b/tools/sensors_data_display_api/tests/test_data.py @@ -0,0 +1,23 @@ +import unittest +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parent.parent)) + +from data import Data + +class TestDataClass(unittest.TestCase): + def test_is_none(self): + data = Data() + self.assertTrue(data.is_none()) + data.jet_pressure = 12.2 + self.assertTrue(data.is_none()) + data.temperature_down=1 + data.temperature_middle=1 + data.temperature_up=1 + data.tank_pressure=1 + data.jet_pressure=1 + data.pressure_difference=1 + data.main_valve=1 + data.vent=1 + self.assertFalse(data.is_none()) diff --git a/tools/sensors_data_display_api/tests/test_data_reader.py b/tools/sensors_data_display_api/tests/test_data_reader.py new file mode 100644 index 00000000..ff1fd195 --- /dev/null +++ b/tools/sensors_data_display_api/tests/test_data_reader.py @@ -0,0 +1,21 @@ +import unittest +from data_reader import DataReader +from unittest.mock import MagicMock, patch + +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parent.parent)) + + +class TestDataReader(unittest.TestCase): + def test_init(self): + dr = DataReader(None,"someip.json") + self.assertEqual(dr.data,0) + self.assertEqual(dr.ip,"127.0.0.1") + self.assertEqual(dr.port,10101) + def test_prepere_lookup_table(self): + dr = DataReader(None,"someip.json") + data = {(515, 32769): 'PC_APP/servoStatusEvent', + (514, 32769): 'PC_APP/newTempEvent_1'} + self.assertEqual(dr.lookup_table, data) \ No newline at end of file diff --git a/tools/sensors_data_display_api/tests/test_someiphdr.py b/tools/sensors_data_display_api/tests/test_someiphdr.py new file mode 100644 index 00000000..7d89a3bb --- /dev/null +++ b/tools/sensors_data_display_api/tests/test_someiphdr.py @@ -0,0 +1,59 @@ +import unittest +import sys +from pathlib import Path +import struct + +# Dodanie katalogu nadrzędnego do ścieżki +sys.path.append(str(Path(__file__).resolve().parent.parent)) + +from some_ip_header import SomeIPHeader + +class TestSomeIpHeader(unittest.TestCase): + def test_constructor(self): + hdr = SomeIPHeader(0x22,0x23,0x1) + self.assertEqual(hdr.service_id,0x22) + self.assertEqual(hdr.methode_id,0x23) + self.assertEqual(hdr.msg_typ,0x1) + self.assertEqual(hdr.payload,[]) + self.assertEqual(hdr.length,0x8) + self.assertEqual(hdr.client_id,0x1) + self.assertEqual(hdr.session,0x1) + self.assertEqual(hdr.msg_return,0x0) + self.assertEqual(str(hdr),""" + service_id:34 + method_id:35 + lenght:8 + msg_type:1 + payload:None""") + + def test_set_payload(self): + hdr = SomeIPHeader(0x01,0x01) + payload = [0,1,2,3,4] + hdr.set_payload(payload) + self.assertEqual(hdr.payload,payload) + self.assertEqual(hdr.length,0x8+len(payload)) + def test_read(self): + hdr = SomeIPHeader() + hex_data=b'\x00\x01\x00\x01\x00\x00\x00\x10\x00\x01\x00\x01\x01\x01\x01\x00\x12\x13' + hdr.read(hex_data) + self.assertEqual(hdr.service_id,0x01) + self.assertEqual(hdr.methode_id,0x01) + self.assertEqual(hdr.length,0x10) + self.assertEqual(hdr.msg_typ,0x1) + self.assertEqual(hdr.raw_payload,b"\x12\x13") + def test_get_some_ip_data(self): + data = b'\x00"\x00#\x00\x00\x00\x08\x00\x01\x00\x01\x01\x01\x01\x00' + hdr = SomeIPHeader(0x22,0x23,0x1) + self.assertEqual(b"".join(hdr.get_some_ip_data()),data) + def test_get_some_ip_data2(self): + data = b'\x00"\x00#\x00\x00\x00\n\x00\x01\x00\x01\x01\x01\x01\x00{\x00' + payload = struct.pack('H',123) + hdr = SomeIPHeader(0x22,0x23,0x1) + hdr.set_payload(payload) + self.assertEqual(b"".join(hdr.get_some_ip_data()),data) + def test_get_some_ip_data_payload(self): + data = b'\x00"\x00#\x00\x00\x00\n\x00\x01\x00\x01\x01\x01\x01\x00{\x00' + payload = struct.pack('H',123) + hdr = SomeIPHeader(0x22,0x23,0x1) + hdr.set_payload(payload) + self.assertEqual(b"".join(hdr.get_some_ip_data_payload(payload)),data) diff --git a/tools/sensors_data_display_api/tests/totalCoverage.sh b/tools/sensors_data_display_api/tests/totalCoverage.sh new file mode 100755 index 00000000..a983018b --- /dev/null +++ b/tools/sensors_data_display_api/tests/totalCoverage.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Wykonanie polecenia coverage report -m i przechwycenie wyniku +coverage_report=$(python3-coverage report -m) + +# Przechwycenie procentowego pokrycia z wyniku +total_coverage=$(echo "$coverage_report" | grep "TOTAL" | awk '{print $NF}') + +echo "Całkowita procentowa pokrywalność kodu: $total_coverage" \ No newline at end of file