Jak się kiedyś robiło polskie litery: praktyczny przykład z roku 1991

Dokumentacja:

(Tekst pochodzi z jakiegoś zamierzchłego edytora, stąd osobliwości, mimo oczyszczenia…)

*═══════════════════════════════════════════════════════*
EMUlator
Polskojęzyczne Środowisko programów.

*═══════════════════════════════════════════════════════*
CO TO JEST.

Program EMU (EMUlator bios’a) tworzy zintegrowane polskojęzyczne środowisko dla programów , korzystających przy obsłudze ekranu z funkcji BIOSa, głównie Clippper’owskich, ale także np.: C, FORTRAN, PASCAL. Umożliwia polskojęzyczną pracę dowolnego programu – przez uzyskanie i obsługę polskich znaków na ekranie, klawiaturze i drukarce, w dowolnym z kodów przyjętych w Polsce:

LATIN_2 – jedyny oficjalny kod polskich liter, stosowany przez IBM, Emix, Elwro,
MAZOVIA – jak sama nazwa wskazuje,
CSK – Computer Studio Kajkowscy (Mbank),
DHN – Dom Handlowy Nauki,
CYFROMAT –
MICROVEX –
UNIA –
NONE – nie używa żadnego kodu.

EMUlator jest zewnętrzny względem obsługiwanego programu – nie ma dla niego znaczenia w której wersji Clipper’a został
skompilowany program. Istotne jest tylko aby program kontaktował się z EMUlatorem w ustalony sposób. Program pracujący pod EMUlatorem może całkowicie poprawnie pracować bez EMUlatora – oczywiście bez polskich liter.

Dla skorzystania EMUlatora konieczne jest tylko posiadanie karty Hercules z dostępnymi obydwiema stronami graficznymi. Praktycznie znaczy to, że nie może być zainstalowana oprócz HGC karta CGA.

Wraz z EMUlatorem dostarczane są funkcje pozwalające użytkownikowi na uzyskanie całkowicie polskojęzycznego programu, co oznacza całkowicie polskojęzyczne sortowanie i wyszukiwanie.

Użytkownik może także w programie w łatwy sposób wywoływać wewnętrzne funkcje EMUlatora, jak np. definiować własne znaki.

EMUlator umożliwia przemienne stosowanie dowolnego standardu polskich liter, co może być niezwykle wygodne np.: przy pisaniu oprogramowania dla użytkowników stosujących różne standardy.

EMUlator nie jest rezydentny – więc nie zajmuje pamięci wtedy gdy nie jest potrzebny, gwarantuje, że po zakończeniu potomnego programu (nie ma znaczenia w jaki sposób się on zakończy) zostanie przywrócony normalny stan DOSa.

EMUlator instaluje własne przerwanie, pozwalające programowi użytkownika na bezpośrednie korzystanie z jego funkcji. Dostarczona dokumentacja oraz dostarczone wersje źródłowe funkcji pozwolą użytkownikowi znającemu asembler lub C na swobodne pisanie własnych funkcji korzystających z EMUlatora.

*═══════════════════════════════════════════════════════*

URUCHOMIENIE.

EMUlator uruchamia się w postaci:

EMU [-kod] nazwa_programu_do_uruchomienia [jego_argumenty…]

– kod w postaci minus i nazwa kodu polskich liter, tak jak to zostało podane powyżej. EMUlator domyślnie używa LATIN_2.
– nazwa_programu_do_uruchomienia – nazwa zbioru, który ma zostać uruchomiony jako potomek EMUlatora.
– jego_argumenty – o ile są podane to zostaną przekazane potomkowi.

Przykład:

Aby uruchomić program ‚kadry.exe’ trzeba napisać:
C:>EMU kadry.exe <───┘ Aby uruchomić DOSa w wersji polskiej – o ile nie masz zainstalowanego ANSI.SYSa ! – trzeba napisać: C:>EMU command <───┘ Możesz wypisać ten właśnie dokument po polsku pisząc: C:>type pg.doc >prn.

Zakończenie pracy uzyskasz pisząc:
C:>exit <───┘. Wraz z EMUlatorem został dostarczony przykładowy program ‚^demo.prg’ oraz ‚^clpm.bat’ służący do jego kompilacji. Uwaga: EMUlator szuka zbioru podanego do uruchomienia po ścieżce – PATH. Nie jest możliwe bezpośrednie uruchamianie zbiorów typu .BAT przez EMUlator. EMUlator pozwala uruchomić program o nazwie z dowolnym rozszerzeniem, nie tylko .COM i .EXE, ale próba uruchomienia zbioru tekstowego może skończyć się bardzo źle (nie wiadomo co on zrobi podczas wykonania, ale na pewno nic dobrego). *═══════════════════════════════════════════════════════* ZAKOŃCZENIE PRACY. Program potomny po wykonaniu się zawsze powraca do EMUlatora, niezależnie od sposobu zakończenia, a EMUlator przywraca poprzedni stan systemu i wyświetla końcowe informacje. W pierwszym wierszu: nazwę programu, numer wersji i numer seryjny. W drugim: nazwę używanego kodu polskich liter, oraz – jeżeli potomny program został poprawnie uruchomiony to podawany jest jego kod wyjścia w postaci dwóch liczb – pierwsza określa sposób zakończenia programu przez DOSa (0 – normalne, 1 – Ctrl-C, 2 – błąd urządzenia, 3 – program rezydentny), a druga jest to kod podawany przez program przy zakończeniu, w Clipper’ze obsługiwany funkcją ERRORLEVEL(). Jeżeli potomny program nie został uruchomiony to podawany jest komunikat określający rodzaj błędu, raportowanego przez funkcję SPAWN. Uwaga: Jeżeli program Clipper’owski załamie się podczas wykonania nagłówka, a przed rozpoczęciem właściwego programu – to zwrócony kod wyjścia nie będzie miał nic wspólnego z określonym przez ERRORLEVEL() w programie. Typowe błędy to: ENOENT – podany program nie został znaleziony ani w bieżącym katalogu, ani na ścieżce – albo go rzeczywiście nie ma, albo to literówka w jego nazwie. ENOMEM – jest za mało pamięci dla uruchomienia potomka – najpewniej masz jakiś program rezydentny – spróbuj go usunąć, wyjdź z NC, jeżeli w nim jesteś. ENOEXEC – to, co chcesz uruchomić, zdaniem DOSa, nie da się uruchomić. Jeżeli to rzeczywiście jest program typu EXE, to prawdopodobnie jest uszkodzony. E2BIG – nie powinno się pojawić, ale jeżeli się pojawi to sygnalizuje przepełnienie (prawdopodobnie) obszaru przeznaczonego na zmienne ustawiane przez SET – sprawdź to. Inne komunikaty świadczą, że prawdopodobnie EMUlator jest uszkodzony – czy to na dysku, czy to przez uruchomiony program. *═══════════════════════════════════════════════════════* SIDEKICK i inne rezydentne programy. Możliwe jest używanie wraz z EMUlatorem także Sidekick’a – istotne jest tylko, aby kończyć pracę z nim przez ESC, co przywróci właściwy tryb pracy ekranu, zmieniony przez SK. Nie jest wykluczone powstanie konfliktów pomiędzy niektórymi programami rezydentnymi a EMUlatorem przy obsłudze klawiatury. Dotąd nie zetknąłem się z czymś takim, ale jeżeli wystąpi to spróbuj empiryczne ustalić, czy zmiana kolejności instalowania programów nie zlikwiduje problemu. *═══════════════════════════════════════════════════════* INFORMACJE SZCZEGÓŁOWE: EKRAN. Podczas pracy programu ekran jest przełączany w tryb graficzny (640×350), znaki na ekranie są wyświetlane są jako graficzne, symulowana jest także sprzętowa obsługa kursora. Program użytkowy nie zdaje sobie z tego sprawy – dla programu użytkowego jest to monochromatyczny mod tekstowy 80×25 (mod 7). Po zakończeniu programu użytkowego jest przywracany poprzedni stan ekranu. Program pisze bezpośrednio do rejestrów kontrolera wizji, oraz samodzielnie wykonuje HGC FULL. Problemem jest interpretowanie atrybutów ekranu tekstowego w trybie graficznym. Program przedstawia znaki o podwyższonej jaskrawości oraz migające jako italiki (pochylone). Nie ma przeszkód przed dowolnym rozszerzeniem ilości fontów, spowoduje to jednak wzrost wielkości programu o więcej niż 256*14=3584 bajty, jeżeli życzysz sobie tego – skontaktuj się z autorem. EMUlator pozwala uzyskać dwa rodzaje kursora: stały oraz migający. EMU_CALL(33,0) && uruchomienie kursora NIE migającego Interpretacja atrybutów – Clipper. EMUlator musi przekształcić atrybuty ekranu do postaci odpowiedniej dla ekranu graficznego – tworzonego przez czarne i białe punkty. W clipper’ze dla tej wersji EMUlatora optymalną konwersję uzyskuje się dla: SETCOLOR(„W/N ,N+/U,,W,N/W”) Atrybut W dla BORDER’u jest zalecany, ponieważ określa on kolor znaków przy pracy z EMU.cga. Jeżeli życzysz sobie EMUlatora dostosowanego do swoich potrzeb – skontaktuj się z autorem, adres jest na końcu tekstu. *══════════════════════════════════════════════════════* INFORMACJE SZCZEGÓŁOWE: KLAWIATURA. Program obsługuje klawiaturę w sposób znany jako ‚klawiatura programisty’. Oznacza to, że literę ‚ą’ uzyskuje się naciskając klawisz ‚a’ wraz z klawiszem ALT, a literę ‚Ą’ – klawisz ‚A’ wraz z klawiszami SHIFT i ALT. (Litery ‚ż’ i ‚ź’ są przyporządkowane klawiszom ‚Z’ i ‚X’.) Klawisz ALT spełnia funkcję POLSKIEGO SHIFTa. Obsługę polskich liter włącza i wyłącza się klawiszem ScrollLock – co pozwala na używanie także kombinacji typu ALT-A, czy ALT-C, co jest niezbędne w wielu programach. Przez użycie EMU_CALL(69, 1) uzyskuje się wymuszenie polskiej klawiatury – stan ScrollLock nie ma wtedy znaczenia. Uwaga: Przez użycie EMU_CALL(71, 1) podczas aktywności polskich liter na klawiaturze: lewy shift oraz prawy shift wraz z klawiaturą numeryczną, szarym ‚+’ i ‚-‚ będą wypisywać znaki tworzące ramki, odpowiednio: pojedynczą i podwójną. Wraz z CapsLock wypisują znaki łączące ramki pojedyncze z podwójnymi. Także z klawiszami Esc, Backspace i Del są związane symbole semigraficzne. *═══════════════════════════════════════════════════════* INFORMACJE SZCZEGÓŁOWE: DRUKARKA. Przy drukowaniu polskich liter mogą wystąpić następujące sytuacje: 1) Drukarka ma zaprogramowany zestaw znaków. Rozwiązanie najprostsze w eksploatacji, ale często niewygodne do uzyskania – gdy oznacza konieczność przeprogramowania wlutowanych EPROMów, a trudne szczególnie dla egzotycznych drukarek. Zaletą są dobre kształty znaków, wadą przywiązanie do jednego kodu – szczególnie w warunkach krajowej wielości obowiązujących standardów. 2) Zaprogramowanie polskich liter na drukarce. Po każdym włączeniu drukarki należy wysłać do niej ciąg znaków definiujących polskie litery. Kody i kształty polskich liter określane są przy ich definiowaniu i mogą być różne dla różnych programów. 3) Metoda BackSpace. Polska litera powstaje poprzez wydrukowanie angielskiego odpowiednika, cofnięcie głowicy przez BS i wydrukowanie odpowiedniego ogonka. Przykładowo, ‚ą’ powstaje z ‚a’, BS, ‚,’. Wielką zaletą tej metody jest to, że działa praktycznie na wszystkich drukarkach, dając przyzwoite kształty polskich liter oraz tolerując wszelkie błędy wydruku. Metoda ta jest męcząca dla drukarki, co też jest jej największą wadą, a przy większej ilości polskich liter w tekście powolna. Ta metoda jest ustawiana przy starcie EMUlatora. Załączenie tej funkcji w programie uzyskuje się przez: EMU_CALL(129, 1) 4) Metoda dwu wierszy. Tekst jest drukowany wierszami. Jeżeli w drukowanym wierszu znajduje się polska litera to wiersz drukowany jest dwa razy: w pierwszym przebiegu angielskie odpowiedniki, w drugim przebiegu na pierwszy wiersz nadrukowywane są ogonki. Metoda nie obciąża drukarki, co jest jej największą zaletą. Wadą metody jest konieczność obsługi przez dosyć skomplikowany program, posiadający co najmniej jeden bufor, o długości większej od długości drukowanych wierszy. Jeżeli program obsługi będzie w miarę uniwersalny, to nie będzie mógł rozumieć większości kodów sterujących drukarki (gdyby chciał je rozumieć, to musiałby być funkcjonalną kopią programu sterującego drukarką). Użytkownik musi wydruki projektować biorąc pod uwagę istnienie i działanie programu. Jeżeli używasz tej metody, to pamiętaj, że handler drukarki rozpoznaje tylko typowe kody sterujące – żadnego z rozpoczynających się od ESCape (DODATEK C). Jeżeli stosujesz wielokrotne nadrukowywanie dla uwydatnienia tekstu, to w tej metodzie to nie zadziała. Załączenie tej funkcji w programie uzyskuje się przez: EMU_CALL(129, 2) *═══════════════════════════════════════════════════════* DODATEK A. Funkcje użytkownika. EMU_CALL(ax, bx, cx, dx, si, di) Wywołanie EMUlatora – to znaczy wykonanie przerwania INT 64h z podanymi wartościami w rejestrach – zgodnie z DODATKIEM B. Funkcja EMU_CALL() może być wywołana niezależnie od obecności EMUlatora. Na wejściu: ax – bx – cx – dx – si – di – Na wyjściu: bx – EMU_DEF(font, znak, def_string) Definiowanie własnych znaków przez użytkownika. Na wejściu: font – numer fontu, tutaj 0 znak – numer znaku 0..255 def_string – 14 znakowy (dla HGC) łańcuch zawierający definicję Na wyjściu: [ NIC ] ISEMU() Sprawdzenie obecności EMUlatora. Na wejściu: [ NIC ] Na wyjściu: .T. – EMUlator jest obecny .F. – nie ma EMUlatora PL_INIT() Inicjalizacja funkcji obsługujących polskie litery. Dane są czytane z EMUlatora, konieczne jest wywołanie tej funkcji na początku programu oraz po zmianie kodu polskich liter. Na wejściu: [ NIC ] Na wyjściu: .T. – EMUlator jest obecny .F. – nie ma EMUlatora PL_UPPER() Zamiana na duże litery, z uwzględnieniem aktualnych polskich. Na wejściu: Tekst Na wyjściu: Tekst PL_LOWER() Zamiana na małe litery, z uwzględnieniem aktualnych polskich. Na wejściu: Tekst Na wyjściu: Tekst PL_MAP() Zamienia na angielskie odpowiedniki podane polskie, z uwzględnieniem aktualnych polskich („Kądziołka”->”Kadziolka”). Funkcja pozwala wyszukiwać w zbiorze polskojęzyczne teksty, niezależnie od tego, czy zostały wpisane z polskimi literami, czy też bez. Przy indeksowaniu pozwala uzyskać przyzwoite polskojęzyczne uporządkowanie.

Przykładowo: ciągi znaków ‚AĄB’, ‚AĄA’, ‚AAB’ zostaną przez PL_MAP() uporządkowane następująco: ‚AĄA’, ‚AAB’, ‚AĄB’.

Na wejściu:
Tekst

Na wyjściu:
Tekst

PL_ORD()
Przekształca podany tekst na łańcuch zawierający bajty określające bezwzględną kolejność podanych znaków – z uwzględnieniem polskich liter. Użycie funkcji przy indeksowaniu spowoduje polskojęzyczne uporządkowanie zbioru.

Przykładowo: ciągi znaków ‚AĄB’, ‚AĄA’, ‚AAB’ zostaną przez PL_ORD() uporządkowane następująco: ‚AAB’, ‚AĄA’, ‚AĄB’.

Na wejściu:
Tekst

Na wyjściu:
Tekst

UWAGA:
W zbiorze $emu.c zawarte są dwie wersje niektórych funkcji, jedna operująca na kopii przekazanego łańcucha, druga bezpośrednio na samym łańcuchu.

*═══════════════════════════════════════════════════════*
DODATEK B.
Przerwanie EMUlatora.

EMUlator podczas pracy instaluje przerwanie 0x64, poprzez które potomny program uzyskuje dostęp do EMUlatora.

Sposób wywołania:

Na wejściu:

rejestr AX – numer funkcji
rejestr BX – główny argument
rejestry CX, DX, SI, DI – argumenty pozostałe
INT 64h

Na wyjściu:

rejestry BX, CX, DX, SI, DI
rejestr AX – jeżeli równy 0xffff, to brak funkcji którą wywoływano
rejestr BX – w nim zwracana jest główna wartość
rejestry CX, DX, SI, DI – pozostałe dane (o ile takowe są)

Opis wszystkich funkcji EMUlatora znajduje się w zbiorze ’emu_func.doc’.

*═══════════════════════════════════════════════════════*
DODATEK C.

Liniowy handler drukarki.
Poniżej podane jest, w jaki sposób liniowy handler drukarki traktuje znaki o kodach 0..31 i 127.

Znaki przesyłane do drukarki bez zmian – jednokrotnie.

Kod 0 – NULL
Kod 1 – SOH
Kod 2 – STX
Kod 3 –
Kod 4 –
Kod 5 –
Kod 6 –
Kod 7 – BEL
Kod 16 – DLE
Kod 17 – DC1
Kod 19 – DC3
Kod 21 –
Kod 22 – SYN
Kod 23 – ETB
Kod 25 – EM
Kod 26 – SUB
Kod 27 – ESC
Kod 28 – FS
Kod 29 – GS
Kod 30 – RS
Kod 31 – US

Znaki przesyłane w obydwu przebiegach.

Kod 8 – BS
Kod 9 – HT
Kod 14 – SO
Kod 15 – SI
Kod 18 – DC2
Kod 20 – DC4
Kod 127 – DEL

Znaki przesyłane i traktowane przez handler jako sterujące.

Kod 10 – LF wysuw papieru o jeden wiersz, powoduje wydruk.
Kod 11 – VT tabulacja pionowa, powoduje wydruk.
Kod 12 – FF wysuw do nowej strony, powoduje wydruk.
Kod 13 – CR powoduje wydruk, także bufora wewnętrznego.
Kod 24 – CAN skasowanie bufora drukarki, także wewnętrznego

Przy próbie przekroczenia wielkości bufora wewnętrznego jest on kasowany i blokowany, aż do rozpoczęcia nowego wiersza.
*═══════════════════════════════════════════════════════*
DODATEK D.

Kolejność polskich liter.
Polskie litery są umieszczone w wewnętrznych buforach programu w poniższej kolejności: „ĄĆĘŁŃÓŚŹŻ”, „ąćęłńóśźż”. Kolejność ta obowiązuje także dla funkcji sortujących.
*═══════════════════════════════════════════════════════*
DODATEK E.

Przygotowanie programu do współpracy z EMUlatorem – Clipper.

UWAGA:

Wśród zbiorów dostarczanych z EMUlatorem znajduje się ‚^DEMO.PRG’, będący przykładowym programem prezentującym podstawowe zastosowania funkcji użytkownika.
Dla wstępnego uruchomienia wystarczy linkować program z PCBIOS.OBJ. Pozwoli to na ewentualne skorygowanie ustawienia atrybutów (SET COLOR ) w programie, tak aby uzyskać jego właściwą postać przy pracy z EMUlatorem.
Następnym etapem jest wpisanie polskich liter do formatek i komunikatów programu.
Taki program będzie już pozwalał wprowadzać dane po polsku, a także będzie pisał na ekranie i drukarce po polsku. Jeżeli pola, w których są polskie litery nie są używane do indeksowania lub wyszukiwania, to może to być już koniec przeróbek!
Aby uzyskać polskojęzyczne sortowanie i wyszukiwanie trzeba oprócz PCBIOS.OBJ zlinkować z programem EMU.LIB (DODATEK G).
Na początku programu trzeba ustawić parametry pracy EMUlatora przez wywołania funkcji EMU_CALL().

*
IF ISEMU() && tylko wtedy, gdy jest EMUlator
*
SETCOLOR(„W/N ,N+/U,,W,N/W”)
*
EMU_CALL(33, 1) && kursor migający
EMU_CALL(65, 1) && kod aktualnie obowiązujących
&& polskich znaków – LATIN 2
EMU_CALL(69, 1) && polskie litery niezależne od ScrollLock
EMU_CALL(129, 2)&& wierszowa obsługa polskich liter
*
* Potem należy wywołać PL_INIT().
PL_INIT()
*
ELSE
* można uniemożliwić uruchomienie programu bez EMU,
* albo ustawić parametry programu dla pracy bez EMU.
*
?
? „*** Ten program wymaga EMUlatora ***”
?
QUIT
ENDIF
*

Jeżeli w bazie dane mają być zapisane dużymi literami to umieścić PL_UPPER() bezpośrednio w instrukcji REPLACE, co da pewność, że zostaną przekształcone.
Jeżeli stosuje się indeksowanie po polach mogących zawierać polskie litery użyć funkcji PL_MAP() albo PL_ORD().
Funkcja PL_MAP() przekształca polskie litery na angielskie odpowiedniki, co oznacza, że np. z ‚Kądziołki’ powstanie ‚Kadziolka’. Użycie tej funkcji do indexowania i wyszukiwania spowoduje, że: dane zostaną posortowane sensownie, ale nie doskonale – ‚ą’ będzie traktowane dokładnie jak ‚a’, ale też program będzie tolerował polskie dane wpisane po angielsku – np. wpisane przed użyciem EMUlatora, jak i błędy przy wprowadzaniu spowodowane brakiem przyzwyczajenia do używania polskich liter.

Przykład:
USE osoby
INDEX ON Pl_map(Pl_upper(nazwisko)) TO nazw
x = „Kądziołka”
x = Pl_upper(x)
SEEK Pl_map(x) * LOCATE FOR Pl_map(x) == Pl_map(osoby->nazwisko)
? imie

Funkcja PL_ORD() przekształca polskie litery na kody, określające w jednoznaczny sposób ich kolejność. Użycie tej
funkcji do indexowania i wyszukiwania spowoduje, że program będzie pracował CAŁKOWICIE po polsku.

Przykład:
USE osoby
INDEX ON Pl_ord(Pl_upper(nazwisko)) TO nazw
x = „Kądziołka”
x = Pl_upper(x)
SEEK Pl_ord(x)
? imie

Podobnie należy postąpić przy wyszukiwaniu (SEEK, LOCATE), oraz przy porównywaniu tekstów polskojęzycznych (IF PL_MAP(x) == PL_MAP(y) ).
Opisane funkcje mogą być wywoływane mimo braku EMUlatora – działają wtedy angielskojęzycznie.
Powyższe wskazówki są wyłącznie orientacyjne – każdy program jest inny i najważniejsze, to wiedzieć, co chce się osiągnąć.
*═══════════════════════════════════════════════════════*
DODATEK F.

Kompilacja.
Poniżej przedstawiony jest BATCH służący do kompilacji programów korzystających z funkcji użytkownika.

Założenia:

W katalogu C:\CLP znajduje się Clipper, czyli CLIPPER.EXE,
CLIPPER.LIB, EXTEND.LIB, DEBUG.OBJ, PCBIOS.OBJ.

EMU.LIB znajduje się w bieżącym katalogu.

LINK.EXE i TLIB.EXE są osiągalne na ścieżce.

Poniższy BATCH nazywa się ECLP.BAT i jest osiągalny na ścieżce.

@ECHO OFF C:\CLP\CLIPPER %1 %2 IF ERRORLEVEL 1 GOTO END ECHO .
rem ————————- rem
rem Ta pozycja ukazuje linkowanie przy pomocy LINKa.
rem (LINK ma duże możliwości, ale jest wolniejszy od TLINKa)
rem link %1+c:\clp\debug+c:\clp\pcbios/noe/noi/se:512/e/far,,nul.map,c:\clp\clipper+c:\clp\extend+EMU.LIB
rem ————————-
rem
rem Ta pozycja ukazuje linkowanie przy pomocy TLINKa.
rem (TLINK jest bardzo szybki ale głupi – może zakłócać działanie
rem niektórych funkcji !) tlink %1+c:\clp\debug+c:\clp\pcbios,,,c:\clp\clipper+c:\clp\extend+EMU.LIB
/c rem ————————- :END IF EXIST %1.OBJ ERASE
%1.OBJ ECHO .

Jeżeli chcesz skompilować przy pomocy powyższega BATCHa program nazywający się ‚TEST.PRG’ to napisz ‚ECLP test <───┘’ (nazwa programu BEZ rozszerzenia).
*═══════════════════════════════════════════════════════*
DODATEK G.

Biblioteka.
Wraz z EMUlatorem są dostarczone zbiory ‚$EMU.C’ i ‚EMU.LIB’. ‚EMU.LIB’ zawiera funkcje, które po dołączeniu, do kompilowanego programu pozwolą wywoływać funkcje EMUlatora, jak i polskojęzyczne warianty niezbędnych funkcji CLIPPER’owskich, a ‚$EMU.C’ zawiera ich postać źródłową. Biblioteka ta nie ma charakteru ostatecznego – jest przykładem i propozycją dla użytkownika jak napisać własne funkcje.

EMU_CALL(ax, bx, cx, dx, si, di) EMU_DEF(font, znak, def_string)

ISEMU() PL_INIT() PL_UPPER() PL_LOWER() PL_MAP() PL_ORD()

FULL_CRS() – załączenie dużego kursora SET_CRS(top, bottom) – zalączenie kursora o podanych wymiarach

Opis EMU, wersja 3.0 tk.

Makefile:

DEBUG=0
MASM_PATH=$(_)/masm
#VERSION=-DTREND
#VERSION=-DCLIPPER
#------------------------------------------------#
#!if $(DEBUG)==1
#C_FLAGS= -AS -c
#D_FLAG= -Mx -Zi
#L_FLAGS= /CPAR:1/FAR/NOI/COD/MAP
#------------------------------------------------#
#!else
C_FLAGS= -AS -Oti -c
D_FLAG= -Mx
L_FLAGS= /CPAR:1/FAR/NOI
#------------------------------------------------#
#!endif
emu.exe: emu.obj a1_emu.obj a2_emu.obj gpkey.obj
link emu.obj+a1_emu.obj+a2_emu.obj+gpkey.obj $(L_FLAGS);
C:/TOOLS/COPYR emu.exe
#
demu.exe:
cl $(C_FLAGS) -DDEMO $(VERSION) emu.c
$(MASM_PATH)/masm $(D_FLAG) -DDEMO $(VERSION) -I$(MASM_PATH) gpkey.asm;
$(MASM_PATH)/masm $(D_FLAG) -DDEMO $(VERSION) -I$(MASM_PATH) a1_emu.asm;
$(MASM_PATH)/masm $(D_FLAG) -DDEMO $(VERSION) -I$(MASM_PATH) a2_emu.asm;
link emu.obj+a1_emu.obj+a2_emu.obj+gpkey.obj $(L_FLAGS), demu.exe;
C:/TOOLS/COPYR demu.exe
del *.obj
#
emu.obj: emu.c
cl $(C_FLAGS) $(VERSION) emu.c
gpkey.obj: gpkey.asm
$(MASM_PATH)/masm $(D_FLAG) $(VERSION) -I$(MASM_PATH) gpkey.asm;
a1_emu.obj: a1_emu.asm
$(MASM_PATH)/masm $(D_FLAG) $(VERSION) -I$(MASM_PATH) a1_emu.asm;
a2_emu.obj: a2_emu.asm
$(MASM_PATH)/masm $(D_FLAG) $(VERSION) -I$(MASM_PATH) a2_emu.asm;

Jeden z modułów:

NAME a1_emu
INCLUDE mixed.inc
.MODEL small
cLang=1
;
CHAR_HEIGHT EQU 14
FONT_SIZE EQU 256*CHAR_HEIGHT
;
;
OFFSET_SUM1 EQU 137;/* SECURITY */
OFFSET_SUM2 EQU 112;/* SECURITY */
OFFSET_KEY EQU 81;/* SECURITY */
USER_NAME_LENGTH EQU 76;/* SECURITY */
;
;
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
;------------------------------------------------------------------
EXTRN _crs_top:BYTE, _crs_bot:BYTE
EXTRN _crs_row:BYTE, _crs_col:BYTE
EXTRN _crs_on:BYTE

EXTRN _display_buffer:BYTE

EXTRN _font_tbl_norm:BYTE
EXTRN _font_tbl_pol:BYTE
EXTRN beg_rows:WORD
;
EXTRN _pol_tbl:BYTE;
EXTRN _eng_tbl:BYTE;
EXTRN _dia_tbl:BYTE;
EXTRN _map_char:BYTE, _map_dia:BYTE;
EXTRN _old_v_10:DWORD
EXTRN _old_v_17:DWORD
;
EXTRN _passwd:BYTE;/* SECURITY */
EXTRN _user_name:BYTE;/* SECURITY */
EXTRN _sum1:WORD;/* SECURITY */
;——————————————————————
_DATA ENDS
DGROUP GROUP _DATA

ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP

_TEXT SEGMENT
ASSUME CS: _TEXT
;——————————————————————
hProc , , reg_AX:WORD, reg_DX:WORD
;
mov AX, reg_AX
mov DX, reg_DX
pushf
CALL DWORD PTR _old_v_17
;
hRet
hEndp
;——————————————————————
; jeżeli znak jest polski, to zwraca !0 i (inaczej 0)
;wpisuje do map_char angielski odpowiednik,
;a do map_dia odpowiedni ogonek.
hProc , , char:BYTE
;
test char, 80h
jz no_map; polskie litery NA PEWNO >= 80h
;
mov AX, DS
mov ES, AX
;
mov AL, char
mov DI, OFFSET _pol_tbl
mov CX, 18
cld
repne scasb
je map_it
no_map:
sub AX, AX
jmp short end_map
;
map_it:
sub DI, OFFSET _pol_tbl + 1
mov AL, DS:[DI + OFFSET _eng_tbl]
mov _map_char, AL
;
mov AL, DS:[DI + OFFSET _dia_tbl]
mov _map_dia, AL
;
end_map:
hRet
hEndp
;——————————————————————
hProc ; AX != 0 dla HGC
;
int 11h
and AX, 0030h
cmp AX, 0030h
je is_mono
sub AX, AX
;
is_mono:
CALL _decode;/* SECURITY */
hRet
hEndp
;——————————————————————
; odczytuje pozycje kursora z biosa i wpisuje ją do zmiennych
hProc ,
;
mov AH, 03h
mov BH, 0
;
pushf
CALL DWORD PTR _old_v_10
;
mov _crs_row, DH
mov _crs_col, DL
;
hRet
hEndp
;——————————————————————
hProc ,
;
mov AH, 02h
mov BH, 0
;
mov DH, _crs_row
mov DL, _crs_col
;
pushf
CALL DWORD PTR _old_v_10
;
hRet
hEndp
;——————————————————————
hProc , , font:BYTE, char_no:BYTE, segm:WORD, offs:WORD
;
mov DI, OFFSET _font_tbl_norm
cmp font, 0
je lc_done
;
mov DI, OFFSET _font_tbl_pol
cmp font, 16
je lc_done
;
mov AX, 0ffffh
jmp short lc_quit
;
lc_done:
mov AX, CHAR_HEIGHT
mov BL, char_no
mul BL
add DI, AX ; DI wskazuje na znak w tablicy fontów
;
mov AX, CHAR_HEIGHT
push AX
push DI
push offs
push segm
CALL _from_far_cpy
add SP, 8
;
sub AX, AX
;
lc_quit:
;
hRet
hEndp
;——————————————————————
; kopiuje do EMU (DS:dst) z zewnątrz src_seg:src_off kount bajtów
hProc , , src_seg:WORD, src_off:WORD, dst_off:WORD, count:WORD
;
mov BX, dst_off
mov SI, src_seg
mov ES, SI
mov SI, src_off
;
mov CX, count
next_byte_cpy:
mov AL, BYTE PTR ES:[SI]
mov BYTE PTR [BX], AL
inc SI
inc BX
loop next_byte_cpy
;
hRet
hEndp
;——————————————————————
;——————————————————————
hProc , ;/* SECURITY */
;
mov DX, 0
mov BX, OFFSET _user_name
mov CX, USER_NAME_LENGTH
mov AH, DL
next_sum2:
mov AL, [BX]
add DX, AX
add BX, 1
loop next_sum2
;
mov AX, DX
;
hRet
hEndp
;——————————————————————
;——————————————————————
hProc ,
;
mov AX, 0b000h
mov ES, AX
mov DI, 0
MOV CX, 2000
mov AX, 0720h
cld
REP stosw
;
hRet
hEndp
;——————————————————————
hProc ,
;
mov AX, 0b800h
mov ES, AX
mov DI, 0
MOV CX, 4000h
mov AX, 0
cld
REP stosw
;
hRet
hEndp
;——————————————————————
; Scroll Window Up & Down
hProc , r_ax:WORD, r_bx:WORD, r_cx:WORD, r_dx:WORD
;
cli
mov AX, SP
push AX
sti
push BX
push CX
push DX
; push SP
push BP
push SI
push DI
;
mov AX, r_AX
mov BX, r_BX
mov CX, r_CX
mov DX, r_DX
;
pushf
CALL DWORD PTR _old_v_10
;
pop DI
pop SI
pop BP
; pop SP
pop DX
pop CX
pop BX
cli
pop AX
mov SP, AX
sti
;
hRet
hEndp
;——————————————————————
;——————————————————————
; Read Character and Attribute at Cursor
hProc ,
;
sub BH, BH
mov BL, _crs_col
shl BL, 1 ; BX = col*2
;
mov AL, 160
mov CL, _crs_row
mul CL ; AX = adres wiersza
;
add BX, AX ; BX = offset do ekranu
;
mov AX, 0b000h
mov DS, AX
;
mov AX, [BX]
; AH – attrib
; AL – ASCII
;
IFDEF DEMO ; Clear TRAP flag
push AX
pushf
pop AX
and AX, 0feffh
push AX
popf
pop AX
ENDIF
hRet
hEndp
;——————————————————————
; Write Character and Attribute at Cursor
hProc , , char:BYTE, attrib:BYTE, times:WORD
;
push SI
;
sub DH, DH
mov DL, _crs_col
mov BH, DL
shl DL, 1 ; DX = col*2
;
mov AL, 160
mov BL, _crs_row
mul BL ; AX = adres wiersza
;
add AX, DX
mov DI, AX ; DI = offset do ekranu
;
mov AX, 0b000h
mov ES, AX
;
mov AL, char ;
mov AH, attrib ;
mov SI, AX ; przechować, display_char niszczy AX
mov CX, times
;
cld
;
next_dsp_9:
mov AX, SI
stosw ; mov AX, ES:[DI], DI+=2
; AH – attrib
; AL – ASCII
;
push SI ; attrib + ASCII
mov DL, BH
push DX ; col
push BX ; row
CALL _display_char ;( BL, BH, AX)
add SP, 6
;
inc BH ; col++
cmp BH, 80
jb same_row_9
mov BH, 0 ; col=0;
inc BL ; row++
same_row_9:
LOOP next_dsp_9
;
pop SI
;
hRet
hEndp
;——————————————————————
;——————————————————————
hProc , ;/* SECURITY */
;
mov DX, [_sum1]
mov BX, OFFSET _user_name
mov AH, 0
mov CX, USER_NAME_LENGTH
next_sum1:
mov AL, [BX]
add DX, AX
inc BX
loop next_sum1
;
xchg AX, DX
;
hRet
hEndp
;——————————————————————
;——————————————————————
; Write Character at Cursor
hProc , , ascii:BYTE, times:WORD
;
sub DH, DH
mov DL, _crs_col
mov BH, DL
shl DL, 1 ; DX = col*2
;
mov AL, 160
mov BL, _crs_row
mul BL ; AX = adres wiersza
;
add AX, DX
mov DI, AX ; DI = offset do ekranu
;
mov AX, 0b000h
mov ES, AX
;
mov DL, ascii ; DL – ascii
mov CX, times
;
cld
;
next_dsp_a:
;
mov AX, ES:[DI] ; AH – attrib, AL – ASCII
mov AL, DL ; ascii do wypisanie
;
stosw ; mov AX, ES:[DI], DI+=2
;
push AX ; attrib + ASCII
mov AL, BH
push AX ; col
push BX ; row
CALL _display_char ;( BL, BH, AX)
add SP, 6
;
inc BH ; col++
cmp BH, 80
jb same_row_a
mov BH, 0 ; col=0;
inc BL ; row++
same_row_a:
LOOP next_dsp_a
;
hRet
hEndp
;——————————————————————
; Write Character in TTY Mode
hProc , , ascii:BYTE
hRet
hEndp
;——————————————————————
;——————————————————————
hProc , , src_addr:WORD, dst_addr:WORD, llength:WORD
;
mov AX, 0b000h
mov DS, AX
mov SI, src_addr
mov ES, AX
mov DI, dst_addr
;
mov CX, llength
cld
rep movsw
;
hRet
hEndp
;——————————————————————
hProc , , dst_addr:WORD, llength:WORD, filler:WORD
;
mov AX, 0b000h
mov ES, AX
mov DI, dst_addr
;
mov AX, filler
mov AL, ‚ ‚
mov CX, llength
cld
rep stosw
;
hRet
hEndp
;——————————————————————
;——————————————————————
; sumuje dla podanego fontu bajty drugiego jego znaku
; do sprawdzenia, czy font był zdefiniowany wewnątrz programu
; jeżeli nie (suma == 0): to program sam musi go zdefiniwać
hProc , , addr:WORD
;
mov SI, addr
add SI, CHAR_HEIGHT
;
sub BX, BX
cld
mov CX, 7
;
test_next:
lodsw
add BX, AX
loop test_next
;
mov AX, BX
;
hRet
hEndp
;——————————————————————
hProc
; BX – ascii+attrib
; CX – licznik znaków
; DX –
; ES:DI – b000 – text
;
sti
;
push ES
push DI
push BX
push CX
push DX
;
cld
;
mov AX, 0b000h
mov ES, AX
mov DI, 0
;
mov CX, 0
next_pair:
;
mov BX, ES:[DI]
inc DI
inc DI
mov AX, CX
mov DL, 80
div DL
; AH-col, AL, row
mov DL, AH ; col
push BX
push DX
push AX
CALL _display_char
add SP, 6
;
inc CX
cmp CX, 2000
jb next_pair
;
;
pop DX
pop CX
pop BX
pop DI
pop ES
;
hRet
hEndp
;——————————————————————
hProc
;DS:SI – tablica fontów
;DS:BX – tablica adresow poczatkow wierszy –> BP
;ES:DI – b800:, DI – col
; CL – row
;
push ES
push DI
push DS
push SI
push DX
push CX
push BX
push AX
push BP
;
;—————————————————>
;
; wpisac adres dla ekranu graficznego DI=CX==col
sub CH, CH
mov CL, _crs_col
; shl CL,1 ; *2
mov DI, CX
;
;—————————————————>
; obliczenie adresu znaku na ekranie
mov AX, 0b000h
mov ES, AX
;
mov AL, 160
mul _crs_row ; AX=row*160
;
mov BX, AX ; BX=row*160
add BX, CX ; BX= BX + col
add BX, CX
;
; wczytanie znaku z ekranu
mov BX, ES:[BX] ; asc, attr
;
mov AX, CHAR_HEIGHT
mul BL ; ascii
;
;—————————————————>
;
mov BL, BH ; kopia
and BL, 70h
cmp BL, 70h
je char_reversed
mov CL, 0ffh
jmp short cl_selected
char_reversed:
sub CL, CL ; CL==0 znak w rewersji ==> cursor normalny
cl_selected:
;
mov SI, OFFSET _font_tbl_norm
add SI, AX
;
;—————————————————>
; obliczyc poczatek tablicy adresow dla podanego wiersza
; BEGROWS ma po 2 bajty – WORD
mov AX, CHAR_HEIGHT*2
mov BL, _crs_row
mul BL
mov BP, OFFSET DS:beg_rows
add BP, AX
;
; mov BP, OFFSET DS:beg_rows
; mov AL, _crs_row
; add AL, AL
; sub AH, AH
; add BP, AX
;
;—————————————————>
;
; adres segmentu ekranu graficznego
mov DX, 0b800h
mov ES, DX
;
;—————————————————>
;
mov DH, _crs_top
mov DL, _crs_bot
;
;—————————————————>
cld
;—————————–*
;—————————–*
lodsb ; tablica fontów
mov BX, DS:[BP] ; beg rows
cmp DH, 0
ja no_crs_00
cmp DL, 0
jb no_crs_00
xor AL, CL ; CL==0 nic, CL=ff reversja
; not AL
no_crs_00:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 1
ja no_crs_01
cmp DL, 1
jb no_crs_01
xor AL, CL
no_crs_01:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 2
ja no_crs_02
cmp DL, 2
jb no_crs_02
xor AL, CL
no_crs_02:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 3
ja no_crs_03
cmp DL, 3
jb no_crs_03
xor AL, CL
no_crs_03:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 4
ja no_crs_04
cmp DL, 4
jb no_crs_04
xor AL, CL
no_crs_04:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 5
ja no_crs_05
cmp DL, 5
jb no_crs_05
xor AL, CL
no_crs_05:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 6
ja no_crs_06
cmp DL, 6
jb no_crs_06
xor AL, CL
no_crs_06:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 7
ja no_crs_07
cmp DL, 7
jb no_crs_07
xor AL, CL
no_crs_07:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 8
ja no_crs_08
cmp DL, 8
jb no_crs_08
xor AL, CL
no_crs_08:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 9
ja no_crs_09
cmp DL, 9
jb no_crs_09
xor AL, CL
no_crs_09:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 0ah
ja no_crs_0a
cmp DL, 0ah
jb no_crs_0a
xor AL, CL
no_crs_0a:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 0bh
ja no_crs_0b
cmp DL, 0bh
jb no_crs_0b
xor AL, CL
no_crs_0b:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 0ch
ja no_crs_0c
cmp DL, 0ch
jb no_crs_0c
xor AL, CL
no_crs_0c:
mov ES:[BX+DI], AL
inc BP
inc BP
;
;—————————–*
lodsb
mov BX, DS:[BP]
cmp DH, 0dh
ja no_crs_0d
cmp DL, 0dh
jb no_crs_0d
xor AL, CL
no_crs_0d:
mov ES:[BX+DI], AL
; inc BP
; inc BP
;—————————–*
;
pop BP
pop AX
pop BX
pop CX
pop DX
pop SI
pop DS
pop DI
pop ES
;
hRet
hEndp
;——————————————————————
hProc ,
;ES:DI – b000:, DI – col
;
mov AX, 0b000h
mov ES, AX
;
sub BH, BH
mov BL, _crs_col
shl BL, 1 ; BX = col*2
;
mov AL, 160
mov DL, _crs_row
mul DL ; AX = adres wiersza
;
add BX, AX
;
mov AX, ES:[BX]
; AH – attrib
; AL – ASCII
;
push AX ; attrib + ASCII
mov AL, _crs_col
push AX ; col
mov AL, _crs_row
push AX
CALL _display_char ;( BL, BH, AX)
add SP, 6
;
hRet
hEndp
;——————————————————————
;——————————————————————
hProc , , row:BYTE, col:BYTE
;ES:BX – b000:
;
;
;—————————————————>
;
; wpisac adres dla ekranu graficznego CX==col
sub CH, CH
mov CL, col
;
;—————————————————>
; obliczenie adresu znaku na ekranie
mov AX, 0b000h
mov ES, AX
;
mov AL, 160
mul row ; AX=row*160
;
mov BX, AX ; BX=row*160
add BX, CX ; BX= BX + col
add BX, CX
;
; wczytanie znaku z ekranu
mov AX, ES:[BX] ; attr, asc
;
hRet
hEndp
;——————————————————————
;——————————————————————
hProc , ;/* SECURITY */
;
mov CX, (USER_NAME_LENGTH/2)
mov DX, WORD PTR [_passwd+OFFSET_KEY] ; kod dekodowania
mov BX, OFFSET _user_name
;
next_decode:
mov AX, [BX]
xor AX, DX
mov [BX], AX
inc BX
inc BX
loop next_decode
;
hRet
hEndp
;——————————————————————
;——————————————————————
;——————————————————————
hProc , , row:BYTE, col:BYTE, ascii:WORD
;DS:SI – tablica fontów
;ES:DI – b800:, DI – col
; CL – row
;
cld
;
mov AX, DS
mov ES, AX
;
; kopiowanie znaku do display_buffer
mov BX, ascii
mov DI, OFFSET _display_buffer
mov SI, OFFSET _font_tbl_norm
;
;
mov AX, CHAR_HEIGHT
mul BL ; ascii
add SI, AX
mov CX, CHAR_HEIGHT/2 ; kopiowanie słowami
rep movsw
;
mov CH, BH ; kopia do sprawdzeń – BX jest do czego innego
;
mov SI, OFFSET _display_buffer
;————————————-*
; test CH, 88h
; jz not_blink_bold
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; mov BX, SI
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
;****************
test CH, 08h
jz not__bold
;**BOLD
mov BX, SI
;0
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;1
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;2
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;3
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;4
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;5
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;6
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
inc BX
inc BX
;7
mov AX, [BX]
shr AH, 1
shr AL, 1
or [BX], AX
; inc BX
; inc BX
;**
not__bold: ;======================
test CH, 80h
jz not__blink
mov BX, SI
;**BLINK
IFNDEF CLIPPER
;0
mov AX, [BX]
mov CL, 3
shr AL, CL
mov CL, 2
shr AH, CL
mov [BX], AX
inc BX
inc BX
;1
mov AX, [BX]
mov CL, 2
shr AL, CL
mov CL, 1
shr AH, CL
mov [BX], AX
inc BX
inc BX
;2
mov AX, [BX]
mov CL, 1
shr AL, CL
mov CL, 0
shr AH, CL
mov [BX], AX
inc BX
inc BX
;3
inc BX
inc BX
;4
mov AX, [BX]
mov CL, 0
shl AL, CL
mov CL, 1
shl AH, CL
mov [BX], AX
inc BX
inc BX
;5
mov AX, [BX]
mov CL, 1
shl AL, CL
mov CL, 2
shl AH, CL
mov [BX], AX
inc BX
inc BX
;6
; mov AX, [BX]
mov AX, [BX]
mov CL, 2
shl AL, CL
mov CL, 3
shl AH, CL
mov [BX], AX
; inc BX
; inc BX
;
ELSE
; Clipper – specjalne
mov AX, [SI]
not AX
mov [SI], AX
;
mov AX, [SI+12]
not AX
mov [SI+12], AX
; gdy ENH, to nie underl
jmp short not_underl
;
ENDIF
;**
not__blink: ;======================

;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
;not_blink_bold:
;————————————-*
mov CL, CH ; odtworzenie atrybutów
and CL, 77h
cmp CL, 01h ; underl
jne not_underl
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; UNDERL
;6
mov AL, [SI+13]
not AL
mov [SI+13], AL
;
not_underl:
;————————————-*
mov CL, CH ; odtworzenie atrybutów
and CL, 77h
cmp CL, 70h
jne not_reversed
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
mov BX, SI
; REVERSE
;0
mov AX, [BX]
not AX
mov [BX], AX
inc BX
inc BX
;1
mov AX, [BX]
not AX
mov [BX], AX
inc BX
inc BX
;2
mov AX, [BX]
not AX
mov [BX], AX
inc BX
inc BX
;3
mov AX, [BX]
not AX
mov [BX], AX
inc BX
inc BX
;4
mov AX, [BX]
not AX
mov [BX], AX
inc BX
inc BX
;5
mov AX, [BX]
not AX
mov [BX], AX
inc BX
inc BX
;6
mov AX, [BX]
not AX
mov [BX], AX
; inc BX
; inc BX
;——————————–*
not_reversed:
test CH, 77h
jnz not_blank
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
mov BX, SI
; BLANK
sub AX, AX
;0
mov [BX], AX
inc BX
inc BX
;1
mov [BX], AX
inc BX
inc BX
;2
mov [BX], AX
inc BX
inc BX
;3
mov [BX], AX
inc BX
inc BX
;4
mov [BX], AX
inc BX
inc BX
;5
mov [BX], AX
inc BX
inc BX
;6
mov [BX], AX
; inc BX
; inc BX
not_blank:
;————————————-*
; ładowanie rejestru ES:DI
mov CL, row
mov AL, col
cbw
mov DI, AX
;
mov AX, 0b800h
mov ES, AX
;————————————-*
;
mov DX, 2000h ; dla przyśpieszenia wykonania
;
; DS:SI — display_buffer
;
;
row_0:
cmp CL, 0
jne row_1
mov BX, 0000h
jmp display_even
row_1:
cmp CL, 1
jne row_2
mov BX, 40f0h
jmp display_odd
row_2:
cmp CL, 2
jne row_3
mov BX, 0230h
jmp display_even
row_3:
cmp CL, 3
jne row_4
mov BX, 4320h
jmp display_odd
row_4:
cmp CL, 4
jne row_5
mov BX, 0460h
jmp display_even
row_5:
cmp CL, 5
jne row_6
mov BX, 4550h
jmp display_odd
row_6:
cmp CL, 6
jne row_7
mov BX, 0690h
jmp display_even
row_7:
cmp CL, 7
jne row_8
mov BX, 4780h
jmp display_odd
row_8:
cmp CL, 8
jne row_9
mov BX, 08c0h
jmp display_even
row_9:
cmp CL, 9
jne row_10
mov BX, 49b0h
jmp display_odd
row_10:
cmp CL, 10
jne row_11
mov BX, 0af0h
jmp display_even
row_11:
cmp CL, 11
jne row_12
mov BX, 4be0h
jmp display_odd
row_12:
cmp CL, 12
jne row_13
mov BX, 0d20h
jmp display_even
row_13:
cmp CL, 13
jne row_14
mov BX, 4e10h
jmp display_odd
row_14:
cmp CL, 14
jne row_15
mov BX, 0f50h
jmp display_even
row_15:
cmp CL, 15
jne row_16
mov BX, 5040h
jmp display_odd
row_16:
cmp CL, 16
jne row_17
mov BX, 1180h
jmp display_even
row_17:
cmp CL, 17
jne row_18
mov BX, 5270h
jmp display_odd
row_18:
cmp CL, 18
jne row_19
mov BX, 13b0h
jmp display_even
row_19:
cmp CL, 19
jne row_20
mov BX, 54a0h
jmp display_odd
row_20:
cmp CL, 20
jne row_21
mov BX, 15e0h
jmp display_even
row_21:
cmp CL, 21
jne row_22
mov BX, 56d0h
jmp display_odd
row_22:
cmp CL, 22
jne row_23
mov BX, 1810h
jmp display_even
row_23:
cmp CL, 23
jne row_24
mov BX, 5900h
jmp display_odd
row_24:
cmp CL, 24
jne row_25
mov BX, 1a40h
jmp display_even
row_25:
hRet
;=================================================================
; DI – col
; BX – współczynnik
; CX – 7fffh – dla przyśpieszenia wykonania
;=================================================================
display_even:
;
mov CX, 7fffh
;
lodsb ; [0]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [1]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [2]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [3]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [4]
add BX, 50h ;++
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [5]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [6]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [7]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [8]
add BX, 50h ;++
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [9]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [10]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [11]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [12]
add BX, 50h ;++
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [13]
mov ES:[BX+DI], AL
; add BX, DX
; and BX, CX
hRet
;=================================================================
display_odd:
;
mov CX, 7fffh
;
lodsb ; [0]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [1]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [2]
add BX, 50h ;++
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [3]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [4]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [5]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [6]
add BX, 50h ;++
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [7]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [8]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [9]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [10]
add BX, 50h ;++
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [11]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [12]
mov ES:[BX+DI], AL
add BX, DX
and BX, CX
;
lodsb ; [13]
mov ES:[BX+DI], AL
; add BX, DX
; and BX, CX
hRet
;=================================================================
;
hRet
hEndp
;——————————————————————
hProc , , chr:BYTE
;
mov AH, 0Eh
mov AL, chr
mov BX, 0007h
INT 10h
;
hRet
hEndp
;——————————————————————
hProc , , cp:WORD
;
mov BX, WORD PTR cp
jmp SHORT fp_begin
fp_loop:
; INT 29h
push AX
CALL _fast_putchar
pop AX
fp_begin:
mov AL, BYTE PTR [BX]
inc BX
or AL, AL
jnz fp_loop
;
hRet
hEndp
;——————————————————————
; bajt b przekształca do postaci dziesiętnej, i wyświetla
hProc , , b:BYTE
;
sub AH, AH
mov AL, b
sub CX, CX ; licznik znaków
mov BX, 10 ; dzielnik
;
bt_getdigit:
sub DX, DX
div BX ; Remainder is last digit
add DL, ‚0’ ; to ASCII
push DX ; cyfra na stos
inc CX
or AX, AX ; czy już nic nie zostało
jnz bt_getdigit
;
; CL – ilość cyfr
;
bt_putdigit:
CALL _fast_putchar
pop AX ; cyfra ze stosu
; INT 29h
inc BX
loop bt_putdigit
;
hRet
hEndp
;——————————————————————
;——————————————————————
;═══════════════════════════════════════════════════════════════════════
;==================================================================

END

Reklamy
Opublikowano Komputery i Internet | Otagowano , , , , | Dodaj komentarz

Prosty i tani wzmacniaczyk klasy D (YL2020)

Stwierdziłem, że przydał by mi się mały wzmacniacz, służący do okazyjnego słuchania muzyki z komputera.

Po zrobieniu remanentu okazało się, że mam:

  • J-042 (przedwzmacniacz, układ TDA1524A),
  • AVT2489 (wzmacniacz 2×25W, układ TDA8563Q),
  • transformator TST 20/003 (220V/12V 1,67A),
  • rozmaite drobiazgi, jak spory mostek i kondensatory elektrolityczne,
  • tudzież uniwersalne obudowy, w różnym stanie.

 Zasilacz dostał jakiś nieco większy mostek i kondensatory 2×4700µF/25V. Napięcie wyjściowe to ≈20V.

Przedwzmacniacz wymagał nowych potencjometrów, o dłuższych ośkach. Zamiast potencjometru balansu zastosowałem helltrim, przylepiony glutem do płytki. Trymery na wyjściu zostały pominięte, gdyby obniżenie poziomu było potrzebne, lepiej by było zrobić to na wejściu wzmacniacza mocy. Układ został zasilony z 7812.

Stopień mocy niestety się nie sprawdził, charczał jeden kanał – zapewne skutek zbyt wysokiego napięcia zasilania. Powstało pytanie: co dalej? Niepewna w skutkach wymiana IC na inny, czy poszukanie czegoś innego – taniego i o odpowiedniej mocy.

Szukać zacząłem na DX, tam znalazłem YL2020 – przeznaczony do telewizorów, o doskonale pasujących parametrach: moc 20W+20W (szczytowo 35W+35W), zasilanie 12V÷24V, obciążenie 4÷8Ω, zbudowany na układzie TPA3100D2. Kupiłem na Aliexpressie ($6.50 brutto, STIME Electronics Technology Co., Ltd). Układ TPA3100D2 posiada zabezpieczenie zwarciowe i cieplne (to drugie nie jest sygnalizowane przez FAULT), i – niestety w tej aplikacji niewykorzystaną – możliwość ustawiania wzmocnienia.

 

Układ, jak widać, to mała płytka, wygodna do zamontowania, z wyprowadzeniami opisanymi i wygodnymi do lutowania. Trzeba tylko przylutować wszystko tam, gdzie należy.

Jeżeli nie korzysta się z MUTE, to należy połączyć ze sobą FAULT i MUTE – spowoduje to wyciszanie wzmacniacza przy błędach.

Aby włączyć MUTE trzeba go podłączyć do dodatniego napięcia zasilania VCC (Wystarczy mniejsze, ale tak jest najprościej).

Wejście SD to !SHUTDOWN, nie trzeba podłączać, nie należy go też wykorzystywać jako Mute, bo użycie go powoduje łomoty w głośnikach.

Przy uruchomieniu jedyną niespodzianką był brak napięcia na jednym z wyjść głośnikowych, wzmacniacz normalnie tam utrzymuje ~½ VCC. Śledzenie doprowadziło do elementu w czerwonym kółku (zapewne dławik), przyciśnięcie go lutownicą rozwiązało problem.

 

 pa-03-of

Jeżeli do wzmacniacza dołącza się głośnik bezpośrednio, krótkimi przewodami, to jego własne filtry wyjściowe są wystarczające. Jeżeli chce się go dołączyć do bardziej odległych kolumn, to trzeba na wyjściu dać filtry dolnoprzepustowe; z jednej strony – by harmoniczne o sporych mocach nie szły w eter, z drugiej – by indukowane w kablach śmieci nie szły do wzmacniacza.

W dokumentacji podane są przykłady, jak taki filtr powinien być zrobiony, dosyć różne dla obciążenia 4Ω i 8Ω. Uznałem, że nie ma się tym co specjalnie przejmować, bo: na kolumnach pisze tylko że pasują do wzmacniaczy 4Ω i 8Ω, a że mają zwrotnice – to przy pytaniu o impedancję należy podawać częstotliwość.

Kluczem są w filtrach indukcyjności: w oryginale są to ekranowane magnetycznie Toko A7503AY-330M (33 μH ±20%, Idc =2,3A, Rdc =115mΩ). Przy szukaniu zamienników należy dbać, by prąd Idc zamienników nie był mniejszy. Ja znalazłem na Allegro tanią ofertę dławików 15 μH, o nieco większym prądzie; opłacalną cenowo przy łączeniu dławików w szereg. Kondensatory w filtrach są ceramiczne, na 50V, oryginalnie to ceramika X7R; dobierałem je tak, by pojemności w obydwu kanałach były podobne.

 

 pa-04-logika

Ponieważ front wzmacniacz miał mieć ładniejszy, dostał 10mm niebieską LEDę jako wskaźnik załączenia, małą czerwoną jako sygnalizator FAIL, oraz duży (niepasujący do nich 😉 ) zielony podświetlany przycisk do MUTE. Logikę zrobiłem na poczwórnym wzmacniaczu operacyjnym TL084, zastosowane tam diody to złącza BC tranzystorów BC337.

Kondensator opóźnienia załączania 22µF okazał się być zbyt mały, teraz jest 470µF (za duży), pewnie 220µF by wystarczyło; ale taki był pod ręką.

Najpoważniejszym zadaniem było takie dobranie oporników do LEDów, by te świeciły – ale nie oświetlały. W sumie – można było dać większe…

Układ nie zapewnia całkowitego wytłumienia dudnienia powstającego przy załączeniu, aby to uzyskać niezbędny by był normalnie zwarty przekaźnik, rozłączany z opóźnieniem, ale to co jest – jest wystarczające.

 

 pa-05-front

 pa-07-back

Obudową jest stara, używana, obudowa uniwersalna (z piwnicy), otwory trzeba było dopasować do już istniejących, wymienić śrubki i pomalować czarnym, błyszczącym lakierem w spreyu.

Układy zostały wykonane na płytkach uniwersalnych, kynarem.

 

 

Wnioski (subiektywne): nie było drogo, gra dobrze, potrafi być zbyt głośny, gdy nie ma muzyki słyszalny jest szum, ale cóż – TDA1524A tak ma.

W każdym razie: Dark Side of the Moon słucha się na tym całkiem dobrze.

 

 pa-06-top

Na obrazku wnętrzności: na przodzie przedwzmacniacz, osłaniająca go blacha aluminiowa to ekran i jednocześnie radiator 7812; na środkowej listwie zasilanie i logika, wejścia i wyjścia podłączone są wtykami; na tylnej ścianie wzmacniacz mocy i filtr wyjściowy.

Kawałek czerwonej taśmy przypomina, który kanał jest lewy.

Obrazka z zamkniętą obudową nie daję, bo blachy okazały się być nieco krzywe, ale, po pomalowaniu, nie wyglądają źle.

 

Przy budowie bardzo się przydał nieodległy sklep elektroniczny Tele-Elektronik Będzin Jasna 6, malutki, ale zaskakująco dobrze zaopatrzony.

Uwaga końcowa: Przylepiłem do IS kawałek radiatora, bo chyba załączało mi się ograniczenie cieplne.

Tekst został opublikowany na Elektrodzie: Elektrodzie

Opublikowano Elektronika | Otagowano , | Dodaj komentarz

Stycznik do czujnika ruchu

Zrobiłem lampę do przedpokoju:
– klosz matowy (z poprzednich wpisów wiadomo dlaczego),
– czujnik ruchu mikrofalowy (żeby mógł być wewnątrz obudowy),
– 2 moduły LED 10W (żeby przy awarii nie trzeba się był śpieszyć).
Czujnik był wygodny, z czterema wyprowadzeniami, przeznaczony do obsługi oświetlenia LED (czytaj: przetwornicy z prostownikiem i kondensatorem). Działało to bardzo ładnie, wykrywając także obecność osoby za drewnianym drzwiami ;), aż przestało gasnąć. Słychać było, że przekaźnik wykonawczy próbuje działać, najwyraźniej styki się skleiły.
Więc rozbiórka, przekaźnik, według dokumentacji, przeznaczony na obciążenia czysto rezystancyjne, więc co się dziwić… Zamiennik na Allegro był (RM50-3011-85-1009; ecoelektryk), wymiana szczęśliwie się udała (szczęśliwie, bo płytka wielowarstwowa…), ale co z przyszłością?
Postanowiłem dołożyć dodatkowy pośredniczący przekaźnik, na 230V (RM84-2012-35-5230, czerwonybonzaj), na wszelki wypadek w podstawce.

Schemat montażowy 😉

 

Wszystko zostało zlutowane na kawałku płytki uniwersalnej, miedź między kontaktami została zeszlifowana, całość została pokryta glutem dla izolacji i zabezpieczenia.

A tak to wygląda od podstawki.

 

 

Sama lampa: na samym dole czujnik mikrofalowy, wyżej dwa radiatory LED, na szczycie pionowo dwa zasilacze LED, między nimi, przekaźnikiem w dół stycznik. (Widoczne czerwone ślady to krew 🙂 )

Opublikowano Elektronika | Otagowano , , | Dodaj komentarz

ReplayGain w praktyce

Od dosyć dawna zbieram stare wideoklipy z ulubioną muzyką; źródła są różne: YT, samodzielne konwersje, i inne takie.

Zestandaryzowałem je, ujednolicając nazwy i konwertując format na MKV. Zrobiłem wyspecjalizowane odtwarzacze do ich grania; jeden wykorzystuje VLC, drugi MediaElement.

(Jak ktoś ciekaw, to można to jeszcze obejrzeć tu)

Mam utworzone różne kolekcje i zestawienia klipów do oglądania i słuchania. Ale – jest problem. Poziom głośności bywa dla poszczególnych klipów bardzo różny, co uniewygodnia przyjemność, zmuszając do czuwania przy gałce wzmacniacza.
Rozwiązaniem jest wykorzystanie przy odtwarzaniu informacji ReplayGain z odtwarzanego pliku do korygowania głośności. Ale, po pierwsze, ReplayGain w moich plikach nie ma…

Więc, jak dodać ReplayGain do videoklipu w formacie MKV?
Proste – Foobar2000 to zrobi 🙂

rgfoobar1

rgfoobar2

A teraz pytanie – jak to odczytać w programie?
Dodawać obcej biblioteki nie chciałem, samodzielne parsowanie struktury pliku Matroska nie wyglądało zachęcająco – sporo pracy dla jednej informacji…
Więc – brute force; wczytanie 1500 B od końca pliku i szukanie tam ciągu znaków. Potem okazało się, że w niewielu przypadkach ReplayGain występuje na początku pliku; więc tam ewentualnie też.

 

Teraz odtwarzanie: player wykorzystujący VLC ma zakres regulacji głośności to 0…200 (lepiej), MediaElement ma zakres 0.0…1.0.
Wyrażenia przeliczające ReplayGain na wzmocnienie są proste – zwykłe mnożenie przez współczynnik.
(Możliwe, że nie powinno być tak prosto, ale nie mam żadnej koncepcji jak powinno się to liczyć…)

Współczynnik trzeba było dobrać empirycznie, teraz dla VLC=5.0, dla MediaElement=0.05.
Na słuch sprawuje się to całkiem dobrze 🙂

 

Wyliczenie wzmocnienia dla podanego ReplayGain, dla MediaElement:


     // stałe z VLC podzielone przez 200
        public static double DefaultLevel
        {
            get { return 0.5; }
        }
        //
        public static double MaxLevel
        {
            get { return 1.0; }
        }
        //
        public static double MinLevel
        {
            get { return 0.1; }
        }
        //
        private static double rgc = 1.0;
        public static double ReplayGainCoefficient
        {
            get { return rgc; }
            set { rgc = value; }
        }
        //
        public static double CalculateLevelAndReplayGain(double replayGain)
        {
            return Math.Min(Math.Max(MinLevel, DefaultLevel + (rgc * replayGain)), MaxLevel);
        }

A tak wygląda szukanie w pliku:


  public class ReplayGain
    {
        //
        //
        //REPLAYGAIN_GAIND‡€
        private static byte [] RG = { 0x52, 0x45, 0x50, 0x4C, 0x41, 0x59, 0x47, 0x41, 0x49, 0x4E, 0x5F, 0x47, 0x41, 0x49, 0x4E, 0x44, 0x87, 0x88 };
        // Uwaga: ostatnie dwa bajty bywają różne

        //REPLAYGAIN_PEAKD‡€
        private static byte[] RP = { 0x52, 0x45, 0x50, 0x4C, 0x41, 0x59, 0x47, 0x41, 0x49, 0x4E, 0x5F, 0x50, 0x45, 0x41, 0x4B, 0x44, 0x87, 0x88 };


        private static bool findGainInBuffer(byte[] bb, out double gainValue)
        {
            bool gainFound = false;
            //
            bool tagFound = false;
            int tagBegin = 0;
            for (int n = 0; n < (bb.Length - RG.Length); n++)
            {
                    if (RG[0] == bb[n + 0] && RG[1] == bb[n + 1] && RG[2] == bb[n + 2] && RG[3] == bb[n + 3] && RG[4] == bb[n + 4] && RG[5] == bb[n + 5] && RG[6] == bb[n + 6] && RG[7] == bb[n + 7] && RG[8] == bb[n + 8] && RG[9] == bb[n + 9] && RG[10] == bb[n + 10] && RG[11] == bb[n + 11] && RG[12] == bb[n + 12] && RG[13] == bb[n + 13] && RG[14] == bb[n + 14] && RG[15] == bb[n + 15] && RG[16] == bb[n + 16])
                {
                    tagFound = true;
                    tagBegin = n;
                    break;

                }
            }
            //
            if (!tagFound)
            {
                gainValue = 0.0;
                return false;
            }
            //
            //
            int gainBegin = tagBegin + RG.Length;
            string gainValueString = "";
            gainValue = 0.0;
            //
            for (int j = gainBegin; j < bb.Length - RG.Length; j++)
            {
                char c = (char)bb[j];
                if (char.IsDigit(c) || '-' == c || '+' == c || '.' == c)
                {
                    gainValueString += c;
                }
                else
                {
                    gainValue = double.Parse(gainValueString, System.Globalization.CultureInfo.InvariantCulture);
                    gainFound = true;
                    break;
                }
            }
            //
            return gainFound;
        }
        //

Opublikowano Komputery i Internet, Uncategorized | Otagowano , , , , , | Dodaj komentarz

Jak zrobić klip video z nagrania audio

Jak zrobić? (Dlaczego? Miałem ściągnięte z YT ‘First Last and Always’ o nader nędznej jakości, chciałem lepsze.)
Czyli – jak połączyć obrazek ze ścieżką dźwiękową? Są do tego programy, niektóre nawet płatne  🙂
Ale najłatwiej to zrobić używając ffmpeg.
A tutaj batch, który to robi:
– wybiera ostatni obrazek w katalogu,
– konwertuje wszystkie pliki audio w katalogu.
Ciekawostką jest to, że jeżeli obrazek jest w formacie PNG to Filmy i TV go nie wyświetlają 🙂

@ECHO OFF
SET EXE="C:\Apps\Bin\ffmpeg.Exe"
SET EXT=mp3
Rem ---
FOR %%a IN (*.jpg) DO SET PIC=%%~dpnxa
Rem ---
IF DEFINED PIC (
ECHO %PIC%
) ELSE (
ECHO *** Image file not found ***
EXIT /B 1
)
Rem ---
FOR %%a IN (*.%EXT%) DO (
%EXE% -hide_banner -loop 1 -i "%PIC%" -i "%%~pa%%~na.%EXT%" -acodec copy -vcodec libx264 -tune stillimage -shortest "%%~pa%%~na.mkv"
)
Rem ---

Do katalogu ze ścieżkami audio kopiujemy obrazek i uruchamiamy batch. Po nieco dłuższej chwili dostajemy wynikowe pliki MKV.

Uwaga konfiguracyjna – tu trzeba wpisać, to co ma się u siebie:

SET EXE="C:\Apps\Bin\ffmpeg.Exe"
SET EXT=mp3
Opublikowano Komputery i Internet | Otagowano , , , | Dodaj komentarz

Wypadek w Czarnobylu: lekcja dla energetyki jądrowej

Wypadek w Czarnobylu: lekcja dla energetyki jądrowej

Zbigniew Jaworowski

profesor doktor habilitowany, Instytut Fizyki, Uniwersytet w Oslo, Norwegia

 (Tekst ze starych „Problemów” (1/1989), szkoda by zniknął)

 

Wchodzimy obecnie w okres, w którym bardziej niż kiedykolwiek w historii wielkoskalowe zmiany w środowisku zaczynają wpływać na politykę rozwoju przemysłu i produkcji energii. Społeczeństwo, które w końcu o wszystkim zdecyduje (miejmy nadzieję, że nie grupy interesu takie jak np. kompleksy przemysłowo-wojskowe, lobby naftowe, węglowe czy atomowe) powinno mieć jasny pogląd na ryzyko związane z różnymi formami produkcji energii. A jaka będzie energetyka, taka będzie przyszłość, gdyż źródła energii są siłą napędową cywilizacji. W tym artykule chcę przedstawić najnowsze oceny naukowe zagrożenia populacji ze strony energetyki jądrowej, przede wszystkim w świetle wypadku w Czarnobylu.

Według oceny Komitetu Naukowego Narodów Zjednoczonych ds. Skutków Promieniowania Atomowego (UNSCEAR), który jest najwyższym w świecie autorytetem w dziedzinie badań nad narażeniem radiacyjnym, normalna praca elektrowni jądrowych i pozostałej części nuklearnego cyklu paliwowego praktycznie nie powoduje narażenia ludności i tylko znikome skażenia środowiska. Z tego powodu należy uznać tę formę produkcji energii za najkorzystniejszą z punktu widzenia ochrony zdrowia ludzi, ekosystemów lokalnych i całej biosfery.

Przeciętny mieszkaniec Ziemi otrzymuje obecnie od całego światowego nuklearnego cyklu paliwowego, poczynając od wydobycia uranu i kończąc na składaniu odpadów, roczną dawkę promieniowania jonizującego wynoszącą 0,27 µSw (tabela 1), tzn. około 0,0001 średniej dawki naturalnej wynoszącej 2400 µSv rocznie. Ta naturalna dawka w niektórych rejonach osiąga stukrotnie wyższe wartości (UNSCEAR, 1988).

Obecnie około 15% energii elektrycznej na świecie wytwarza się w elektrowniach jądrowych. Gdyby cała światowa energia elektryczna była produkowana tylko przez elektrownie jądrowe, to roczna dawka promieniowania otrzymana przez przeciętnego mieszkańca planety wynosiłaby 1,8 µSv. Tak znikoma dawka nie mogłaby spowodować żadnych wykrywalnych zmian zdrowotnych w społeczeństwie.

Natomiast łatwo można sobie wyobrazić, jakie korzystne skutki przyniosłaby całkowita eliminacja elektrowni węglowych, a także innych źródeł energii opartych na paliwach kopalnych. W Polsce byłaby to likwidacja emisji 1,8 mln ton pyłów, 2,8 mln ton dwutlenku siarki („Rocznik Statystyczny”, 1987) i 300 mln ton CO2 rocznie. Oznaczałoby to usunięcie przyczyny co najmniej kilku tysięcy zgonów rocznie, powodowanych w Polsce przez pyły i tlenki siarki z elektrowni węglowych, usunięcie jednej z głównych przyczyn wymierania lasów w Europie Środkowej, ginięcia ryb w jeziorach oligotroficznych, ą w skali biosfery – usunięcie głównej przyczyny efektu cieplarnianego i groźby planetarnych zmian klimatu, wiodących do całkowitego stopienia lodowców, podwyższenia poziomu oceanów o około 80 m i niekorzystnych zmian geografii upraw rolnych.

Jak bliska jest ta groźba – świadczy apel rządów świata, wystosowany przez uczestników międzynarodowej konferencji „The Changing Global Environment – Implications for Global Security” w Toronto w 1988 r., o zmniejszenie o 20% emisji CO2 ze spalania paliw kopalnianych. W apelu tym stwierdzono, że „ludzkość przeprowadza obecnie niezamierzony eksperyment, od którego końcowych skutków może być gorsza tylko wojna jądrowa”. W wyniku podgrzania atmosfery o 1,5 do 4,5°C już około 2050 r. poziom oceanów podniesie się o około 1,5 m i dramatycznie zwiększy się częstość cyklonów („New Scientist”, 1988). Zapobiegnięcie tej katastrofie, bez rezygnacji z obecnego poziomu życia i perspektyw dalszego rozwoju ludzkości, jest możliwe wyłącznie przez całkowite przejście na energetykę jądrową, łącznie z wtórnym jej stosowaniem do środków transportu (poprzez napęd elektryczny i wodorowy).

Rozważmy jednak, jak przedstawia się sprawa w przypadku wielkich awarii elektrowni jądrowych, które – zgodnie z teoretycznymi przewidywaniami – mogłyby prowadzić do poważnych strat wśród ludności. Wypadek czarnobylski umożliwił – niestety – sprawdzenie tych przewidywań. Ponieważ była to prawdopodobnie największa z możliwych katastrof elektrowni jądrowych (nic gorszego poza pewnym nasileniem sytuacji radiacyjnej przy gorszych warunkach meteorologicznych i przy przedłużeniu emisji radionuklidów nie można sobie wyobrazić), stała się ona kamieniem milowym w historii energetyki. Przez następne dziesięciolecia będzie ona obiektem badań i każda poważna dyskusja nad energetyką jądrową będzie musiała uwzględniać ich wyniki.

Historyczny wymiar tej katastrofy, w której zginęło 29 ratowników i 2 osoby z obsługi reaktora, wynika m.in. z dwóch powodów:

1)      dysproporcji między ogromem technicznym wypadku i stratami ekonomicznymi (12,5 miliarda dolarów w ZSRR), a całkowitym brakiem strat wśród ludności,

2)      lękiem wywołanym na całej Półkuli Północnej, prawdopodobnie największym jaki zdarzył się w  okresie pokoju w czasach historycznych, zupełnie nie uzasadnionym rzeczywistym zagrożeniem.

W artykule tym przedstawię ocenę skutków katastrofy czarnobylskiej – głównie na podstawie raportów radzieckich oraz raportu UNSCEAR z 1988 r. przygotowanego dla Zgromadzenia Ogólnego Narodów Zjednoczonych. Raport UNSCEAR oparty jest na szczegółowych danych dostarczonych Komitetowi przez 34 kraje. Jest on najpełniejszym z dotychczasowych opracowań, dotyczących oceny zagrożenia radiacyjnego ludności Półkuli Północnej, wywołanego wypadkiem czarnobylskim.

 

Emisja radionuklidów

 

Awaryjny wzrost mocy reaktora nr 4 w elektrowni czarnobylskiej spowodował eksplozję pary wodnej i prawdopodobnie również wodoru uwolnionego z reakcji pary z cyrkonem zawartym w rdzeniu reaktora (142 tony) z grafitem (2500 ton)[1]. Eksplozja spowodowała rozszczelnienie reaktora oraz natychmiastową emisję radionuklidów w formie gazowej i aerozoli, a także w formie drobnych kropli stopionego paliwa (o średnicy do 0,6 mm) oraz cząstek stałych paliwa rozkruszonego podczas gwałtownych zmian temperatury (o średnicy do 10 mm). Te większe cząstki osadziły się w pobliżu reaktora.

Rozszczelnienie reaktora umożliwiło dostęp tlenu do grafitu, którego pożar podtrzymywał przez 10 dni gwałtowną emisję radionuklidów do atmosfery. W tym czasie spaliło się tylko 10% grafitu i uwolniła się tylko część lotnych radionuklidów. Pożar grafitu ugaszono dzięki wręcz bohaterskiej akcji ratowniczej, podczas której zrzucono na reaktor około 5000 ton dolomitu, piasku, gliny, boru i ołowiu.

Gdyby nie ugaszono pożaru, emisja radionuklidów trwałaby dalej, może nawet przez kilka miesięcy, prowadząc do znacznie silniejszych skażeń rejonu Czarnobyla i dalszych okolic. Dziennie spalało się około 20 ton grafitu, dając moc termiczną około 8 MW. Istniały również inne źródła ciepła, które powodowały emisję radionuklidów do atmosfery. Była to energia promieniowania w rdzeniu reaktora (20 MW) oraz reakcja cyrkonu z wodą (Zr + H2O à ZrO2 + 2H2) i specjalnie uwolnionego wodoru (50 MW). Łączna moc źródła ciepła wynosiła więc 78 MW, a po wypaleniu wodoru – 28 MW. Ta energia była prawdopodobnie główną przyczyną wysokiego wzniesienia się radionuklidów w atmosferze, a następnie rozprzestrzeniania ich wokół całej Półkuli Północnej.

 

Tabela 1. Średnia roczna dawka promieniowania jonizującego od światowego jądrowego cyklu paliwowego – w 1986 r. Moc zainstalowana 274 GW, produkcja 170 GWe. (Na podstawie UNSCEAR, 1988)

Faza cyklu paliwowego Dawka [µSv] Części dawki od całego cyklu [%]
Wydobycie rudy uranu 0,016 6
Przeróbka rudy 0,0013 0,48
Hałdy po wydobyciu i przeróbce 0,08 29,9
Produkcja paliwa 0,0001 0,036
Praca reaktorów 0,079 29,4
Przeróbka wypalonego paliwa (emisje do atmosfery) 0,007 2,6
(emisje do oceanów) 0,081 29,9
Transport 0,003 1,2
SUMA 0,27 100
ŚREDNIA DAWKA NATURALNA 2400

 

W momencie awarii w rdzeniu reaktora znajdowały się radionuklidy o aktywności około 1 × 1020 Bq. Większość z nich stanowiły: molibden-99, ksenon-133, cer-141, bar-133, ruten-103 i cyrkon-95. Z wyjątkiem radioaktywnych gazów: kryptonu-85 i ksenonu-133 – tylko część pozostałych radionuklidów zawartych w stopionym rdzeniu przedostała się do atmosfery. Według obliczeń specjalistów radzieckich, 10 do 20% lotnych radioizotopów jodu, cezu i telluru zostało uwolnionych z rdzenia, a radionuklidów nielotnych – 3 do 5,5%. Ocena ta oparta była na pomiarach aktywności osadzonej na powierzchni gruntu w granicach Związku Radzieckiego.

W tych obliczeniach założono, że początkowo radionuklidy wzniosły się w atmosferze tylko na wysokość około 1 km, zanim rozpoczął się poziomy ich transport, oraz że następnie wznosiły się znacznie niżej. Jednakże pomiary samolotowe prowadzone w Polsce w ciągu pierwszych dwóch tygodni po wypadku wykazały obecność bardzo silnych stężeń radioaktywnego jodu i cezu na dużych wysokościach w troposferze – aż do wysokości 12 km. Oceny Amerykańskiego Departamentu Energii (oparte na modelach transportu na dalekie odległości) biorące pod uwagę nasze pomiary radioaktywności na dużych wysokościach, oraz oceny UNSCEAR (oparte na pomiarach depozycji radionuklidów poza Związkiem Radzieckim), dały wyższy odsetek uwolnienia lotnych radionuklidów: w przypadku jodu-131 sięgający od 35 do 55% a cezu-137 – 25 do 31%.

Aktywność radionuklidów zawartych w rdzeniu reaktora (1,2 × 1020 Bq) była w momencie rozpoczęcia się awarii 2,5 razy wyższa od naturalnej rocznej emisji radonu-222 do atmosfery (4,8 × 1019 Bq) oraz 200 000 razy mniejsza od aktywności radionuklidów uwolnionych we wszystkich dotychczasowych eksplozjach jądrowych w atmosferze (2,2 × 1025 Bq). Natomiast aktywność radionuklidów uwolnionych ze zniszczonego reaktora do atmosfery była znacznie mniejsza: np. jodu-131 uwolniło się 3,3 × 1017 Bq, a cezu-137 – 7 × 1016 Bq.

W roku 1962, w którym dokonano najwięcej próbnych wybuchów jądrowych w atmosferze o całkowitej mocy rozszczepieniowej 76,6 megaton, 77 eksplozji wprowadziło do atmosfery niemal 1000 razy więcej jodu-131 (3,2 × 1020 Bq) i około 6 razy więcej cezu-137 (4,5 × 1017 Bq) niż wypadek czarnobylski. Wynika z tego, że wypadek czarnobylski uwolnił do atmosfery 12 razy mniej jodu-131 i 12 razy mniej cezu-137 niż eksplozja rozszczepieniowa o mocy 1 megatony. Jednak próby jądrowe dokonane zostały w miejscach odległych od okolic gęsto zaludnionych, a uwolnienia z elektrowni czarnobylskiej nastąpiły w terenie, gdzie gęstość zaludnienia była trzykrotnie większa niż średnio na Białorusi, 1,7 razy wyższa niż średnio na Ukrainie i podobna do gęstości zaludnienia w Polsce, Danii czy Szwajcarii.

Pomiary aerozoli zbieranych przy powierzchni ziemi i na dużych wysokościach w troposferze i stratosferze w Polsce wskazywały, że w pierwszych dniach po wypadku radioaktywność systematycznie spadała aż do 5 maja; 7 i 8 maja wzrosła dziesięciokrotnie, a następnie 11 maja znowu obniżyła się o kilka rzędów wielkości. Było to zgodne ze zmianami emisji obserwowanymi bezpośrednio w czarnobylskiej elektrowni. Ta fluktuacja emisji radionuklidów wynikała ze zmian skuteczności walki z ogniem w reaktorze i odcinania jego dostępu do atmosfery.

 

Skażenia i dawki promieniowania

 

W ciągu 10 dni emisji zmienne warunki pogodowe, z wiatrami wiejącymi w różnych kierunkach na różnych wysokościach, doprowadziły do bardzo skomplikowanej sytuacji skażeń (ryc. 1). Z całkowitej aktywności uwolnionego cezu-137,43% zdeponowało się w Związku Radzieckim, a 38% poza jego granicami w Europie, 8% na oceanach, a reszta w innych rejonach Półkuli Północnej.

WwCldej1

Ryc.1. Średnia depozycja cezu-137 na powierzchni gruntu w Europie (wg UNSCEAR, 1988).

 

Najwyższą „lokalną” depozycję cezu-137 poza Związkiem Radzieckim stwierdzono w Szwecji (85 kBq/m2), w Szwajcarii (43 kBq/m2), Bawarii (45 kBq/m2) i Austrii (33-59 kBq/m2). Średnia depozycja tego nuklidu w Szwecji wahała się w różnych rejonach od 0,8 do 31 kBq/m2, w Finlandii wynosiła 14,7 kBq/m2, Austrii 23,1 kBq/m2, w RFN od 2,7 do 16 kBq/m2, w Rumunii 4,5 do 18 kBq/m2, w Szwajcarii 1,3 do 14,8 m2, a w Polsce – 5,2 kBq/m2.

Skład izotopowy radionuklidów zdeponowanych w poszczególnych rejonach świata różnił się znacznie, co wynikało ze zmieniających się procesów emisji w zniszczonym reaktorze (zależnych głównie od zmian temperatury) i od sytuacji meteorologicznej. Stosunek jodu-131 do cezu-137 w chmurach radioaktywnych przelatujących nad Polską wahał się od 2,9 w dniu 29 kwietnia 1986 r. na wysokości 6 km, do 71 na wysokości 9 km w dniu 7 maja. Znalazło to odbicie w składzie radioizotopów zdeponowanych na powierzchni ziemi w poszczególnych krajach, w których średni stosunek jodu-131 do cezu-137 wahał się od 1 do 33. Oceny skażeń poszczególnymi izotopami potrzebne do obliczeń dawki promieniowania, oparte na pomiarze jednego radionuklidu, np. cezu-137 lub tzw. globalnej aktywności beta, nie mają więc sensu. Piszę o tym, ponieważ w Polsce panuje moda na tego rodzaju obliczenia, spóźniona o dobre 30 lat.

Poza granicami Związku Radzieckiego depozycja radionuklidów nigdzie nie spowodowała zagrożenia życia i zdrowia.

WwCldej2

Ryc. 2. Moc dawki promieniowania gamma wokół Czarnobylskiej Elektrowni Jądrowej w końcu kwietnia 1986 r. (mGy/h) /wg Asmolov et al., 1987/.

 

Jak wykazały pomiary przeprowadzone w sierpniu 1986 r., moc dawki promieniowania w środku zniszczonego reaktora wynosiła ponad 100 Gy/h. Jak wynika z ryc. 2 z początkiem maja 1986 r. aż do odległości około 3 km do reaktora moc dawki wynosiła 100 mGy/h, aż do 10 km na zachód od reaktora – około 10 mGy/h, a do odległości 30 km na zachód – około 2 mGy/h. Dawka śmiertelna dla człowieka sięga od 3 Gy (kilka procent zgonów) do 6 Gy (niemal 100 procent zgonów).

W nowo zbudowanym mieście Prypeć, zamieszkanym przez 49 000 osób i położonym od 2,5 do 5 km na zachód od reaktora o godzinie 7.00 27 kwietnia 1986 r. moc dawki gamma sięgała od 1,8 do 6,0 mGy/h, a o godzinie 17.00 – 3,6 do 10 mGy/h.

Oznacza to, że w okolicach bliskich reaktora śmiertelna dawka promieniowania mogła łatwo zostać pochłonięta w ciągu kilkudziesięciu godzin, a w okolicach do 10 kilometrów – w ciągu kilku dni. Z ryciny 2 można wnosić, że dawka na całe ciało od 250 do 750 mSv, przyjęta w ZSRR jako poziom wymagający ewakuacji ludności, mogła być osiągnięta na bardzo dużym obszarze w ciągu kilku dni po awarii.

Jednak zasięg strefy śmiertelnego zagrożenia radioaktywnym skażeniem terenu był w przypadku katastrofy czarnobylskiej znacznie mniejszy niż po wybuchu bomby atomowej o mocy 1 megatony. W tym przypadku, 18 godzin po eksplozji, moc dawki 100 mGy/h sięgałaby na odległość 120 km w kierunku wiatru od miejsca wybuchu. Jednak zasięg plam skażeń, gdzie moc dawki promieniowania prawdopodobnie osiągnęła poziom zagrożenia śmiertelnego (rejon Żytomierza, Homla i Briańska, dla których źródła radzieckie nie podają wartości mocy dawek) był w przypadku Czarnobyla stosunkowo znacznie większy niż to obserwowano po wybuchach jądrowych przeprowadzonych w rejonach pustynnych i oceanicznych. Różnica wynikała z odmiennych warunków meteorologicznych w Europie wschodniej i na pustynnych poligonach atomowych oraz ze znacznie rzadszej sieci pomiarowej przy próbach oceanicznych.

WwCldej3

Ryc.3. Zasięg mocy dawki 100 mGy/h w końcu kwietnia 1986 r. po wypadku w Elektrowni Czarnobylskiej oraz rozmieszczenie rejonów silnych skażeń skąd ewakuowano ludność, w porównaniu z idealizowanym zasięgiem mocy dawki mGy/h po wybuchu jądrowym o mocy 1 megatony.

 

W innych rejonach i poza Związkiem Radzieckim maksymalne moce dawek osiągnęły poziom tysiące razy niższy. Np. w Szwecji – 9 µGy/h, w Austrii – 2,5 µGy/h, w Bawarii – 1,0 µGy/h.

Dawki promieniowania pochłonięte przez ludność w pierwszym roku po awarii pochodziły głównie od trzech izotopów: jodu-131, cezu-137 i cezu-134. Pozostałe izotopy, a wśród nich najważniejsze: tellur- -132 i ruten-103 – miały znacznie mniejszy udział. Dawka długoterminowa, z której większość zostanie zaabsorbowana w ciągu około 50 lat, spowodowana będzie głównie promieniowaniem cezu-137 i cezu- -134.

Do dawki na całe ciało w pierwszym roku po awarii promieniowanie radioaktywnej chmury wniosło mniej niż 1%, inhalacja około 6%, żywność i woda około 70%, a napromieniowanie zewnętrzne 23%. W poszczególnych krajach stosunki te różniły się dość znacznie. Dawka pięćdziesięcioletnia będzie pochodziła po połowie od napromieniowania zewnętrznego i przez drogę pokarmową.

Geograficzne rozmieszczenie depozycji radionuklidów, a więc i dawek otrzymywanych przez ludność, miała bardzo nieregularny, jakby „plamisty” charakter, co wynikało z niejednorodności opadów deszczu, kierunków wędrówki chmur radioaktywnych i wahań emisji z reaktora. Było tak zarówno w okolicach bliskich reaktora, jak i w odległości kilkuset kilometrów, gdzie depozycja radionuklidów była tak wielka, że zaistniała konieczność ewakuacji mieszkańców.

Podobnie zmieniło się geograficznie skażenie żywności, które w pierwszym roku zależało od sezonu wegetacyjnego. Stężenie jodu-131 w mleku, które mogło stanowić największe zagrożenie dla małych dzieci w maju 1986 r., w większości najsilniej skażonych krajów europejskich sięgało kilkuset Bq/l. Było zatem poniżej „wtórnego awaryjnego poziomu odniesienia” (derived emergency reference level – DERL) 2000 do 20 000 Bq/l, ustalonego przez brytyjski National Radiological Protection Board (NRPB) i ogłoszonego w marcu 1986 r., tj. przed wypadkiem w Czarnobylu. W niektórych rejonach Związku Radzieckiego (Płd. Białoruś, Płn. Ukraina i sąsiednie rejony Rosji) stężenie jodu-131 w mleku sięgało 40 000 do 400 000 Bq/l, a więc przekraczało wartości DERL.

Brytyjskie wartości DERL przyjęto dla cezu-137: w mleku 36 000 Bq/l, w jarzynach zielonych 1 900 000 Bq/l, a w owocach 2 800 000 Bq/l. W pobliżu Czarnobylskiej Elektrowni Jądrowej w 1986 r. ułamek żywności skażonej powyżej norm radzieckich sięgał 10 do 30%. Poza Związkiem Radzieckim stężenia cezu-137 w żywności były zwykle setki tysięcy razy niższe od wartości DERL, opartych na zaleceniach Międzynarodowej Komisji Ochrony Radiologicznej i na aktualnej wiedzy radiologicznej. Jednak w niektórych krajach wielkie ilości pożywienia zostały zniszczone, co spowodowało wiele milionów dolarów strat. Powodem tego było wprowadzenie ad hoc znacznie surowszych limitów skażeń żywności, jakie w niektórych krajach były 50 000 razy niższe od norm brytyjskich. Limity te wprowadzono po pierwszej fali radioaktywności, która objęła Polskę i inne kraje sąsiadujące z ZSRR, a jeszcze nie dotarła dalej na zachód. Był to poziom tysiące razy niższy od norm brytyjskich i amerykańskich, a samych Brytyjczyków zmuszono do porzucenia własnych norm. Nasz eksport natychmiast odczuł skutki tych zarządzeń, które były korzystne (tylko początkowo) dla zachodnich producentów żywności.

Polityczno-merkantylny charakter tych działań obrazuje zarządzenie wydane w jednym z krajów Bliskiego Wschodu (w którym poziom wiedzy radioekologicznej – jak sądzę, jest raczej wysoki), gdzie limit skażenia cezem-137 dla żywności importowanej z Europy Wschodniej ustalono na 250 Bq/kg i 600 Bq/kg dla żywności z Europy Zachodniej.

Najwyższe dawki promieniowania (poza ratownikami i personelem elektrowni jądrowej) otrzymała grupa 88 000 osób ewakuowana z Prypeci i okolic, 2500 osób ewakuowanych z rejonu Homla na Białorusi (140 km N od Czarnobyla), 1000 osób z rejonu Żytomierza (170 km SE od Czarnobyla) oraz 1000 osób z Briańska, w Rosji (350 km NE od Czarnobyla) (tabela 3). Wśród nich najbardziej narażoną grupą byli ci, których obowiązki zmuszały do długotrwałego przebywania na otwartej przestrzeni: lekarze, pracownicy służb komunalnych i milicjanci. Za pomocą dozymetrii biologicznej, opartej na mierzeniu liczby aberracji chromosomowych w limfocytach, stwierdzono, że w tej specjalnie narażonej grupie średnia dawka zaabsorbowana przez całe ciało wynosiła 130 mSv. Natomiast średnia dawka wśród 88 000 osób ewakuowanych z Prypeci i okolic sięgała około 30 Sv, tj. 15 razy powyżej rocznej dawki naturalnej. W niektórych wioskach (Tłusty Las, Kopacze) indywidualne dawki sięgały do 400 mSv.

 

Tabela 3. Średnia dawka od odpadu czarnobylskiego na całe ciało (w mSv i w procentach dawki naturalnej) w pierwszym roku i w ciągu 50 lat (wg UNSCEAR, 1988 i Il’in i Pavlovskij, 1987).

Ludność W pierwszym roku Po 50 latach
[mSv] [%] [mSv] [%]
Ewakuowani 40 1600 40,8 33
Płd. Europa 0,51 21 1,18 1
Środkowa Europa 0,34 14 0,92 0,77
Polska 0,24 10 0,74 0,62
ZSRR 0,26 11 0,82 0,68
Płn. Europa 0,22 9 0,91 0,76
Zach. Europa 0,06 2,5 0,17 0,14
Płn. Ameryka 0,001 0,04 0,005 0,004
Średnia dawka naturalna 2,4 100 120,0 100

 

Dawka na tarczycę wśród ewakuowanych osób wynosiła średnio 300 mSv, a 1% osób otrzymało dawkę do 1300 mSv, co można porównać z dawką interwencyjną – od 500 do 5000 mSv zalecaną przez organizacje międzynarodowe.

Poza grupą osób ewakuowanych, pierwszoroczna dawka na całe ciało była o kilka rzędów wielkości niższa (tab. 3). Sięgała ona w Europie od 0,002 mSv w Portugalii do 0,65 mSv w Austrii, tj. stanowiła odpowiednio 0,08 do 28% rocznej dawki naturalnej. Polska znalazła się na 11 miejscu z dawką średnią wynoszącą 0,24 mSv.

Dawka długoterminowa sięgać będzie od 0,005 mSv w Północnej Ameryce do 1,18 mSv w Południowej. W ciągu 50 lat ludność żyjąca w tych regionach otrzyma średnią dawkę promieniowania ze źródeł naturalnych sięgającą około 120 mSv, tzn. opad czarnobylski zwiększy ją w tym czasie o 0,004 – 1%. (tab. 3). W Polsce dawka pięćdziesięcioletnia od tego opadu sięgać będzie średnio 0,74 mSv, tj. 0,62% dawki naturalnej. Natomiast w grupie osób ewakuowanych dawka pięćdziesięcioletnia sięgnie 40,8 mSv, tj. 33% dawki naturalnej.

 

Zgony nowotworowe

 

Dawki promieniowania pochłonięte od opadu czarnobylskiego przez ludność Półkuli Północnej są tak małe, że nie można z żadną pewnością stwierdzić, iż mogą one mieć wpływ szkodliwy lub dobroczynny. Sądzę, że obliczenie odpowiadającej im liczby zgonów nowotworowych wkracza w dziedzinę fantazji. Ponieważ bardzo wiele ludzi żyje na Półkuli Północnej, mnożąc teoretyczne współczynniki ryzyka przez niemal dowolnie znikome wartości dawek otrzymuje się wielkie liczby zgonów.

Współczynniki ryzyka popromiennego używane zwykle w tego rodzaju obliczeniach zostały opublikowane przez Komitet UNSCEAR w 1977 r. i następnie przyjęte przez Międzynarodową Komisję Ochrony Radiologicznej. Opracowano je dla celów ochrony poszczególnych osób przed promieniowaniem oraz dla ustalenia przepisów i polityki ochrony. Są one oparte ha wynikach badań epidemiologicznych grup ludności narażonych na bardzo wysokie dawki promieniowania, przy wysokich mocach dawek. Nieograniczone stosowanie wartości tych współczynników do oceny skutków małych dawek i małych ich mocy, a następnie twierdzenie, że wyniki obliczeń przedstawiają biologiczną rzeczywistość, jest nie do przyjęcia z punktu widzenia epidemiologii. Stosowanie ich do sytuacji czarnobylskiej, nawet do oceny liczby dodatkowych zgonów nowotworowych w najsilniej narażonej grupie osób ewakuowanych z pobliża elektrowni, wydaje się nieuzasadnione. Jednak dla ilustracji zagadnienia przedstawię tę ocenę.

Dawka promieniowania pochłonięta w ciągu 50 lat po wypadku (40,8 mSv) przez 115 000 osób ewakuowanych, będzie co najmniej 2 rzędy wielkości większa niż w innych grupach ludności narażonych na opad ze zniszczonego reaktora (tab. 3). Stosując nowy współczynnik ryzyka nowotworowego (przyjęty w 1983 r. przez UNSCEAR), wynoszący średnio 65 dodatkowych zgonów na 1000 osób i na 1 Gy, oraz przyjmując, za UNSCEAR, że współczynnik redukcji dla ryzyka przy małych dawkach i niskich mocach dawek ma średnio wartość 5, można obliczyć, że liczba dodatkowych zgonów nowotworowych, która w tej grupie osób mogłaby powstać, wynosi 60 (od 28 do 92). Ta hipotetyczna liczba dodatkowych zgonów nie mogłaby nigdy być wykryta wśród 23 000 naturalnych zgonów nowotworowych, których należy oczekiwać wśród osób ewakuowanych.

Sam Komitet UNSCEAR w swoim raporcie czarnobylskim powstrzymał się od oceny prawdopodobieństwa powstania zgonów nowotworowych, ponieważ uważa, że stosowalność współczynników ryzyka do tej sytuacji jest wątpliwa. Komitet natomiast stwierdził, że poniżej pewnego poziomu dawki nie powstaje statystycznie znacząca liczba dodatkowych zgonów nowotworowych, w porównaniu z populacją kontrolną. Poniżej tego poziomu dawki nie można zaobserwować zwiększenia ryzyka nowotworowego i dlatego nie może ono być wprost określone (UNSCEAR, 1988). Dawka, poniżej której nigdy nie zauważono żadnego nowotworu, wynosi 200 mSv.

Dawka promieniowania od opadu czarnobylski ego zaabsorbowana przez najbardziej narażoną grupę ludności ewakuowanej, tj. około 40 mSv, będzie pięciokrotnie niższa od tej dawki. Zajmowanie się oceną liczby dodatkowych zgonów nowotworowych dla innych populacji, narażonych na dawki od czarnobylskiego opadu o kilka rzędów wielkości niższe niż w grupie ewakuowanej, jest ćwiczeniem nie mającym związku z rzeczywistością.

 

Straty w środowisku

 

Spośród roślin najbardziej ucierpiały drzewa iglaste. Największe straty powstały w lasach sosnowych, w których dawka pochłonięta sięgała 80 – 100 Gy. Obszar objęty zniszczeniem sięgał w zimie 1986/87 – 400 hektarów. Lasy liściaste praktycznie nie uległy uszkodzeniu. W rejonach o dawce poniżej śmiertelnej dla drzew iglastych (8-10 Gy) niektóre młode drzewa (10-12-letnie), również wymarły, a 90 – 95 % z nich miało objawy martwicy. W rejonach dawek 2 – 4 Gy większość sosen miała krótsze zakrzywione i pogrubione przyrosty, z częściowo tylko zachowanymi szpilkami. W szpilkach nienormalnych przyrostów obserwowano zniszczenie kompleksu chlorofilo-białkowo-lipidowego.

Od września 1986 r. obserwowano inwazje larw Monchamus galloprovinceali pistor w powalonych pniach sosen, w rejonach gdzie moc dawki sięgała do 40 mR/h. W larwach tych nie zauważono odstępstw od normalnej morfologii. Należy oczekiwać masowej inwazji tego szkodnika w osłabionych lasach sosnowych i masowego wymierania sosen na terenach skażonych w okresie następnych 8 do 10 lat.

W trawach zauważono znamienne statystycznie zwiększenie liczby mutacji na terenach objętych mocą dawki powyżej 0,05 mGy/h.

Wśród 29 rodzin dzikich, narażonych na moc dawki 0,1 – 2,5 mGy/h masa nasion i siła kiełkowania uległy zmniejszeniu.

Trzydziestokrotne zmniejszenie mezofauny glebowej, zamieszkującej ściółkę leśną, obserwowano w lipcu 1986 r. na terenach sąsiadujących z elektrownią czarnobylską. Na terenach rolnych redukcja mezofauny glebowej była 2-3-krotna, jak również zauważono zmniejszoną reprodukcję populacji. W przeciwieństwie do lasów, gdzie wczesne stadia larwy i nimfy nie występowały, na terenach rolniczych śmiertelność młodych zwierząt była znacznie niższa, tylko ok. 4 razy większa niż na terenach nie skażonych.

Katastrofalne zmiany w ściółce leśnej występowały przy dawkach ok. 29 Gy, dawki ok. 8 Gy powodowały nieznaczne, ale wykrywalne zmiany. Na terenach rolniczych, nawet przy dawkach sięgających 86 Gy, zwierzęta żyjące w glebie nie ucierpiały wiele, prawdopodobnie wskutek dobrej ochrony przed promieniowaniem beta przez warstwę gleby oddzielającą je od powierzchniowego opadu.

Dominujące mutacje letalne obserwowano u muszek owocowych. Ich częstość sięgała ok. 15% przy mocy dawki 0,01 – 08 mGy/h, 9% przy 0,02 – 0,06 mGy/h i 6% przy 0,002 – 0,03 mGy/h. Normalna częstość tych mutacji u muszek nie napromienionych wynosi 4,3%.

Nie zauważono zwiększonej śmiertelności, zmniejszenia płodności lub migracji dzikich zwierząt kręgowych w pierwszym okresie po wypadku. Jednak na silnie skażonych terenach, gdzie moc dawki wahała się od 0,0004 do 4,0 mGy/h, ocenia się, że dawka pochłonięta przez gryzonie musiała sięgać od 6 do 60 Gy od napromieniowania zewnętrznego i ok. dziesięciokrotnie mniej od spożytych radionuklidów, a więc należałoby oczekiwać, że 50 do 90% gryzoni powinno zginąć na tych terenach (LD 50 dla gryzoni wynosi 6- 12 Gy). Na tych terenach zaobserwowano jednak na wiosnę 1987 r. silny wzrost liczby gryzoni, co wynikało prawdopodobnie z migracji z rejonów przyległych na pola z pozostawionymi uprawami, opuszczone przez ludzi i zwierzęta domowe. Liczba gryzoni wzrosła na całym skażonym terenie z ok. 56 zwierząt na hektar przed awarią do 600 na hektar w 1987 r.

Zwiększoną częstość aberracji chromosomowych zauważono u dzikich gryzoni, natomiast stwierdzono brak zmian genetycznych u zwierząt wodnych żyjących w zbiorniku wody chłodzącej elektrowni czarnobylskiej.

 

Po dwóch latach

 

Jak wynika z rozmów, które niedawno przeprowadziłem z członkami delegacji radzieckiej w UNSCEAR oraz z innymi osobami, które w maju 1988 r. zwiedzały rejon Czarnobyla, z początkiem 1988 r. mieszkańcy 16 wiosek mniej skażonych – w sektorach zewnętrznych strefy 30 kilometrowej, powrócili do swoich domów. Przewiduje się, że w wyniku działania procesów naturalnych cały obszar między 10 a 30 km od elektrowni powróci do warunków praktycznie przedwypadkowych w ciągu około 10 lat. Już obecnie w wielu rejonach, zwłaszcza północno-wschodnich i południowych, warunki spełniają wymagania ochrony radiologicznej. Jednak nadal utrzymuje się tam zakaz osiedlania, który będzie obowiązywał prawdopodobnie przez kilka lat.

Około 20 wiosek wewnątrz strefy 30-kilometrowej zostało zasiedlonych bez zezwolenia władz przez około 1000 starszych osób. Narażenie na promieniowanie zewnętrzne nie będzie dla nich stanowiło zagrożenia. W pobliżu samej elektrowni, gdzie drzewa z wymarłego lasu zostały usunięte, prowadzi się obecnie zalesianie.

Miasto Czarnobyl jest ponownie zasiedlone i służy jako zaplecze dla akcji dekontaminacyjnej, w której bierze udział ok. 10 000 osób. Miasto Prypeć jest obecnie odkażane i prawdopodobnie po kilku latach wszystkie mieszkania będą gotowe do przyjęcia powracającej ludności.

Reaktory nr 1 i 2 elektrowni czarnobylskiej pracują ponownie od lutego 1987 r., a reaktor nr 3 od grudnia 1987 r.

Masowe badania lekarskie, które objęły ponad 1 milion osób spośród ludności eksponowanej na opad czarnobylski, jak dotąd nie wykazały odstępstw od normalnego stanu zdrowia, które mogłyby być związane z napromieniowaniem.

 

Wnioski

 

Zagrożenie dla ludności wywołane awarią czarnobylską wynikało wyłącznie z uwolnienia do atmosfery wielkich ilości substancji radioaktywnych. W porównaniu z innymi uwolnieniami katastroficznymi, wywołanymi przez człowieka i naturalnymi, liczba dawek szkodliwych cezu-137 uwolnionych z uszkodzonego reaktora była dziesięciokrotnie niższa niż dawek izocjanku metylu, uwolnionego np. podczas katastrofy fabryki pestycydów w Bhopalu (Indie) w grudniu 1984 r. (gdzie zginęło 2346 osób, a 40 000 zostało ciężko poszkodowanych) oraz dziesiątki tysięcy razy niższa od liczby dawek szkodliwych dwutlenku węgla uwolnionych w czasie naturalnej katastrofy w Jeziorze Nyos w Kamerunie, w sierpniu 1986 r. (gdzie zmarło około 1700 osób) (tabela 4). Po wypadku w elektrowni czarnobylskiej nie wystąpiły wśród ludności żadne zgony ani uszkodzenia ciała.

Brak zgonów wśród ludności wynikał z dwóch przyczyn: 1) stosunkowo niskiej toksyczności uwolnionych substancji, których działanie zależało od dość długiego czasu potrzebnego do pochłonięcia szkodliwych dawek promieniowania; umożliwiło to przeprowadzenie skutecznych operacji ratowniczych, oraz 2) koncentracji ogromnych zasobów wielkiego kraju dla przeciwdziałania skutkom katastrofy. Prawdopodobnie system społeczny i polityczny Związku Radzieckiego ułatwił tę koncentrację.

Odległe skutki zdrowotne, tj. zgony nowotworowe wywołane małymi dawkami promieniowania pochłoniętymi przez ludność, jeżeli w ogóle mogły powstać, będą poniżej progu wykrywalności.

Długotrwałe skutki środowiskowe są obecnie  ograniczone do obszaru ok. 20 km2, który składa się w połowie z terenów uprawnych i w połowie z lasów i nieużytków.

Opad czarnobylski był łatwo wykrywalny dziesiątki tysięcy kilometrów od źródła emisji nie dlatego, że masy radionuklidów były wielkie – zaledwie 28 kg cezu-137 i 370 g jodu-134, ale ze względu na niezwykle wysoki poziom systemów monitoringu promieniowania jonizującego, istniejących w wielu krajach. Obecnie stosowane metody monitoringu wykrywają rutynowo skażenia radionuklidami na poziomie wiele milionów razy niższym niż nieradioaktywnych substancji toksycznych. W chwili wypadku, tysiące stacji zorganizowanych w liczne systemy monitoringu śledziło bezustannie poziom promieniowania w środowisku. Była to sytuacja wyjątkowa, nie mogąca się zdarzyć w przypadku innych czynników szkodliwych, ponieważ dla żadnego z nich nie rozwinięto ani tak czułych metod wykrywania, ani tak rozległych systemów monitoringu.

 

Tabela 4. Porównanie emisji do atmosfery substancji toksycznych z Czarnobylskiej E. J. i z innych źródeł.

Źródło emisji i substancja

[Bq lub g]

Liczba[i] jednostek szkodliwych Wczesne zgony (Z)

ciężkie uszkodzenia (U)

Wybuchy jądrowe – 1962
Cs-137 4,5E17 1,3E9 0 Z
J-131 3,2E20 2,4E10 0 U
Czarnobyl, 1986
Cs-137 8,9E16 2,5E8 31 Z
J-131 1,7E18 1,3E8 203 U
Three Mile Island, 1979
Cs-137 ~0 0 Z
J-131 5,5E11 0 U
Bhopal, Indie, 1984
izocjanek metylu ~30E6 2,3E9 2346 Z

~40000 U

Jezioro Nyos, Kamerun, 1986
dwutlenek węgla 2,4E12 1,7E12 1700 Z
Naturalna roczna emisja Rn-222 z powierzchni Ziemi do atmosfery 4,8E19 ? U

 

Paradoksalnie – doskonałość ochrony radiologicznej była jedną z przyczyn lęku ludności, jaki wystąpił w wielu krajach Półkuli Północnej. Sygnały czarnobylskie wykryte przez systemy monitoringu poza Związkiem Radzieckim były tysiące razy poniżej niebezpiecznego poziomu promieniowania, ale jednocześnie były one tysiące razy powyżej poziomu przedawaryjnego. Ani publiczność, ani władze, ani znaczna część ekspertów – nie były przygotowane do racjonalnego reagowania na te sytuacje, a ich percepcja była często zakłócona czynnikami politycznymi i emocjonalnymi, którym poddana jest sprawa energetyki jądrowej.

Prawdopodobnie, w dalszej perspektywie, wypadek czarnobylski wpłynie na ukształtowanie się bardziej racjonalnego poglądu na energetykę jądrową, toteż i sygnały ewentualnego odległego wypadku radiacyjnego nie będą natychmiast wzbudzały lęku i grozy.

Gdyby jednak katastrofa zdarzyła się nie w czasie pokoju, lub gdyby z innych powodów właściwe przedsięwzięcia ratownicze nie mogły być podjęte, skutki emisji radionuklidów z reaktora czarnobylskiego mogłyby być znacznie groźniejsze.

Rzeczywiste zagrożenie radiacyjne ludności wystąpiło na terenach w promieniu około 30 km od elektrowni oraz w „plamach skażeń” do kilkuset kilometrów od elektrowni. Monitorowanie promieniowania na takim terytorium okazało się niezmiernie trudnym zadaniem logistycznym, do którego potrzebna była wielka liczba zespołów radiometrycznych oraz zwiad lotniczy. W sytuacjach gdy taki monitoring byłby niemożliwy, np. w czasie wojny, nie można by wcześniej ostrzec ludności. To, jak również trudności ze zorganizowaniem masowej ewakuacji, odkażania ludzi, pojazdów, ulic, itp. spowodowałoby bardzo wysokie bezpośrednie straty ludzkie na tych terenach, rzędu dziesiątków do setek tysięcy osób.

Pomimo, że ok. 70% dawki promieniowania w pierwszym roku po awarii pochłonięto drogą pokarmową, skażenie terenów rolniczych nie miałoby większego znaczenia dla przeżycia ludności w sytuacjach, gdy nie można by zastosować tak skutecznych środków ratowniczych w przypadku Czarnobyla. Mogłoby to jednak prowadzić do zwiększenia zachorowań na nowotwory i choroby dziedziczne, natomiast bezpośrednie zagrożenie życia ludzi byłoby ograniczone wyłącznie do krótkoterminowego napromieniowania zewnętrznego.

Uwolnienie substancji radioaktywnych z reaktora czarnobylskiego trwało 10 dni. W tym czasie spaliło się około 10% grafitu i uwolniło się 15 do 55% lotnych radionuklidów. Przy braku akcji ratowniczej, to uwolnienie mogłoby trwać znacznie dłużej, prowadząc do większego napromieniowania lokalnego i regionalnego ludności i ekosystemów. Długie uwalnianie radionuklidów z reaktorów typu innego niż RM BK, nie zawierających grafitu, mogłoby również się zdarzyć, gdyż ciepło promieniowania radionuklidów w rdzeniu byłoby do tego wystarczające.

Wypadek w czarnobylskiej elektrowni jądrowej udowodnił, że w warunkach pokoju nawet największa z możliwych awaria reaktora energetycznego nie powoduje strat wśród ludności. Jak większość wielkich dzieł technicznych współczesności, reaktory jądrowe stanowią wielkie potencjalne źródła zagrożenia i sama ich obecność zwiększa niebezpieczeństwo skutków wojen, które stają się coraz bardziej anachroniczną spuścizną historii. Wydaje się, że do życia w pokoju zmusza nas rozwój nauki i techniki. On jest głównym źródłem zachodzących obecnie zmian kulturowych i sposobu myślenia, które wiodą w stronę wygaszania agresywnych instynktów społecznych. Te zmiany oraz otwarcie praktycznie nieograniczonego skarbca energii, jakim są reakcje jądrowe, będą prawdopodobnie najważniejszym wkładem, który wiek XX wniesie w przyszłość.

 

Objaśnienia symboli

 

Gy (gray) – jednostka dawki promieniowania jonizującego pochłoniętego w materii (J/kg).

Sv (sievert) – jednostka równoważnika dawki promieniowania jonizującego uwzględniająca różnice skuteczności biologicznej różnych rodzajów promieniowania [J/kg].

Bq (becquerel) – jednostka aktywności substancji promieniotwórczej, równa jednemu rozpadowi atomu na sekundę.

LD50 – połowiczna dawka śmiertelna promieniowania lub substancji trującej, po której zginie 50% narażonej populacji.

[1] Patrz również art. prof. Z. P. Zagórskiego: Chemia katastrof w Windscale i Czarnobylu. „Problemy: nr 11/1988 (Red.)

[i] Jednostki dawek szkodliwych przyjęto jako: 1) aktywność pochłoniętych radionuklidów, dająca dawkę promieniowania 5 Gy, tj. 3,6E8 Bq cezu-137 i 1,3E10 Bq jodu-131 oraz 2) jako LD50 dla izocjanku metylu 1,3E2 i 1,4 g dwutlenku węgla.

Opublikowano Czarnobyl, Historia | Dodaj komentarz

Sortowanie Favorites (Ulubionych) w Edge

Jak wiadomo w Edge posortować Ulubionych (dalej zwanymi dla uproszczenia Favorites) się nie da. Taka cecha…

Nie przeszkadzało mi to, bo przed importem z IE były posortowane, a zmian w Edge wiele nie było.

Ale przyszła chwila instalacji Windows Phone 10 na smartfonie… Po instalacji urządzenia się zsynchronizowały – no i zrobił się problem:

  • jeżeli miałem w Favorites folder A z zawartością 5 linków,
  • to teraz miałem dwa foldery A, odległe od siebie, jeden zawierający 2 linki, a drugi 3.

Rozmnożyło się tak większość folderów, i korzystanie z Favorites stało się mordęgą.

 

Więc trzeba było poszukać. W win10-edge-favorites-folder-location była informacja o konfiguracji.

W katalogu C:\Users\%UserName%\AppData\Local\Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\RoamingState znajdują się pliki o nazwach takich jak: {00516beb-9ef3-4a06-8a1c-a7760fcb37e8}.json

 Nazwa, jak widać to Guid, a sam plik to zserializowana klasa.

Odtworzona klasa wygląda tak:


 

[DataContract]
public class Favorite
{
 [DataMember]
 public int Collection;
 [DataMember]
 public int SchemaVersion;
 [DataMember]
 public string ItemId;
 [DataMember]
 public string ParentId;
 [DataMember]
 public Int64 OrderNumber;
 [DataMember]
 public bool IsFolder;
 [DataMember]
 public string Title;
 [DataMember]
 public string URL;
 [DataMember]
 public UInt32 DateUpdatedLow;
 [DataMember]
 public UInt32 DateUpdatedHigh;
 [DataMember]
 public string FaviconFileContent;
 //
 public string OrderNumberAsText
 {
 get
 {
 return DateTime.FromFileTime(OrderNumber).ToString("yyy.MM.dd HH:mm:ss");
 }
 }
 //
 public Int64 DateUpdated
 {
 get
 {
 UInt64 u = DateUpdatedHigh;
 u <<= 32;
 u |= DateUpdatedLow;
 //
 return (Int64)u;
 }
 set
 {
 UInt64 uH = (UInt64)value;
 UInt64 uL = uH & 0xFFFFFFFF;
 uH >>= 32;
 //
 DateUpdatedLow = (UInt32)uL;
 DateUpdatedHigh = (UInt32)uH;
 }
 }
 public string DateUpdatedAsText
 {
 get
 {
 return DateTime.FromFileTime(DateUpdated).ToString("yyy.MM.dd HH:mm:ss");
 }
 }
 //
 public override string ToString()
 {
 string s = "";
 //
 s += string.Format("Collection:{0}{1}", Collection, Environment.NewLine);
 s += string.Format("SchemaVersion:{0}{1}", SchemaVersion, Environment.NewLine);
 s += string.Format("ItemId:{0}{1}", ItemId, Environment.NewLine);
 s += string.Format("ParentId:{0}{1}", ParentId, Environment.NewLine);
 s += string.Format("OrderNumber:{0}{1}", OrderNumberAsText, Environment.NewLine);
 s += string.Format("IsFolder:{0}{1}", IsFolder, Environment.NewLine);
 s += string.Format("Title:{0}{1}", Title, Environment.NewLine);
 s += string.Format("URL:{0}{1}", URL, Environment.NewLine);
 s += string.Format("FaviconFileContent:{0}\n", FaviconFileContent);
 s += string.Format("DateUpdated:{0}{1}", DateUpdatedAsText, Environment.NewLine);
 //
 return s;
 }
}

Zostało to, na wszelki wypadek opakowane:

 public class FileFavorite
 {
 public string FName;
 public Favorite F;
 }

 

ItemId i ParentId to Guidy, jeżeli ParentId jest równy „{fddf6d73-3ca3-456b-946a-96b379ad4a44}” to element znajduje się w głównym katalogu. ItemId zawsze był taki sam, jak w nazwie pliku.

OrderNumber, wbrew pozorom, to data w formacie FileTime. Określa ona kolejność wyświetlania elementów w Edge.

DateUpdatedLow, DateUpdatedHigh to połówki daty w formacie FileTime.

I tylko te elementy klasy zmieniałem, pozostawiając resztę.


Przy okazji zrobiłem formalne sprawdzenie poprawności danych: sieroty i duble. Sierot nie było, ale okazało się że prawie połowa wpisów to duble… Co ciekawe, nie były one widoczne.

Wczytana lista Guidów nie będącym plikami i których przodkiem był root, była grupowana po Title. W tych grupach, gdzie było > 1 elementów, wszystkie elementy poza pierwszym były usuwane, a w ParentId elementów będących ich potomkami wpisywany był ParentId pierwszego.

Zadziałało, chociaż by Edge zauważył zmianę trzeba było wejść i wyjść z jakiegoś katalogu Favorites.


A tutaj przykład posortowania Favorites:

static string rootId = „{fddf6d73-3ca3-456b-946a-96b379ad4a44}”;// na innym PC był taki sam

List<FileFavorite> lf = new List<FileFavorite>();// wszystkie Fav.

long ct = DateTime.Now.ToFileTime();
//
var AllFav = (from x in lf orderby x.F.Title orderby !x.F.IsFolder where (x.F.ParentId == rootId) select x).ToList();
//
DateTime ord = DateTime.Now;
TimeSpan m1 = new TimeSpan(0, 1, 0);
ord = ord.Subtract(new TimeSpan(0, AllFav.Count() * 3, 0));
//
for (int j = 0; j < AllFav.Count(); j++)
{
 AllFav[j].F.DateUpdated = ct;
 AllFav[j].F.OrderNumber = ord.ToFileTime();
 //
 Console.WriteLine(AllFav[j].F.Title);
 WriteFavorite(dstFav, AllFav[j]);
 //
 ord = ord.Add(m1);
}
//

Funkcje użytkowe:

  • deserializacja
  • serializacja

(ciekawostką jest to, że Edge używa innego serializera, bo DataContractJsonSerializer zamienia `/’ na `\/’, a tego w danych nie było. Ale to bez znaczenia, obydwie postacie są prawidłowe.)


 

public static FileFavorite ReadFavorite(string f)
{
 Byte[] bb = File.ReadAllBytes(f);
 MemoryStream ms = new MemoryStream(bb);
 ms.Position = 0;
 Favorite fv = (Favorite)ser.ReadObject(ms);
 //
 FileFavorite ffv = new FileFavorite()
 {
 FName = Path.GetFileNameWithoutExtension(f),
 F = fv
 };
 //
 if (ffv.FName != ffv.F.ItemId)
 {
 throw new Exception("ffv.Id != ffv.F.ItemId");
 }
 return ffv;
}

 

public static void WriteFavorite(string path, FileFavorite ffv)
{
 MemoryStream ms = new MemoryStream();
 ser.WriteObject(ms, ffv.F);
 ms.Seek(0, SeekOrigin.Begin);
 byte[] bb = ms.ToArray();
 string filename = Path.Combine(path, ffv.FName + ".json");
 File.WriteAllBytes(filename, bb);
}

Aktualizacja 2017

Teraz to nie pliki są używane, tylko baza danych i dane znajdujące się w:

%LOCALAPPDATA%\Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\AC\MicrosoftEdge\User\Default\DataStore\Data\nouser1\120712-0049

a konkretnie to ta baza danych:

 DBStore\spartan.edb

Do edycji bazy polecam program:

http://www.emmet-gray.com/Articles/EdgeManage.html

Ćwiczyłem to, gdy po aktualizacji zniknęła mi połowa favorities. Szczęśliwie, na innej maszynie pozostały właściwe dane

Opublikowano c#, Komputery i Internet | Otagowano , , | Dodaj komentarz