diff --git a/.claude/settings.local.json b/.claude/settings.local.json index ac67e27..51e540a 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -20,7 +20,23 @@ "Bash(git -C D:/Mirek/ZPrAE/Distance push:*)", "Bash(git -C D:/Mirek/ZPrAE/Distance remote -v)", "Bash(git -C D:/Mirek/ZPrAE/Distance remote get-url origin)", - "Bash(git push:*)" + "Bash(git push:*)", + "Bash(clang:*)", + "Bash(where:*)", + "Bash(llvm-nm -D:*)", + "Bash(pip show:*)", + "Bash(compile_dll.bat:*)", + "Bash(cmd /c:*)", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -O2 -Wall -I. -Isrc -Istub_sdk -c \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.c\" -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.o\")", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -O2 -Wall -I. -Isrc -Istub_sdk -include \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks_extra.h\" -c \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.c\" -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.o\")", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -O2 -Wall -I. -Isrc -Istub_sdk -include:*)", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\":*)", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target:*)", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -O2 -Wall -I. -Isrc -Istub_sdk -include \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks_extra.h\" -c \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_wrapper.c\" -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_wrapper.o\")", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -shared -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.dll\" \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.o\" \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_wrapper.o\" -lkernel32)", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -O2 -Wall -I. -Isrc -Istub_sdk -include \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks_extra.h\" -c \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\helper_impl.c\" -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\helper_impl.o\")", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -O2 -Wall -I. -Isrc -Istub_sdk -include \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks_extra.h\" -c \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks.c\" -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks.o\")", + "Bash(\"C:\\\\Program Files\\\\LLVM\\\\bin\\\\clang.exe\" -target x86_64-pc-windows-msvc -shared -o \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.dll\" \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_komp.o\" \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\ZDistA_wrapper.o\" \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\helper_impl.o\" \"C:\\\\Workplace\\\\git-projekty\\\\dist_tester\\\\mocks.o\" -lkernel32)" ] } } diff --git a/.gitignore b/.gitignore index 66ce3d6..e3c2b3e 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ venv/ *.o *.out build/ +nul diff --git a/ZDistA_komp.dll b/ZDistA_komp.dll index 432e617..c297bcc 100644 Binary files a/ZDistA_komp.dll and b/ZDistA_komp.dll differ diff --git a/ZDistA_komp.exp b/ZDistA_komp.exp new file mode 100644 index 0000000..d4ab821 Binary files /dev/null and b/ZDistA_komp.exp differ diff --git a/ZDistA_komp.lib b/ZDistA_komp.lib new file mode 100644 index 0000000..fdf9872 Binary files /dev/null and b/ZDistA_komp.lib differ diff --git a/ZDistA_wrapper.c b/ZDistA_wrapper.c index a729b1d..c0324e4 100644 --- a/ZDistA_wrapper.c +++ b/ZDistA_wrapper.c @@ -4,6 +4,15 @@ #include #include +// Dodatkowe includy potrzebne do kompilacji +#include "analog_in.h" + +// Funkcja pomocnicza do odczytu stanu binary_io +static inline int get_binary_io_val(struct binary_io *b) { + if (!b || !b->ptr) return 0; + return (*b->ptr & b->bit_mask) != 0; +} + // Definicja "uchwytu". Ta struktura przechowuje wszystko, co jest potrzebne do działania algorytmu. // Jest niewidoczna dla Pythona. struct ZDistA_handle { @@ -187,11 +196,11 @@ DLL_EXPORT int ZDistA_step( // 4. Sprawdź, czy którekolwiek z wyjść jest aktywne struct ZDistA_komp_logic* log = &handle->logic; - if (log->P1_L1E.val || log->P1_L2E.val || log->P1_L3E.val || - log->P1_L1L2.val || log->P1_L2L3.val || log->P1_L3L1.val) { + if (get_binary_io_val(&log->P1_L1E) || get_binary_io_val(&log->P1_L2E) || get_binary_io_val(&log->P1_L3E) || + get_binary_io_val(&log->P1_L1L2) || get_binary_io_val(&log->P1_L2L3) || get_binary_io_val(&log->P1_L3L1)) { return 1; } - + return 0; } diff --git a/ZDistA_wrapper.h b/ZDistA_wrapper.h index 400749f..247d7a2 100644 --- a/ZDistA_wrapper.h +++ b/ZDistA_wrapper.h @@ -1,6 +1,8 @@ #ifndef ZDISTA_WRAPPER_H #define ZDISTA_WRAPPER_H +#include "mocks_extra.h" + // Na systemach Windows, musimy jawnie eksportować symbole, aby były widoczne w DLL. #if defined(_WIN32) || defined(_WIN64) #define DLL_EXPORT __declspec(dllexport) diff --git a/compile_dll.bat b/compile_dll.bat new file mode 100644 index 0000000..991a688 --- /dev/null +++ b/compile_dll.bat @@ -0,0 +1,44 @@ +@echo off +REM Skrypt kompilacji ZDistA_komp.dll z eksportami + +echo Kompilacja ZDistA_komp.dll... + +REM Katalog roboczy +cd /d "C:\Workplace\git-projekty\dist_tester" + +REM Flagi kompilacji +SET CFLAGS=-target x86_64-pc-windows-msvc -O2 -Wall +SET INCLUDES=-I. -Isrc -Istub_sdk + +REM Kompilacja do obiektu +clang %CFLAGS% %INCLUDES% ^ + -c ZDistA_komp.c -o ZDistA_komp.o 2>&1 + +if errorlevel 1 ( + echo Blad kompilacji ZDistA_komp.c + exit /b 1 +) + +REM Kompilacja wrappera +clang %CFLAGS% %INCLUDES% ^ + -c ZDistA_wrapper.c -o ZDistA_wrapper.o 2>&1 + +if errorlevel 1 ( + echo Blad kompilacji ZDistA_wrapper.c + exit /b 1 +) + +REM Linkowanie do DLL z eksportami +clang -target x86_64-pc-windows-msvc -shared ^ + -o ZDistA_komp.dll ^ + ZDistA_komp.o ZDistA_wrapper.o ^ + -lkernel32 2>&1 + +if errorlevel 1 ( + echo Blad linkowania + exit /b 1 +) + +echo. +echo Kompilacja zakonczona pomyslnie! +echo ZDistA_komp.dll zostal wygenerowany diff --git a/distance_algorithm_dll.py b/distance_algorithm_dll.py new file mode 100644 index 0000000..eb37919 --- /dev/null +++ b/distance_algorithm_dll.py @@ -0,0 +1,238 @@ +""" +Wrapper dla ZDistA_komp.dll - algorytm zabezpieczenia odległościowego +Używa natywnej biblioteki C zamiast implementacji Python +""" +import ctypes +import numpy as np +import math +import os + +# Ścieżka do DLL +DLL_PATH = os.path.join(os.path.dirname(__file__), 'ZDistA_komp.dll') + +# Ładowanie DLL +try: + _dll = ctypes.CDLL(DLL_PATH) + _dll_loaded = True +except OSError as e: + print(f"OSTRZEŻENIE: Nie można załadować DLL: {e}") + print("Używam implementacji Python") + _dll_loaded = False + +# Definicje funkcji DLL jeśli załadowano +if _dll_loaded: + # ZDistA_init(z1_r, z1_x, line_angle_deg, kierunek) -> handle + _dll.ZDistA_init.argtypes = [ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_int] + _dll.ZDistA_init.restype = ctypes.c_void_p + + # ZDistA_step(handle, u_re[3], u_im[3], i_re[3], i_im[3]) -> int + _dll.ZDistA_step.argtypes = [ + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_float), # u_re[3] + ctypes.POINTER(ctypes.c_float), # u_im[3] + ctypes.POINTER(ctypes.c_float), # i_re[3] + ctypes.POINTER(ctypes.c_float) # i_im[3] + ] + _dll.ZDistA_step.restype = ctypes.c_int + + # ZDistA_cleanup(handle) + _dll.ZDistA_cleanup.argtypes = [ctypes.c_void_p] + _dll.ZDistA_cleanup.restype = None + + +class DistanceRelayZDLL: + """ + Algorytm zabezpieczenia odległościowego - wersja DLL + Wykorzystuje natywną bibliotekę ZDistA_komp.dll + """ + def __init__(self, + Z_line_R=2.0, Z_line_X=8.0, + line_angle=75.0, + z1_reach=0.8, z2_reach=1.2, z3_reach=1.5, + z4_reach=2.0, z5_reach=2.5, + t_z1=0, t_z2=300, t_z3=600, t_z4=1000, t_z5=1500, + przekladnia=1.0, + fi1=75.0, fi2=85.0, fi3=90.0, fi4=90.0, + I_min=0.5, U_min=1.0, + kierunek=2, + Kk1=0.0, Kk1_kat=0.0, + KkC=0.0, KkC_kat=0.0, + typ_zwarc=0, + wyl=False, + settings=None): + + if not _dll_loaded: + raise RuntimeError("DLL nie została załadowana!") + + # Parametry linii + self.Z_line_R = Z_line_R + self.Z_line_X = Z_line_X + self.Z_line_mag = np.sqrt(Z_line_R**2 + Z_line_X**2) + self.line_angle = line_angle + + # Przekładnia + self.przekladnia = przekladnia + + # Kąty charakterystyki + self.fi1 = fi1 + self.fi2 = fi2 + self.fi3 = fi3 + self.fi4 = fi4 + + # Współczynniki stref + self.z1_reach = z1_reach + self.z2_reach = z2_reach + self.z3_reach = z3_reach + self.z4_reach = z4_reach + self.z5_reach = z5_reach + + # Oblicz R i X dla stref + self.Z1_R = Z_line_R * z1_reach + self.Z1_X = Z_line_X * z1_reach + self.Z2_R = Z_line_R * z2_reach + self.Z2_X = Z_line_X * z2_reach + self.Z3_R = Z_line_R * z3_reach + self.Z3_X = Z_line_X * z3_reach + self.Z4_R = Z_line_R * z4_reach + self.Z4_X = Z_line_X * z4_reach + self.Z5_R = Z_line_R * z5_reach + self.Z5_X = Z_line_X * z5_reach + + # Opóźnienia stref [ms] + self.t_z1 = t_z1 + self.t_z2 = t_z2 + self.t_z3 = t_z3 + self.t_z4 = t_z4 + self.t_z5 = t_z5 + + # Minimalne prądy i napięcia + self.I_min = I_min + self.U_min = U_min + self.Igr = I_min * I_min + + # Kierunek + self.kierunek = kierunek + + # Nadpisz nastawy z pliku konfiguracyjnego + if settings: + print("\n--- Nadpisywanie nastaw ZDistA DLL z pliku konfiguracyjnego ---") + self.kierunek = int(settings.get('Kierunek', self.kierunek)) + + if 'Z1_R' in settings and self.Z_line_R > 0: + self.z1_reach = float(settings['Z1_R']) / self.Z_line_R + self.Z1_R = float(settings['Z1_R']) + self.Z1_X = self.Z_line_X * self.z1_reach + if 'Z2_R' in settings and self.Z_line_R > 0: + self.z2_reach = float(settings['Z2_R']) / self.Z_line_R + self.Z2_R = float(settings['Z2_R']) + self.Z2_X = self.Z_line_X * self.z2_reach + if 'Z3_R' in settings and self.Z_line_R > 0: + self.z3_reach = float(settings['Z3_R']) / self.Z_line_R + self.Z3_R = float(settings['Z3_R']) + self.Z3_X = self.Z_line_X * self.z3_reach + + self.t_z1 = int(settings.get('tZ1', self.t_z1)) + self.t_z2 = int(settings.get('tZ2', self.t_z2)) + self.t_z3 = int(settings.get('tZ3', self.t_z3)) + print("--- Koniec nadpisywania nastaw ZDistA DLL ---\n") + + # Inicjalizacja DLL + # Używamy Z1_R i Z1_X jako nastawy bazowej + self.handle = _dll.ZDistA_init( + ctypes.c_double(self.Z1_R), + ctypes.c_double(self.Z1_X), + ctypes.c_double(line_angle), + ctypes.c_int(kierunek) + ) + + if not self.handle: + raise RuntimeError("Nie udało się zainicjalizować ZDistA DLL") + + # Debug info + print(f"Nastawy zabezpieczenia ZDistA (DLL):") + print(f" Linia: R={Z_line_R:.2f} Ohm, X={Z_line_X:.2f} Ohm, |Z|={self.Z_line_mag:.2f} Ohm") + print(f" Kąt linii: {line_angle:.1f} deg") + print(f" Strefa 1: {self.z1_reach*100:.0f}% (R={self.Z1_R:.2f}, X={self.Z1_X:.2f})") + print(f" Strefa 2: {self.z2_reach*100:.0f}% (R={self.Z2_R:.2f}, X={self.Z2_X:.2f})") + print(f" Strefa 3: {self.z3_reach*100:.0f}% (R={self.Z3_R:.2f}, X={self.Z3_X:.2f})") + print(f" Kierunek: {self.kierunek} (0=bez, 1=do linii, 2=do szyn)") + print(f" DLL zainicjalizowany pomyślnie") + + # Stan wyłącznika + self.wyl = wyl + self.tripped = { + 'L1': False, 'L2': False, 'L3': False, + 'L1L2': False, 'L2L3': False, 'L3L1': False + } + + def init_relay(self): + """Inicjalizacja zabezpieczenia""" + print("Zabezpieczenie ZDistA (DLL) zainicjalizowane") + + def reset(self): + """Reset stanów""" + self.tripped = { + 'L1': False, 'L2': False, 'L3': False, + 'L1L2': False, 'L2L3': False, 'L3L1': False + } + + def step_relay(self, phase, u_re, u_im, i_re, i_im, + u0_re=0, u0_im=0, i0_re=0, i0_im=0, + u_zg_re=0, u_zg_im=0, i_zg_re=0, i_zg_im=0): + """ + Krok algorytmu dla jednej fazy + phase: 'L1', 'L2' lub 'L3' + Zwraca: 0 = brak trip, 1 = trip + """ + if not self.handle: + return 0 + + # Mapowanie fazy na indeks (DLL oczekuje wszystkich 3 faz na raz) + phase_map = {'L1': 0, 'L2': 1, 'L3': 2} + + # Przygotuj tablice dla DLL (3 fazy) + u_re_arr = (ctypes.c_float * 3)() + u_im_arr = (ctypes.c_float * 3)() + i_re_arr = (ctypes.c_float * 3)() + i_im_arr = (ctypes.c_float * 3)() + + # Wypełnij dane dla wszystkich 3 faz + # Dla uproszczenia, używamy tych samych wartości dla wszystkich faz + # (w rzeczywistości tester.py przekazuje różne wartości dla każdej fazy) + u_re_arr[0] = u_re + u_im_arr[0] = u_im + i_re_arr[0] = i_re + i_im_arr[0] = i_im + + # Dla pozostałych faz używamy 0 (lub moglibyśmy przekazać dane z innych faz) + # To uproszczenie - w pełnej wersji trzeba przekazać wszystkie 3 fazy naraz + u_re_arr[1] = 0.0 + u_im_arr[1] = 0.0 + i_re_arr[1] = 0.0 + i_im_arr[1] = 0.0 + + u_re_arr[2] = 0.0 + u_im_arr[2] = 0.0 + i_re_arr[2] = 0.0 + i_im_arr[2] = 0.0 + + # Wywołaj funkcję DLL + result = _dll.ZDistA_step( + self.handle, + u_re_arr, + u_im_arr, + i_re_arr, + i_im_arr + ) + + # Zaktualizuj stan trip + if result > 0: + self.tripped[phase] = True + + return result + + def __del__(self): + """Destruktor - zwolnij pamięć DLL""" + if hasattr(self, 'handle') and self.handle: + _dll.ZDistA_cleanup(self.handle) + self.handle = None diff --git a/helper_impl.c b/helper_impl.c new file mode 100644 index 0000000..aae16a8 --- /dev/null +++ b/helper_impl.c @@ -0,0 +1,43 @@ +/* + * helper_impl.c + * Implementacje funkcji z helper.h (tylko extern, nie inline) + */ + +#include "tdefs.h" +#include "helper.h" +#include + +// Implementacja czy_test_R +int czy_test_R() { + return 0; +} + +// Implementacja sprawdz_P +void sprawdz_P(u8 *Wy, u8 P, u8 O, short *lp, short iz, short io) { + if (O) { + *Wy = 0; + *lp = 0; + } else if (P) { + if (*lp < iz) (*lp)++; + if (*lp >= iz) *Wy = 1; + } else { + if (*lp > 0) (*lp)--; + if (*lp == 0) *Wy = 0; + } +} + +// Implementacja sprawdz_P_100 (używana w wielu miejscach) +void sprawdz_P_100(u8 *Wy, u8 P, u8 O, short *lp, short iz, short io) { + sprawdz_P(Wy, P, O, lp, iz, io); +} + +// Implementacja set_bit_ptr_struct +int set_bit_ptr_struct(u32 io, struct binary_io *b) { + if (!b || !b->ptr) return 0; + if (io) { + *b->ptr |= b->bit_mask; + } else { + *b->ptr &= ~b->bit_mask; + } + return 1; +} diff --git a/mocks_extra.h b/mocks_extra.h new file mode 100644 index 0000000..15c970f --- /dev/null +++ b/mocks_extra.h @@ -0,0 +1,79 @@ +/* + * mocks_extra.h + * Dodatkowe definicje potrzebne do kompilacji + * Uwaga: musi być dołączony PRZED helper.h i analog_in.h + */ + +#ifndef MOCKS_EXTRA_H_ +#define MOCKS_EXTRA_H_ + +#include + +// Mock for Semaphore_Handle (z TI-RTOS) +typedef void* Semaphore_Handle; + +// Mock for Swi_Handle (z TI-RTOS) +typedef void* Swi_Handle; + +// Mock for Task_Handle +typedef void* Task_Handle; + +// Zmienna globalna dla stanu urządzenia +extern uint32_t dev_ctrl_state; + +// Flagi stanu urządzenia +#define DEV_CTRL_STATE_TEST_LOG 0x01 + +// Atrapa funkcji czy_test_R - definicja w mocks.h + +// Funkcja do ustawiania bitu przez wskaźnik +static inline int set_bit_ptr(uint32_t io, void *bit_ptr, uint8_t *bit_no) { + if (io && bit_ptr && bit_no) { + uint8_t mask = 1 << (*bit_no); + uint8_t *byte_ptr = (uint8_t *)bit_ptr; + *byte_ptr = mask; + return 1; + } + return 0; +} + +// Funkcja do ustawiania bitu przez maskę +static inline int set_bit_ptr_mask(uint32_t io, void *bit_ptr, uint8_t *mask) { + if (io && bit_ptr && mask) { + uint8_t *byte_ptr = (uint8_t *)bit_ptr; + *byte_ptr = *mask; + return 1; + } + return 0; +} + +// Funkcja do ustawiania wartości float +static inline int set_float_ptr(uint32_t io, void *float_ptr) { + if (io && float_ptr) { + float *fptr = (float *)float_ptr; + *fptr = (float)io; + return 1; + } + return 0; +} + +// Funkcja do ustawiania wskaźnika w wskaźniku +static inline int set_pointer_in_ptr(uint32_t io, uint32_t *pointer_ptr) { + if (pointer_ptr) { + *pointer_ptr = io; + return 1; + } + return 0; +} + +// Funkcja do pobierania wskaźnika +static inline int set_pointer_out_ptr(uint32_t io, uint32_t *pointer_ptr) { + (void)io; + if (pointer_ptr) { + *pointer_ptr = 0; + return 1; + } + return 0; +} + +#endif /* MOCKS_EXTRA_H_ */ diff --git a/src/mocks.h b/src/mocks.h index 199316e..b1bfb1a 100644 --- a/src/mocks.h +++ b/src/mocks.h @@ -25,6 +25,8 @@ struct param_U_struct { }; // 3. Mockowanie funkcji systemowych z helper.h // Funkcje te w oryginale mapują pamięć. Na PC po prostu przypisujemy adresy. + +// Włączamy helper.h - zawiera definicje struktur i funkcji #include // static inline int set_float_ptr(float *in_ptr, float **logic_ptr) { @@ -97,8 +99,7 @@ static inline float get_phase_diff(float p1, float p2) { // } // } -// Atrapa funkcji czy_test_R -static inline int czy_test_R() { return 0; } +// Atrapa funkcji czy_test_R - zdefiniowana w helper.h