device zxspectrum128 ;; temp pages: splash_gfx_page equ #20 Gfx_vid_page equ #c0 menu_gfx_page equ #d0 highlight_menu_page equ #d1 Text_page equ #d8 Vid_page equ #e0 Sprite_page equ #f0 Mouse_pal_num equ #f0 ; BORDER is sampled immediately by the FPGA, unlike VCONFIG/VPAGE which are ; latched at the following line start. Keep one palette index for the whole ; frame: #00 is black in both the 256c palette and text GPAL (#F0). GFX_BORDER equ #00 sd_driver_page equ #0f cursor_adr equ #c000 cursor_page equ #10 music_players_page equ 3 music_page equ #1d ; 2 pages for music list_ram_page equ #1f download_page equ #20 ; allocate #28 pages for 640rb TRD get_buffer equ #4000 window_height equ #0d window_start_Yl equ #0100 window_start_Y equ high window_start_Yl bigbuff equ #c000 download_sites equ 1 gfx_sites equ 2 music_sites equ 3 press_sites equ 4 highlight_size equ 1408 search_textpage_adr equ #0108 do_nothing equ 0 view_downloaded_list equ 1 view_text equ 2 save_file equ 3 play_music equ 4 view_gfx equ 5 start_paging_page equ 1 analizator_screen_adr equ #c2e0-4 progress_bar_screen_adr equ #0012 cable_zifi=0 ; 1 - Cable version, 0 - wifi version org #8000 start // call write_rtc ld sp,#bfff call all_init call set_256c_mode ; TSCONFIG (sprite engine) and PALSEL set EXACTLY ONCE, here -- ; see set_256c_mode's comment. #3f = GPAL=15/T0PAL=3/T1PAL=0; ; confirmed by the sibling fork's own author: writing PALSEL ; mid-frame (from the raster interrupt handlers, every mode ; switch) is the actual root cause of the cursor-cutoff bug. ld bc,TSCONFIG ld a,TSU_SEN out (c),a ld bc,PALSEL ld a,#3f out (c),a call sd_init ei ld b,60 call wait ; Do not expose the raster handler before Text_page has been cleared: ; otherwise a frame can display the loader's leftover RAM contents. di call gfx_init call set_text_colors ld hl,int_main ld (#beff),hl ei call load_ini IF cable_zifi call psb_start ELSE call init_zifi ENDIF call set_Textpage ; set_download_dir leaves PAGE0 on the SD driver page, not Text_page ld hl,zifi_ready_msg ld b,1 call zifi_echo ld a,1 ld (zifi_ready),a ; enable menu tabs only after all initialization above ld a,(mouse_button) cpl and #f0 ld (wheel_old+1),a main sites_sw ld a,0 or a call nz,sites_list ; показать список сайтов для раздела load_sw ld a,0 or a jp z,main_ex call modem_load_file ld a,(do_after_load+1) cp save_file jr c,do_after_load call create_filename do_after_load ld a,0 cp save_file jr c,1f push af call save_downloaded_file pop af 1 cp view_downloaded_list call z,create_link_list cp view_text call z,text_view cp play_music call z,music_loaded cp view_gfx call z,view_image main_ex call wait_frame ; The analyzer runs outside the raster IRQ: its variable-height bars are ; too long for the line-287 handler. analyzer_active makes pt_play ; restore PAGE3 back to this routine if an IRQ occurs meanwhile. ld a,(save_mode+1) or a call nz,music_analizator do_start_music ld a,1 or a call z,music_init ; off music before loading new music file do_init_music ld a,0 or a jr z,main call music_init xor a ld (music_sw+1),a ld (is_music_play+1),a ld (do_init_music+1),a jp main wifi_connected db 'Connected succefully',0,0 wifi_try_connect db #0d,#0a,'Try connect to Access point',0,0 zifi_ready_msg db 'ZiFi is ready.',0,0 create_filename ; and check extension for scl scr sxg others ld hl,modem_command+5 ; without GET ld a,#0d 1 cpi jr nz,1b ; HTTP/1.0#0d ld bc,11+2 sbc hl,bc 1 ld (ix+thread.file_ext),hl ;find file extension dec hl 1 ld a,(hl) ; check \ / : * ? " < > | cp "\\" jr z,1f cp "/" jr z,1f cp ":" jr z,1f cp "*" jr z,1f cp "?" jr z,1f dec hl jr 1b 1 inc hl ld de,FILE_NAME ; file_name create ld b,48 ; FILE_NAME is exactly 48 bytes - never write past it 2 ld a,(hl) cp ' ' jr z,1f ld (de),a inc hl inc de djnz 2b ; ran out of room - stop here and null-terminate below 1 xor a ld (de),a ld a,(ix+thread.page) ; check unzip extension call set_page1 ld hl,(ix+thread.adress) ld a,"." cp (hl) ret nz inc hl 1 dec de ld a,(de) cp '.' jr nz,1b inc de ld b,3 1 ld a,(hl) ld (de),a inc hl inc de djnz 1b xor a ld (de),a ld (ix+thread.adress),hl ; all lenght - 4bytes of extension ld a,(ix+thread.full_len_high) ; a - high 16bit lenght ld hl,(ix+thread.full_len) ; hl - low 16bit lenght ld de,4 or a sbc hl,de sbc a,0 ld (ix+thread.full_len_high),a ; a - high 16bit lenght ld (ix+thread.full_len),hl ; hl - low 16bit lenght ret /* Address Mode Name Description 0x00EF..0xBFEF R DR Data register. Get byte from input FIFO. Input FIFO must not be empty (IFR > 0). 0x00EF..0xBFEF W DR Data register. Put byte into output FIFO. Output FIFO must not be full (OFR > 0). Address Mode Name Description 0xC0EF R IFR Input FIFO Used Register. 0 - input FIFO is empty, 255 - input FIFO is full. 0xC1EF R OFR Output FIFO Free Register. 0 - output FIFO is full, 255 - output FIFO is empty. Address Mode Name Description 0xC7EF W CR Command register. Command set depends on API mode selected. */ modem_load_file xor a ld (pause_music+1),a ld l,a ld h,a ld ix,read_threads ld (ix+thread.full_len),hl ld (ix+thread.full_len_high),a ld a,(do_after_load+1) cp play_music jr nz,1f ld a,(is_music_play+1) or a jr z,1f call set_music_pages call music_player_mute call restore_music_pages xor a ld (music_sw+1),a ld (is_music_play+1),a ld (do_init_music+1),a 1 ; show link ; ld hl,cmd_conn2site_adr ; ld de,#1e00 ; show link ; call show_line_get_buffer ; ld hl,modem_command ; ld de,#1000 ; show link ; call show_line_get_buffer load_ram_page ld a,0 ld (clr_load_mem1+1),a ld (clr_load_mem2+1),a call set_page3 call off_int_dma ld hl,0 ld (#c000),hl ld hl,clr_load_mem call set_ports ld de,download_icon call set_icon ld hl,cancel_icon_copy call set_ports call on_int_dma ld hl,progress_bar_screen_adr-1 ld (progress_bar+1),hl ld b,4 call view_progress_bar ; добавляем строку поиска первой и устанавливаем адрес загрузки после неё ld hl,#0000 ; main download adress ld a,(do_after_load+1) cp view_downloaded_list jr nz,1f ld a,download_page call set_page0_lite ld de,0 ld bc,list_search_db_end-list_search_db ld hl,list_search_db ldir ex de,hl ; download adress for lists. after "Search:" 1 ld (zipd_adr+1),hl ; snapshot load_ram_page NOW, before the (possibly multi-second) ; network receive below -- see saved_thread_page's own comment for why ; re-reading load_ram_page AFTER the call is wrong. ld a,(load_ram_page+1) ld (saved_thread_page),a IF cable_zifi ld a,(load_ram_page+1) ld hl,modem_command call psb_get ELSE call zifi_get ENDIF ; bc: hl - lenght of readed data ld ix,read_threads ld a,c ld (ix+thread.full_len_high),a ; bc - high 16bit lenght ld (ix+thread.full_len),hl ; hl - low 16bit lenght or h or l jr nz,1f ; ld a,do_nothing ld (do_after_load+1),a ; do NOTHING 1 xor a ld (ix+thread.num),a ld a,(saved_thread_page) ld (ix+thread.page),a call set_page1 ld hl,status_copy ; clear statusbar gfx call set_ports xor a ld (load_sw+1),a /* IF !cable_zifi */ ld hl,get_buffer ld (ix+thread.adress),hl ; Wifi adress without headers /* ELSE call find_0d0a ; Fined header end and skip for Cable ver ld (ix+thread.adress),hl ld de,get_buffer or a sbc hl,de ex de,hl ld hl,(ix+thread.full_len) sbc hl,de ld (ix+thread.full_len),hl ; hl - low 16bit lenght ENDIF */ ld a,(do_after_load+1) cp view_downloaded_list ret nz call off_int_dma ld hl,link_page_copy ; copy donwloaded list to list_page call set_ports jp on_int_dma zifi_get call wait_frame ld a,dl_timeout_quanta ; fresh inactivity budget for this connection attempt ld (dl_timeout_left),a ld a,(load_ram_page+1) ld (zipd_page+1),a call set_page0 inc a call set_page1 ld hl,0 ld (readed_len_low+1),hl ld hl,cmd_conn2site ; AT+CIPSTART - connect to site call zifi_send ld de,str_error call buffer_cmp jr nz,zg_ok ld hl,cmd_cipclose call zifi_send 1 ld de,str_ok call buffer_cmp jr z,zifi_get call wait_frame call fifo_inir jr 1b zg_ok ld b,15 ; TLS handshakes (SSL connect) can take longer than one poll zg_ok_wait ld de,str_ok call buffer_cmp jr z,zg_ok_done push bc call wait_frame call fifo_inir pop bc djnz zg_ok_wait jr zifi_get ; still no OK - start the whole connection attempt over zg_ok_done 1 ld hl,cmd_cipsend ; AT+CIPSEND=, call zifi_send_raw 2 call fifo_inir ld de,str_ok call buffer_cmp jr nz,2b 1 ld a,(hl) inc hl cp #ff jr z,2b cp ">" jr nz,1b ; send http request ld hl,modem_command call zifi_send_raw 1 call zifi_getchar cp "O" jr nz,1b call zifi_getchar cp "K" jr nz,1b // receive header first_ipd call reread_ipd 2 call read_fifo_char dec hl cp #0d jr nz,2b call read_fifo_char dec hl cp #0a jr nz,2b call read_fifo_char dec hl cp #0d jr nz,2b call read_fifo_char dec hl cp #0a jr nz,2b // header skipped ld a,h or l jr z,read_all_ipds ld (zipd_full_len+1),hl jr zipd_adr // receive data read_all_ipds call reread_ipd zipd_adr ld hl,#0000 zipd_full_len ld de,0 ; ipd len p231 ld bc,zifi_input_fifo_status 1 in a,(c) or a ; 0 - input FIFO is empty, jr z,1b p232 cp 0xbf ; jr c,p233 ; ld a,0xbf ; д p233 ld c,a ; о ld a,d ; л or a ; г jr nz,p234 ; о ld a,e ; cp c ; з jr nc,p234 ; а ld c,e ; п p234 ex de,hl ; р xor a ; я ld b,a ; г sbc hl,bc ; а ex de,hl ; е ld b,c ; м ld c,0xef ; inir ; и быстро едем ld a,d or e jr nz,p231 ld a,h cp #40 jr c,1f zipd_page ld a,0 inc a ld (zipd_page+1),a call set_page0 inc a call set_page1 ld a,h sub #40 ld h,a 1 ld (zipd_adr+1),hl ld hl,(zipd_full_len+1) ld b,h readed_len_low ld de,0 add hl,de ld (readed_len_low+1),hl jr nc,1f readed_len_high ld a,0 inc a ld (readed_len_high+1),a 1 call view_progress_bar jp read_all_ipds read_fifo_char ld bc,zifi_input_fifo_status ; ждём прихода данных в фифо 3 in a,(c) jr z,3b ; 0 - input FIFO is empty, ld b,0 in a,(c) ret reread_ipd ;ld a,3 ; out (#fe),a ld e,#ff ld hl,output_buff call rdipd ; xor a ; out (#fe),a ld de,CLOSED call buffer_cmp ; or a ; CLOSED, exit jp z,zifi_read_ipd_ex ld de,str_ipd call buffer_cmp ; cp low output_buff+#bf jr nz,reread_ipd ex de,hl call count_ipd_lenght ; in HL - lenght of ipd packet ld (zipd_full_len+1),hl ret zifi_read_ipd_ex pop af ld a,(readed_len_high+1) ld c,a ld hl,(readed_len_low+1) ret rdipd: call zifi_getchar jr z,rdipd ld (hl),a inc hl cp ':' ret z cp #0a ret z jr rdipd zifi_getchar: call zifi_input_fifo_check or a jr z,zifi_getchar ; ld bc,0xc0ef ; in a,(c) ; jr z,zifi_getchar ld b,0 in a,(c) dec b ret wifi_cancel_download_ex ld sp,#bfff xor a ld (load_sw+1),a ld (wifi_cancel_download+1),a ld hl,status_copy ; clear statusbar gfx call set_ports jp main ; same hard unwind as above, but leaves load_sw alone - timeout_next_track ; already set it to 1 so main picks up and starts loading the next track dl_timeout_advance_ex ld sp,#bfff xor a ld (wifi_cancel_download+1),a ld hl,status_copy ; clear statusbar gfx call set_ports jp main ; same hard unwind again, but re-arms load_sw for the SAME target (parse_url ; already built the request - just resend it) instead of cancelling/skipping dl_timeout_retry_ex ld sp,#bfff xor a ld (wifi_cancel_download+1),a ld a,1 ld (load_sw+1),a ld hl,status_copy ; clear statusbar gfx call set_ports jp main dl_timeout_quanta equ 2 ; ~5s per quantum (256 frames @ 50Hz) - 2 quanta = ~10s of silence dl_timeout_left db 0 dl_retries_max equ 3 ; retry the same request this many times before giving up on it dl_retries_left db dl_retries_max music_skip_chain_max equ 8 ; give up after this many consecutive dead tracks music_skip_chain_left db music_skip_chain_max ; called when a download times out while loading a music track - advances ; autoplay_num and starts loading the next track instead of just cancelling timeout_next_track ld a,(sum_list_lines+1) dec a ld c,a ld a,(autoplay_num+1) inc a cp c jr c,1f ld a,1 1 ld (autoplay_num+1),a call calc_link_num ld a,list_ram_page call set_page1 ld h,(ix+4) ld l,(ix+3) call parse_url ld a,1 ld (load_sw+1),a ret count_ipd_lenght ld hl,0 ; count lenght ; ld de,strbuff+7 cil1 ld a,(de) inc de cp ':' ret z sub 0x30 ld c,l ld b,h add hl,hl add hl,hl add hl,bc add hl,hl ld c,a ld b,0 add hl,bc jr cil1 ss_cmp ld hl,output_buff ss_cm1 ld a,(de) or a ret z inc de cpi jr z,ss_cm1 ret /* ld a,3 out (#fe),a ld de,#c000 ; call read_idp_packet read_idp_packet push de ld e,#ff ; lenght xor a out (#fe),a call read_pack ld c,a ld hl,output_buff ld b,l pop de ldir ld a,4 out (#fe),a ld a,d cp #d0 jr nz,read_idp_packet nop nop ret */ read_pack ld bc,zifi_input_fifo_status ; ждём прихода данных в фифо ld hl,0 1 dec hl ld a,h or a jp z,zifi_read_ipd_ex in a,(c) or a ; 0 - input FIFO is empty, jr z,1b ld hl,output_buff ; in E - lenght read_pack_proc cp 0xbf jr c,1f ld a,0xbf 1 ld b,a ld a,d or a jr nz,1f ld a,b cp e jr c,1f ld b,e 1 ld a,b push af 2 in a,(c) ld (hl),a inc l djnz 2b ; di ; inir ; ei ; push af ret fifo_inir push de call zifi_input_fifo_check ld hl,output_buff ; read data from fifo, count: #bf push hl ld bc,zifi_data_reg inir pop hl pop de ret zifi_send call zifi_send_raw zifi_check_receive_command jp fifo_inir zifi_send_echo push hl ld b,1 call zifi_echo pop hl call zifi_send 1 ld a,(hl) inc hl cp #0d+1 jr c,1b dec hl ld b,3 zifi_echo ld de,#1000 call print ld a,d cp 24 jr c,1f ld hl,text_up_copy call set_ports ld hl,24*256 call clear_text_line ld a,22 1 ld (zifi_echo+2),a ret print ld a,(hl) cp #ff ret z ld a,b or a jr nz,1f ld b,1 1 push de print1 ld a,(hl) inc hl cp #0d+1 jr c,print2 ld (de),a inc de jr print1 print2 ld a,(hl) cp #0d+1 jr nc,1f inc hl 1 pop de inc d djnz print ret zifi_send_raw call check_output_fifo_status call clear_output_fifo push hl ld hl,output_buff ld de,output_buff+1 ld bc,#ef ld (hl),l ldir pop hl ld bc,zifi_data_reg 1 ld a,(hl) or a ret z out (c),a inc hl jr 1b zifi_input_fifo_check ld bc,zifi_input_fifo_status ; ждём прихода данных в фифо ld e,0 3 in a,(c) or a ; 0 - input FIFO is empty, jr z,1f push af ld a,dl_timeout_quanta ; got data - reset the inactivity timeout ld (dl_timeout_left),a pop af ret 1 wifi_cancel_download ld a,0 or a jp nz,wifi_cancel_download_ex call wait_frame dec e jr nz,3b ; one ~5s quantum (256 frames @ 50Hz) passed with nothing from the server at all ld a,(dl_timeout_left) dec a ld (dl_timeout_left),a jr nz,error ; still have quanta left - flash the border and keep waiting ; timed out - retry the same request a few times before giving up on it ld a,(dl_retries_left) or a jr z,dl_timeout_no_more_retries dec a ld (dl_retries_left),a jp dl_timeout_retry_ex dl_timeout_no_more_retries ld a,(do_after_load+1) cp play_music jr nz,dl_timeout_giveup ld a,(music_skip_chain_left) or a jr z,dl_timeout_giveup ; skipped too many dead tracks in a row - stop trying dec a ld (music_skip_chain_left),a call timeout_next_track jp dl_timeout_advance_ex dl_timeout_giveup jp wifi_cancel_download_ex error ld a,2 out (#fe),a ret clear_output_fifo ld a,cmd_clear_output_fifo call zifi_out_command check_output_fifo_status ld bc,zifi_output_fifo_status cofs in a,(c) or a jr z,cofs ; 0 - output FIFO is full ret clear_input_fifo ld a,cmd_clear_input_fifo call zifi_out_command ld bc,zifi_input_fifo_status clear_input_fifo1 in a,(c) or a jr nz,clear_input_fifo1 ;0 - input FIFO is empty ret zifi_out_command ld bc,zifi_command_reg out (c),a ret zifi_command_result ld bc,zifi_error_reg in a,(c) ret downloaded_len db "Content-Length: ",0 CLOSED db "CLOSED",#0d,#0a,0 ;wifi_disconnect db "WIFI DISCONNECT",#0d,#0a,0 buffer_cmp ld hl,output_buff data_cmp ld (buffer_cmp_start+1),de ld c,low output_buff+#bf buffer_cmp_start ld de,0 buffer_cmp0 ld a,(de) cp (hl) jr z,buffer_cmp1 ld a,l cp c jr z,buffer_cmp_notfound inc hl jr buffer_cmp0 buffer_cmp_notfound or a ret buffer_cmp1 inc de inc hl ld a,(de) or a ret z cp (hl) jr nz,buffer_cmp_start jr buffer_cmp1 set_icon ld a,e ld (status_icon_copy+1),a ld a,d ld (status_icon_copy+3),a ld hl,status_icon_copy jp set_ports wait call wait_frame djnz wait ret view_progress_bar ld a,b or a ret z push hl push bc push bc ld a,Vid_page+9 call set_page0_lite pop bc progress_bar ld hl,0 inc hl bit 7,l jr z,1f ld l,low progress_bar_screen_adr ld a,(progress_bar_color+1) xor #18 ld (progress_bar_color+1),a 1 ld (progress_bar+1),hl progress_bar_color ld a,#74 ld (hl),0 inc h inc h dup 3 ld (hl),a ; inc l ; ld (hl),a ; dec l inc h inc h edup ld (hl),0 inc h inc h djnz progress_bar call restore_page0 pop bc pop hl ret /* +#0000 #04 #7f+"SXG" - 4 байта сигнатура, что это формат файла SXG +#0004 #01 1 байт версия формата +#0005 #01 1 байт цвет фона (используется для очистки) +#0006 #01 1 байт тип упаковки данных (#00 - данные не пакованы) +#0007 #01 1 байт формат изображения (1 - 16ц, 2 - 256ц) +#0008 #02 2 байта ширина изображения +#000a #02 2 байта высота изображения (далее указываются смещения, для того, что бы можно было расширить заголовок) +#000c #02 смещение от текущего адреса до начала данных палитры +#000e #02 смещение от текущего адреса до начала данных битмап Собственно начало данных палитры +#0010 #0200 512 байт палитра и начало данных битмап +#0210 #xxxx данные битмап */ init_view_image ld hl,int_gfx_view ld (#beff),hl xor a ld bc,VSINTL out (c),a inc b out (c),a jp wait_frame view_image ld ix,read_threads ld a,(ix+thread.page) call set_page1 ld a,Gfx_vid_page call set_page3 ld hl,(ix+thread.file_ext) inc hl ld a,"x" ; sxg / scr cpi jr z,view_sxg_image ld a,"r" cpi ret nz view_scr_image ld hl,(ix+thread.adress) ld de,#c000 ld bc,#1b00 ldir call init_view_image xor a ld (gfx_vmode+1),a ld (gfx_border+1),a ld a,#0f ld (gfx_vpal+1),a ; palsel jp show_gfx ; ----- SXG viewer ------------- view_sxg_image call init_view_image ld hl,(ix+thread.adress) ld de,5 add hl,de push hl ld a,(hl) ; background? #4005 ld l,a ld h,a ld (gfx_border+1),a ld (#c000),hl ld hl,clr_gfx_screen call set_ports ld b,#28 ld a,#ff out (c),a ld b,#27 ld a,%00000100 OUT (C),a call dma_stats pop hl inc hl inc hl ; #4007 ; push af ; ld (clrColor+1),a ; ld a,(hl) ; Тип упаковки данных (#00 - не пакованы) ld a,(hl) ; Video color mode ld c,a inc hl cp 2 ; 16c mode ld b,DMA_RAM + DMA_DALGN ; dma mode ld a,1 ; high byte pal adress ld de,#0f08 ; 32byte for pal dma send, 8 for palsel jr nz,3f xor a ld b,DMA_RAM + DMA_DALGN + DMA_ASZ ld de,#ff00 3 ld (view_image_pals_vpal_adr+1),a ld (color_type+1),a ld a,b ld (gfx_copy_type+1),a ld (gfx_copy_t2+1),a ld a,e ld (gfx_vpal+1),a ld a,d ld (view_image_pals_vpal+1),a or a rl e rl e rl e rl e ld a,e ld (gfx_border+1),a /* ld (imageMode),a push hl call setImageMode pop hl cp #ff ; error -> exit ret z */ ld e,(hl) ; Width 0-512 inc hl ld d,(hl) inc hl ld a,VID_360X288 or c ld (gfx_vmode+1),a push hl push bc ld hl,360 or a sbc hl,de srl l xor a sub l or a jr z,1f ld bc,GXOFFSL out (c),a inc b ld a,1 out (c),a 1 pop bc pop hl /* ; #168 - 360; #140 - 320; #100- 256 ld a,#68 cp e jr nz,1f ld a,VID_360X288 jr 2f 1 ; ld a,#40 ; cp e ; jr nz, ld a,VID_320X240 ; standart resolution 2 or c ld (gfx_vmode+1),a */ srl d rr e color_type ld a,0 or a jr z,4f srl d rr e ; Width 0-512 /4 4 ld a,e dec a ld (gfx_copy_w+1),a ld e,(hl) ; Height 0-512 inc hl ld d,(hl) inc hl push hl ld hl,288 or a sbc hl,de srl l xor a sub l or a jr z,1f ld bc,GYOFFSL out (c),a inc b ld a,1 out (c),a 1 pop hl bit 0,d jr z,1f ld a,#ff jr 2f 1 xor a dec e 2 ld (gfx_copy_h+1),a dec e ld a,e ld (gfx_copy_h2+1),a ld c,(hl) ; Указатель (смещение) на начало данных палитры inc hl ld b,(hl) inc hl push hl add hl,bc ; Начало данных палитры ld a,l ld (view_image_pals+1),a ld a,h ld (view_image_pals+3),a ld hl,view_image_pals call set_ports ;gPalNum ld b,#01 ; Номер экрана для кого грузить палитру ; ld a,setGfxPalette ; call cliKernel pop hl ld c,(hl) ; Указатель (смещение) на начало данных bitmap inc hl ld b,(hl) inc hl add hl,bc ; Начало данных bitmap ld a,l ld (gfx_copy+1),a ld a,h ld (gfx_copy+3),a ld hl,gfx_copy call set_ports gfx_copy_h2 ld a,0 ld b,#28 out (c),a dec b gfx_copy_t2 ld a,DMA_RAM + DMA_DALGN out (c),a call dma_stats show_gfx call wait_frame gfx_vmode ld a,0 ld bc,VCONFIG out (c),a ld b,high PALSEL gfx_vpal ld a,#08 out (c),a ld b,high TSCONFIG ld a,0 out (c),a ld b,high BORDER gfx_border ld a,0 out (c),a ld a,Gfx_vid_page ld b,high VPAGE out (c),a call pause LD BC,#FADF 3 IN A,(C) ;читаем порт кнопок and 3 cp 3 jr z,3b call pause ld hl,int_main ld (#beff),hl xor a ld bc,GXOFFSL out (c),a inc b out (c),a inc b out (c),a inc b out (c),a ld b,high TSCONFIG ld a,TSU_SEN out (c),a ld hl,all_pals call set_ports ld hl,zx_pals jp set_ports pause ld b,#0a call wait_frame djnz $-3 ret text_view ; main_list_url ld a,download_page call set_page1 text_view_in xor a ld (lmb_click_sw+1),a ld (do_after_load+1),a inc a ld (text_scroll+1),a call set_text_colors xor a call set_page3 call set_Textpage call parse_text ; ld hl,(ix+thread.adress) ; ld ix,#c000;2 ; text line buffer adresses ; ld (ix+0),l ; ld (ix+1),h ld hl,#c000 ld de,window_start_Yl ; text page ld b,window_height*4 ; rows call show_text_line ld hl,window_height*2 ld (text_up_line_adr+1),hl ld a,l ld (text_up+1),a ret parse_text ld de,(ix+thread.adress) ld hl,#c000 ; text line buffer adresses ld b,download_page parse_text0 ld c,0 ld (hl),e inc hl ld (hl),d inc hl ld (hl),b inc hl parse_text1 ld a,(de) or a jr z,parse_text_ex cp #ff jr z,parse_text_ex cp #0d jr nz,parse_text2 inc de inc de jr parse_text4 parse_text2 inc de bit 7,d jr z,parse_text3 ld d,#40 inc b ld a,b push bc call set_page1 pop bc parse_text3 inc c ld a,c cp 80 jr nz,parse_text1 parse_text4 ld (hl),c inc hl jr parse_text0 parse_text_ex xor a ld (hl),a inc hl ld (hl),a ret /* ld de,window_start_Yl ; text page ld bc,(window_height*2)*256+80 ; rows col, chars in row call show_text_line */ show_text_line ld (show_text_line_adr+1),de show_text_line1 ld e,(hl) inc hl ld d,(hl) inc hl ld a,d or e ret z ld a,(hl) inc hl push bc call set_page1 ld c,(hl) inc hl ld a,c or a jr z,show_text_line2 push hl ex de,hl show_text_line_adr ld de,0 ld a,d ld b,0 ldir inc a ld (show_text_line_adr+2),a pop hl show_text_line2 pop bc djnz show_text_line1 ld a,1 ret /* show_text_line ld a,(hl) or a ret z cp #ff ret z cp #0d jr nz,text_view2 inc hl inc hl text_nl ld a,0 or a jr z,text_nl2 inc ix inc ix ld (ix+0),l ld (ix+1),h text_nl2 inc d ld e,0 ld c,80 dec b jr nz,show_text_line ld a,1 or a ret text_view2 ld (de),a inc hl inc de dec c jr z,text_nl jr show_text_line */ text_up ld a,1 or a ret z ld a,download_page call set_page1 ld hl,text_up_copy call set_ports ld hl,window_start_Yl+((window_height-1)*2*256) push hl call clear_text_line pop de ; ld a,1 ; ld (text_nl+1),a text_up_line_adr ld hl,0 add hl,hl add hl,hl ld a,h add #c0 ld h,a push hl ld hl,(text_up_line_adr+1) inc hl inc hl ld (text_up_line_adr+1),hl xor a call set_page3 call set_Textpage_lite pop hl ld bc,2*256+80 ; rows col, chars in row call show_text_line or a ld (text_up+1),a ret text_down ld hl,(text_up_line_adr+1) ld de,window_height*2 or a sbc hl,de jr nz,1f ; cp window_height*2 ; jr nz,1f xor a ret 1 ld hl,(text_up_line_adr+1) dec hl dec hl ld (text_up_line_adr+1),hl or a sbc hl,de add hl,hl add hl,hl ld a,h or #c0 ld h,a push hl ld a,download_page ld (text_up+1),a call set_page1 call text_dma_down xor a call set_page3 call set_Textpage_lite pop hl ld de,window_start_Yl ld b,2 ; rows jp show_text_line text_dma_down ld hl,text_down_copy call set_ports ld d,window_start_Y+window_height*2-4 ld e,window_start_Y+window_height*2-2 ld a,window_height*2-1 td1 exa ld b,high DMASADDRH out (c),d ld b,high DMADADDRH out (c),e dec d dec e ; dec d ; dec e ld b,#27 ld a,DMA_RAM out (c),a call dma_stats exa dec a jr nz,td1 call set_Textpage_lite ld hl,#180 ld a,7 ld (hl),a inc l jr nz,$-2 jp restore_page0 ; in hl - adress: ; http://zxaaa.untergrund.net/get.php?f=DEMO6/a_brief_history_of_vacuum_cleaner_nozzle_attachments.zip parse_url ld a,dl_retries_max ; a fresh target - reset the retry budget ld (dl_retries_left),a ; detect http:// vs https:// (5th char: ':' for http, 's'/'S' for https) push hl ld bc,4 add hl,bc ld a,(hl) pop hl or #20 ; fold to lowercase cp "s" jr z,pu_https pu_http ld a,"T" ld (cmd_conn2site_type+0),a ld a,"C" ld (cmd_conn2site_type+1),a ld a,"P" ld (cmd_conn2site_type+2),a ld de,create_link_suffix_http ld (create_link1+1),de ld de,7 ld (create_link1+4),de jr pu_scheme_done pu_https ld a,"S" ld (cmd_conn2site_type+0),a ld (cmd_conn2site_type+1),a ld a,"L" ld (cmd_conn2site_type+2),a ld de,create_link_suffix_https ld (create_link1+1),de ld de,8 ld (create_link1+4),de pu_scheme_done ld de,cmd_conn2site_adr pu1 ld a,(hl) ; http:// inc hl cp "/" jr nz,pu1 inc hl ; / ld bc,"//" ld (host_url+1),hl call find_copy_char inc hl ld (file_url+1),hl ; ld c,#0d ; call find_copy_char create_link1 ld hl,create_link_suffix_http ld bc,7 ldir ld hl,modem_command ld (hl),"G" inc hl ld (hl),"E" inc hl ld (hl),"T" inc hl ld (hl)," " inc hl ld (hl),"/" inc hl ex hl,de file_url ld hl,0 ld bc,#0d0a call find_copy_char ld hl,http_part1 ld bc,http_part2-http_part1 ldir host_url ld hl,0 ld bc,"//" call find_copy_char ld a,13 ld (de),a inc de ld a,10 ld (de),a inc de ld hl,http_part2 ld bc,http_part3-http_part2 ldir ; dec de ex de,hl ld de,modem_command or a sbc hl,de ; inc hl ld de,url_len ld bc,-1000 call Num1 cp "0" jr z,1f ld (de),a inc de 1 ld bc,-100 call Num1 ld (de),a inc de 1 ld c,-10 call Num1 ld (de),a inc de 1 ld c,-1 call Num1 ld (de),a inc de ld a,#0d ld (de),a inc de ld a,#0a ld (de),a inc de xor a ld (de),a ret Num1: ld a,'0'-1 Num2: inc a add hl,bc jr c,Num2 sbc hl,bc ret find_copy_char ld a,(hl) cp c ret z cp b ret z ld (de),a inc hl inc de jr find_copy_char create_link_suffix_http db #22,",80",13,10,0 create_link_suffix_https db #22,",443",13,10,0 copy_ini ld a,(hl) cp #0d+1 ret c ld (de),a inc hl inc de jr copy_ini cp_ini ld a,(de) or a jr z,cp_ini1 cp (hl) jr nz,error_ini inc hl inc de jr cp_ini cp_ini1 inc de cp_ini2 ld a,(hl) cp #20 ret nz inc hl jr cp_ini2 error_ini ld a,2 out (#fe),a pop hl call set_Textpage ld hl,error_ini_text ld b,1 call zifi_echo ei jr $ ini_db db "SSID:",0 db "password:",0 ini_db_time db "time:",0 error_ini_text db "Error parsing ini file",0 site_list dw download_site_list,gfx_site_list,music_site_list,press_site_list download_site_list db "Games: vtrd.in ",#0d,#0a, "http://ex.vtrd.in/vt/export.php?t=g",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Games: prods.tslabs.info - ZX Enhanced",#0d,#0a, "https://prods.tslabs.info/prods_zifi.php?t=2",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Demos: bbb.retroscene.org",#0d,#0a, "https://bbb.retroscene.org/zxn_zifi.php?t=0",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Classic demos",#0d,#0a, "https://bbb.retroscene.org/zxn_zifi.php?t=1",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Most liked",#0d,#0a, "https://bbb.retroscene.org/zxn_zifi.php?t=2",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Most favorited",#0d,#0a, "https://bbb.retroscene.org/zxn_zifi.php?t=3",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " ZX Enhanced",#0d,#0a, "https://bbb.retroscene.org/zxn_zifi.php?t=4",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Demo Packs: vtrd.in",#0d,#0a, "http://ex.vtrd.in/vt/export.php?t=d",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Demos: prods.tslabs.info - ZX Enhanced",#0d,#0a, "https://prods.tslabs.info/prods_zifi.php?t=1",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Demos: pouet.net - ZX Spectrum",#0d,#0a, "http://zifi.vtrd.in/pouet.php?src=pouet_zx",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Demos: pouet.net - ZX Enhanced",#0d,#0a, "http://zifi.vtrd.in/pouet.php?src=pouet_zxe",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "System: vtrd.in",#0d,#0a, "http://ex.vtrd.in/vt/export.php?t=s",#0d,#0a, save_file,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db #00 gfx_site_list db "Graphics: zxart.ee",#0d,#0a, "http://zxart.ee/zxnet/?a=g",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Most popular",#0d,#0a, "http://zxart.ee/zxnet/?a=g&o=p",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Top-rated",#0d,#0a, "http://zxart.ee/zxnet/?a=g&o=r",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " First places",#0d,#0a, "http://zxart.ee/zxnet/?a=g&o=w",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Top of last year published",#0d,#0a, "http://zxart.ee/zxnet/?a=g&o=y",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " - Multicolour graphic & Timex",#0d,#0a, "http://zxart.ee/zxnet/?a=g&t=multi",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " - Colorful pictures",#0d,#0a, "http://zxart.ee/zxnet/?a=g&t=color",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " - Lowres graphics",#0d,#0a, "http://zxart.ee/zxnet/?a=g&t=lowres",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " - Pixel graphics",#0d,#0a, "http://zxart.ee/zxnet/?a=g&t=pixel",#0d,#0a, view_gfx,download_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db #00 music_site_list db "Music database: zxart.ee",#0d,#0a, "http://zxart.ee/zxnet/?a=m",#0d,#0a, play_music,music_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Most popular",#0d,#0a, "http://zxart.ee/zxnet/?a=m&o=p",#0d,#0a, play_music,music_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Top-rated",#0d,#0a, "http://zxart.ee/zxnet/?a=m&o=r",#0d,#0a, play_music,music_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " First places",#0d,#0a, "http://zxart.ee/zxnet/?a=m&o=w",#0d,#0a, play_music,music_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " Top of last year published",#0d,#0a, "http://zxart.ee/zxnet/?a=m&o=y",#0d,#0a, play_music,music_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db " --+ TurboSound Music +--",#0d,#0a, "http://zxart.ee/zxnet/?a=m&f=ts",#0d,#0a, play_music,music_page,#0d,#0a, " ",#0d,#0a, " ",#0d,#0a db #00 press_site_list db "Hype: hype.retroscene.org",#0d,#0a, "http://zifi.vtrd.in/get.php?src=hype",#0d,#0a, view_text,download_page, #0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Emags: vtrd.in", #0d,#0a, "http://ex.vtrd.in/vt/export.php?t=p",#0d,#0a, save_file,download_page, #0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "Z80 Telegram Log", #0d,#0a, "http://zifi.vtrd.in/tlg.php",#0d,#0a, view_text,download_page, #0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "IRC Logs", #0d,#0a, "http://irclog.dimkam.ru/zifi.php?src=z80",#0d,#0a, view_downloaded_list,download_page, #0d,#0a, " ",#0d,#0a, " ",#0d,#0a db "RSS Channels", #0d,#0a, "http://irclog.dimkam.ru/zrss.php",#0d,#0a, view_text,download_page, #0d,#0a, " ",#0d,#0a, " ",#0d,#0a db #00 hl_menu_src db #1a,0 db #1b,0 hl_menu_desc db #1d,0 db #1e,0 db #1c,highlight_menu_page db #1f,Vid_page db #26,88/2-1 db #28,16-1 db #27,DMA_RAM + DMA_DALGN +DMA_ASZ db #ff hl_menu_adr dw 0,#c000+88 dw highlight_size,#e000+88 dw highlight_size*2,#c000+88+88+8 dw highlight_size*3,#e000+88+88+8 sites_list dec a ; highlight menu gfx push af add a,a add a,a ld l,a ld h,0 ld de,hl_menu_adr add hl,de ld de,hl_menu_src+1 ld b,4 1 ld a,(hl) ld (de),a inc hl inc de inc de djnz 1b ld hl,menu_copy call set_ports ld hl,hl_menu_src call set_ports ld a,download_page ld (load_ram_page+1),a xor a ld (scroll_sw+1),a ; switch off mouse scrolls call set_text_colors ; clear text screen pop af add a,a ld l,a ld h,0 ld de,site_list add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a push hl ld de,link_adreses call parse_get ld a,c ld (all_lines_counter+1),a ld (sum_list_lines+1),a ld ix,link_adreses ld b,a dec b pop hl ld de,window_start_Yl 2 push bc call show_line_get_buffer pop bc djnz 2b xor a ld (sites_sw+1),a ld (click_offset+1),a ; GYOFFSL =0 ld (show_now_play_link+1),a ld a,view_downloaded_list ld (do_after_load+1),a ret set_text_colors call off_int_dma call set_Textpage ld hl,0 ld (#0000),hl ld hl,clr_text_screen call set_ports ld hl,#0080 set_text_colors_color ld a,#07 1 ld (hl),a inc l jr nz,1b ld l,#80 inc h bit 5,h jr z,1b jp on_int_dma create_link_list ld a,1 ld (scroll_sw+1),a xor a ld (text_scroll+1),a ld (link_num+1),a ld (click_offset+1),a ld hl,(ix+thread.adress) push hl ld de,link_adreses call parse_get ld a,c ld (sum_list_lines+1),a cp window_height ; check num of prods < window list for scrolls jr nc,1f xor a jr 2f 1 sub window_height 2 ld (all_lines_counter+1),a ld a,c call set_text_colors ld ix,link_adreses pop hl ld de,window_start_Yl ld b,window_height 2 push bc call show_line_get_buffer pop bc djnz 2b do_after_link_list ld a,0 ; действие после загрузки ld (do_after_load+1),a ld c,0 cp play_music jr nz,1f ld c,1 1 ld a,c ld (autoplay+1),a loadpage_after_link_list ld a,0 ; страница для загрузки прода данного раздела ld (load_ram_page+1),a xor a ld (load_sw+1),a ret find_0d0a ld hl,get_buffer find_0d0a_hl ss_cm4 ld a,#0d ss_cm3 cpi jr nz,ss_cm3 ld a,#0a cpi jr nz,ss_cm4 ld a,#0d cpi jr nz,ss_cm4 ld a,#0a cpi jr nz,ss_cm4 ret /* ld hl,get_buffer ld de,link_adreses ; 0 - number of link ; 1,2 - adress of link name ; 3,4 - adress of link url ; 5 - count of chars date+author lenght */ list_up text_scroll ld a,0 or a jp nz,text_up link_num ld a,0 all_lines_counter cp 0 ret z inc a ld (link_num+1),a add window_height-1 call calc_link_num ld hl,text_up_copy call set_ports ld hl,window_start_Yl+((window_height-1)*2*256) push hl call clear_text_line pop de ld l,(ix+1) ld h,(ix+2) call show_line_get_buffer ld a,1 ret calc_link_num ld l,a ld h,0 add hl,hl push hl add hl,hl pop de add hl,de ex de,hl ld ix,link_adreses add ix,de ret list_down ld a,(text_scroll+1) or a jp nz,text_down ld a,(link_num+1) or a ret z dec a ld (link_num+1),a call calc_link_num call text_dma_down /* ld hl,get_buffer ld de,link_adreses ; 0 - number of link ; 1,2 - adress of link name ; 3,4 - adress of link url ; 5 - count of chars date+author lenght */ down_link ld hl,window_start_Yl push hl call clear_text_line pop de ld l,(ix+1) ld h,(ix+2) call show_line_get_buffer ld a,1 ret ; ------- page 0 set_Textpage_lite ld a,Text_page jr set_page0_lite set_Textpage ld a,Text_page jr set_page0 set_page0 ld (restore_page0+1),a set_page0_lite ld bc,PAGE0 out (c),a ret restore_page0 ld a,0 jr set_page0_lite ; ------- page 1 set_buffer_page ld a,list_ram_page set_page1 ld (restore_page1+1),a set_page1_lite ld bc,PAGE1 out (c),a ret restore_page1 ld a,0 jr set_page1_lite ; ------- page 3 set_page3 ld (restore_page3+1),a set_page3_lite ld bc,PAGE3 out (c),a ret restore_page3 ld a,0 jr set_page3_lite set_music_pages ld a,music_page call set_page0 inc a call set_page1 ld a,music_players_page jp set_page3 restore_music_pages xor a call set_page0 ld a,list_ram_page jp set_page1 /* set_music_pages ld a,(restore_page0+1) ld (rest_p0+1),a ld a,(restore_page1+1) ld (rest_p1+1),a ld a,(restore_page3+1) ld (rest_p3+1),a ld a,music_page call set_page0 inc a call set_page1 ld a,music_players_page jp set_page3 restore_music_pages rest_p0 ld a,0 call set_page0 rest_p3 ld a,0 call set_page3 rest_p1 ld a,list_ram_page jp set_page1 */ set_music_pages_lite ld a,music_page call set_page0_lite inc a call set_page1_lite ld a,music_players_page jp set_page3_lite restore_music_pages_lite call restore_page0 call restore_page1 jp restore_page3 /* ld hl,get_buffer ld de,link_adreses ; 0 - number of link ; 1,2 - adress of link name ; 3,4 - adress of link url ; 5 - type of a site_list */ parse_get call set_buffer_page ld c,1 parse_get1 ld a,(hl) cp #0a jr c,parse_get_ex cp #0d jr z,parse_get_ex ld a,c ld (de),a ; number of link inc de call save_parsed ; adress of link name call scan_0d call save_parsed ; adress of link url call scan_0d ; date adr call scan_0d ; author call scan_0d ; city inc de call scan_0d ; next record inc c jr parse_get1 parse_get_ex ld a,c ld (de),a ; number of link inc de save_parsed ld a,l ld (de),a ; adress of link adress inc de ld a,h ld (de),a inc de ret scan_0d ld a,(hl) inc hl cp #0a jr nz,scan_0d ; inc hl ; #0a ret clear_text_line ld d,h inc d ld e,l call set_Textpage_lite xor a ld b,#80 1 ld (hl),a ld (de),a inc l inc e djnz 1b jp restore_page0 show_line_get_buffer call set_Textpage_lite ld a,list_ram_page call set_page1_lite ld a,(hl) ; end of list or a jp z,slgb_ex push de ld a,6+8 call drawString ; name call scan_0d ; propusk: links ld a,(hl) cp #0b ; пропуск всех пустых строк сразу (для списка ссылок раздела и поиска) jr nc,show_get_buf4 or a jr z,show_get_buffer_ex call scan_0d call scan_0d call scan_0d jr show_get_buffer_ex+3 ; echo $x++.'.'.$lx['title']."\r\n ; $lx['url']."\r\n" ; $lx['year']."\r\n". ; substr($authors,0,-1)."\r\n"; ; addslashes($lx['city'])."\r\n"; show_get_buf4 ld (show_year_adr+1),hl ; store "year" call scan_0d ld (show_author_adr+1),hl ; store "authors" call scan_0d ; ld (show_city_adr+1),hl ; store "city" call scan_0d ld (show_get_buffer_ex+1),hl show_author_adr ld hl,0 ld a,(hl) ; check "by author" cp #0e jr c,1f push hl ld hl,by_db ; by ld a,4 call drawString pop hl ld a,4+8 ; authors call drawString 1 show_year_adr ld hl,0 ; year ld a,(hl) ; check "year" cp #0e jr c,1f ld a,"," ld (de),a inc de inc de ld a,4 call drawString 1 show_get_buffer_ex ld hl,0 ld de,6 add ix,de pop de inc d inc d slgb_ex call restore_page0 jp restore_page1 by_db db " by ",#0a drawString ; de: screen adress in tiles ; hl: string ld (char_color+1),a ld a, 80 ld (charz+1), a push de exx pop hl set 7,l exx dStr1 ld a,(hl) cp #0a jr z,dStr2 cp #0d jr z,dStr3 ld (de),a inc e exx char_color ld (hl),0 inc l exx inc hl charz ld a, 0 dec a ret z ld (charz+1), a jr dStr1 dStr3 inc hl dStr2 inc hl ; #0a ret wait_frame ld a,(frame+1) or a jr z,wait_frame xor a ld (frame+1),a ret int_gfx_view push af,hl,de,bc,ix ld a,(frame+1) inc a ld (frame+1),a ld a,(music_sw+1) or a call nz,pt_play pop ix,bc,de,hl,af ei ret int_main push af,hl,de,bc,ix,iy ; Line 0 is in vertical blanking. Restore the single black border here, ; never during the text/graphics transition lines. ld a,GFX_BORDER ld bc,BORDER out (c),a exx push hl,de,bc exx exa push af exa xor a ld b,high GYOFFSL out (c),a inc b out (c),a call set_256c_mode frame ld a,0 inc a ld (frame+1),a ; Arm the text-mode raster chain before potentially long mouse/list ; processing. A CPU screen copy can take longer than the 84 raster lines ; before the text area; delaying this setup exposes the 256c page for one ; frame. ld hl,56+4*8-4 ld bc,VSINTL out (c),l ld b,high VSINTH out (c),h ld hl,int_text_cor ld (#beff),hl ei save_mode ld a,1 or a jr z,int_ex_regs mouse_sw ld a,1 or a call nz,mouse_proc link_highlight ld a,0 or a call nz,link_highlight_view jr int_ex_regs int_ex ld bc,VSINTL out (c),l ld b,high VSINTH out (c),h ex de,hl ld (#beff),hl int_ex_regs exa pop af exa exx pop bc,de,hl exx pop iy,ix,bc,de,hl,af ei ret int_text_cor push af push hl push bc ld hl,56+4*8 ld bc,VSINTL out (c),l ld b,high VSINTH out (c),h ld hl,int_text_on ld (#beff),hl xor a ld (int_text_cor_ex+1),a ei int_text_cor_ex ld a,0 or a jr z,int_text_cor_ex pop bc pop hl pop af ret int_text_on push af,hl,de,bc ; VCONFIG, VPAGE and GYOFFS are latched on the next line start; ; program them first. BORDER is intentionally not touched here. ld a,(click_offset+1) ld bc,GYOFFSL out (c),a ld b,high VCONFIG ld a,VID_TEXT+VID_320X240 out (c),a ld b,high VPAGE ld a,Text_page out (c),a ld a,#3f ld (int_text_cor_ex+1),a push ix,iy exx push hl,de,bc exx exa push af exa ld hl,47+240-1-2 ld de,int_text_ofcor jp int_ex int_text_ofcor push af push hl push bc ld hl,47+240 ld bc,VSINTL out (c),l ld b,high VSINTH out (c),h ld hl,int_text_off ld (#beff),hl xor a ld (int_text_ofcor_ex+1),a ei int_text_ofcor_ex ld a,0 or a jr z,int_text_ofcor_ex pop bc pop hl pop af ret int_text_off push af,hl,de,bc ; The mode registers are latched on the next line start. BORDER is ; deliberately unchanged here: it must stay constant over the frame. call set_256c_mode ld hl,47+240 ; was 47+240-1 - bottom panel sat a couple pixels too low ld b,high GYOFFSL out (c),l inc b out (c),h push ix,iy exx push hl,de,bc exx exa push af exa music_sw ld a,0 or a call nz,pt_play ld a,(save_mode+1) or a jr z,int_ex3 enter_search_sw ld a,0 or a call nz,enter_search int_ex3 ld hl,0 ld de,int_main ld a,1 ld (int_text_ofcor_ex+1),a jp int_ex pt_play call set_music_pages_lite call music_player_play jp show_now_play_link pt_play_restore_pages call restore_music_pages_lite ld a,(analyzer_active) or a ret z ld a,Vid_page+9 jp set_page3_lite show_now_play_link ld a,0 or a jr z,autoplay ld a,(current_list_page+1) mus_link_page cp 0 jr nz,autoplay show_now_play_cnt ld a,0 inc a and 7 ld (show_now_play_cnt+1),a jr nz,autoplay call set_Textpage_lite ld a,(link_num+1) ld c,a ld a,(autoplay_num+1) sub c cp #0f jr nc,autoplay add a,a inc a ld h,a ld l,#80 ld b,80 1 ld a,(hl) xor #08 ld (hl),a inc l djnz 1b autoplay ld a,1 or a jr z,pt_play_ex ld a,(music_setup_vars) bit 7,a jr z,pt_play_ex ; loop is passed ld a,(sum_list_lines+1) dec a ld c,a autoplay_num ld a,0 inc a cp c jr c,1f ld a,1 1 ld (autoplay_num+1),a call calc_link_num ld a,list_ram_page call set_page1 ld h,(ix+4) ld l,(ix+3) call parse_url ld a,1 ld (load_sw+1),a pt_play_ex jp pt_play_restore_pages ; autoplay may have re-pointed page1 itself above - restore again /* SETUP DB 0 ;set bit0, if you want to play without looping ;(optional); ;set bit1 for PT2 and reset for PT3 before ;calling INIT; ;bits2-3: %00-ABC, %01-ACB, %10-BAC (optional); ;bits4-5: %00-no TS, %01-2 modules TS, %10- ;autodetect PT3 TS-format by AlCo (PT 3.7+); ;Remark: old PT3 TS-format by AlCo (PT 3.6) is not ;documented and must be converted to new standard. ;bit6 is set each time, when loop point of 2nd TS ;module is passed (optional). ;bit7 is set each time, when loop point of 1st TS ;or of single module is passed (optional). */ set_256c_mode ld bc,VCONFIG ld a,VID_256C+VID_320X240 ;VID_NOGFX+ out (c),a ld b,high VPAGE ld a,Vid_page out (c),a ; TSCONFIG and PALSEL NOT touched here -- both written exactly ; once at program start instead (see "start"). This procedure ; runs from the raster interrupt handlers (int_main, ; int_text_off) every single frame; the sibling fork's own ; author confirmed writing PALSEL mid-frame is the real cause ; of the cursor-cutoff bug (TSCONFIG has the same hazard: ; re-asserting the sprite engine mid-scanline blanks the ; cursor sprite on that line). ret link_highlight_view ld a,#0a dec a ld (link_highlight_view+1),a ret nz 1 ld a,(link_highlight+1) ld d,a ld a,Text_page call set_page3_lite ld e,#80 ld hl,highlight_colors_buff ld bc,80 ldir xor a ld (link_highlight+1),a ld a,#0a ld (link_highlight_view+1),a jp restore_page3 music_analizator ld a,1 ld (analyzer_active),a ld a,Vid_page+9 call set_page3_lite ld hl,0 ld (analizator_screen_adr),hl ld hl,clr_analizator call set_ports ; wait for the fill before drawing over it ld hl,ay_volume push hl ld b,3 2 ld a,(hl) or a jr z,1f dec (hl) 1 inc hl djnz 2b ld hl,ay_volume ld de,#0308 ma1 LD BC, #FFFD OUT (C), e IN A, (C) and #0f cp (hl) jr c,1f ld (hl),a 1 inc hl inc e dec d jr nz,ma1 pop de ld hl,analizator_screen_adr ld c,3 ma3 ld a,(de) inc a inc de add a,a ld b,a add #40 ma2 ld (hl),a inc hl djnz ma2 ld l,low analizator_screen_adr inc h inc h dec c jr nz,ma3 xor a ld (analyzer_active),a jp restore_page3 ay_volume ds 3 analyzer_active db 0 /* 1 D0 - левая кнопка 2 D1 - правая кнопка 4 D2 - средняя кнопка #10-#f0 D4-D7 - wheel */ mouse_buttons scroll_sw ld a,0 or a jr z,lmb_old wheel_old ld c,#f0 ld a,(mouse_button) cpl and #f0 cp c jr z,lmb_old ld (wheel_old+1),a sub c jp m,list_up jp nc,list_down jp p,list_down jp list_up /* jp m,list_down jp nc,list_up jp p,list_up jp list_down */ lmb_wait equ #c lmb_old ld a,(mouse_button) cpl and 1 cp 1 ; lmb pressed jp nz,lmb_release lmb_counter ld a,0 inc a cp lmb_wait jr z,drag_start jr nc,lmb_drag ld (lmb_counter+1),a ret drag_start ld (lmb_counter+1),a ld a,(mouse_y) ld (drag_start_pos+1),a ; begin pos of drag ld (lmb_line_cnt+1),a ld (lmb_old_line_cnt+1),a ret lmb_drag ld a,1 or a ret z ld a,(scroll_sw+1) or a ret z lmb_line_cnt ld e,0 ; current point of prirost + y_coord lmb_old_line_cnt ld d,0 ; old point of prirost + y_coord ld a,(mouse_y) drag_start_pos sub 0 ; begin pos of drag ld l,a ld h,high mouse_step ld a,e add (hl) ; prirost ld e,a ld (lmb_line_cnt+1),a sub d jp m,ld10 cp #10 jr c,ld2 jr ld01 ld10 cp #f0 jr nc,ld2 neg sub #10 add e ; ld a,e ld (lmb_old_line_cnt+1),a call list_down jr nz,ld2 ld (lmb_drag+1),a ld (click_offset+1),a jr ex_no_offset ; + ld01 ld a,e ld (lmb_old_line_cnt+1),a call list_up jr nz,ld2 xor a ld (lmb_drag+1),a ld (click_offset+1),a jr ex_no_offset ld2 ld a,(lmb_old_line_cnt+1) ld c,a ld a,(lmb_line_cnt+1) sub c and #0f ld (click_offset+1),a ex_no_offset ld a,#02 jp lmb_ex2 lmb_release ld a,(lmb_counter+1) or a jp z,lmb_ex cp lmb_wait-1 jp nc,lmb_ex ld a,(mouse_y) cp 4*8 jp c,menu_click cp 240-8 jp nc,status_click lmb_click_sw ld a,1 or a jp z,lmb_ex ld a,(mouse_y) sub 4*8 ; Y offset from menu click_offset add 0 ; mouse Y offset 0-15 srl a srl a srl a srl a ld c,a sum_list_lines ld a,0 dec a ld b,a cp c jp z,lmb_ex jp c,lmb_ex ld a,c ; save txt colors buffer push bc add a,a inc a add #c0 ld (link_highlight+1),a ld h,a ld a,Text_page call set_page3_lite ld l,#80 ld de,highlight_colors_buff ld bc,80 ldir ld l,#80 ld a,#0f 1 ld (hl),a inc l jr nz,1b call restore_page3 pop bc ld a,(link_num+1) add c cp b ; all links counter jp z,lmb_ex ld c,a or a jr nz,1f ld a,(do_after_load+1) cp view_downloaded_list jr z,1f ld a,1 ; start enter search word ld (enter_search_sw+1),a call set_Textpage_lite ld hl,search_textpage_adr ld (search_input_adress+1),hl ld a,"_" ld (hl),a inc l xor a ld b,#40 ld (hl),a inc l djnz $-2 ld hl,highlight_colors_buff+7 ld b,#40 ld a,7 2 ld (hl),a inc l djnz 2b jp lmb_ex 1 ld a,(do_after_load+1) cp play_music jr nz,1f ld a,c ld (autoplay_num+1),a ld a,(current_list_page+1) ld (mus_link_page+1),a ld (show_now_play_link+1),a 1 ld a,c call calc_link_num ld a,list_ram_page call set_page1 ld h,(ix+4) ld l,(ix+3) ld (main_list_url+1),hl ld a,(do_after_link_list+1) ; проверка на текст и установка нового пейджинга cp view_text jr nz,1f call parse_url jr main_list_url ; paging for text files 1 push hl cp save_file ; проверка на файло для закачки jr nz,not_unzip ; проверка на zip ld de,zip_url_buffer_data ld bc,#0d0a call find_copy_char ld a,#0d ld (de),a ld hl,zip_url_buffer not_unzip call parse_url pop hl call scan_0d ld a,(hl) ; проверка на клик по списку сайтов в разделе cp #0d jr nc,1f ld (do_after_link_list+1),a ; тип действия для данного сайта inc hl ld a,(hl) ; пага загрузки для данного сайта ld (loadpage_after_link_list+1),a ld h,(ix+4) ld l,(ix+3) ld (main_site_url+1),hl main_list_url ld hl,0 ld (current_list_url+1),hl ld bc,#0d0d ld de,current_paging_url call find_copy_char ex de,hl ld (hl),"&" inc hl ld (hl),"p" ; page num inc hl ld (hl),"=" inc hl ld (current_paging_page+1),hl ld (hl),"0" inc hl ld (hl),"2" inc hl ld (hl),#0d ld a,start_paging_page ld (current_list_page+1),a 1 ld a,1 ld (load_sw+1),a lmb_ex ld a,1 ld (lmb_drag+1),a dec a ld (lmb_counter+1),a lmb_ex2 ld (mouse_spr+4),a ret status_click ld hl,(current_list_url+1) ld a,h or l or a jr z,lmb_ex ; url with link list not loaded call mouse_x_div8 cp #10 jr c,lmb_ex cp #12 jr c,cancel_download cp #19 jp z,music_play cp #1a jp z,music_stop ld c,a ld a,(load_sw+1) ; 1-load now, check for download now or a jr nz,lmb_ex ld a,c cp #21 jp z,first_page cp #22 jp z,page_back cp #27 jp z,page_forward jr lmb_ex cancel_download ld a,1 if cable_zifi=1 ld (uart.cable_cancel_download+1),a else ld (wifi_cancel_download+1),a endif jr lmb_ex first_page current_list_url ld hl,0 call parse_url ld a,start_paging_page ld (current_list_page+1),a paging_page_ex ld a,1 ld (load_sw+1),a ld a,view_downloaded_list ld (do_after_load+1),a ld a,download_page ld (load_ram_page+1),a jp lmb_ex page_back ld a,(current_list_page+1) dec a cp start_paging_page-1 ; p=1 jp z,lmb_ex ld (current_list_page+1),a jr current_list_page_count page_forward current_list_page ld a,0 inc a ld (current_list_page+1),a current_list_page_count ld l,a ld h,0 current_paging_page ld de,0 ld bc,-10 call Num1 ld (de),a inc de ld c,-1 call Num1 ld (de),a ld hl,current_paging_url call parse_url jr paging_page_ex music_loaded ld a,1 ld (music_play+1),a ld a,music_skip_chain_max ; a track made it through - reset the dead-track counter ld (music_skip_chain_left),a xor a ld (is_music_play+1),a ld hl,(ix+thread.adress) ; res 7,h res 6,h ld (music_adr+1),hl music_play ld a,0 ; music is loaded? or a jp z,lmb_ex is_music_play ld a,0 ; music is inited, check pause/play or a jr nz,pause_music ld (do_start_music+1),a jp lmb_ex music_stop ld a,(music_play+1) or a jp z,lmb_ex ld (do_init_music+1),a jp lmb_ex music_init call set_music_pages music_adr ld hl,0 call music_player_init ; call music_player_mute call restore_music_pages ; ld hl,SETUP ; res 0,(hl) ; loop mode ld a,1 ld (music_sw+1),a ld (is_music_play+1),a ld (do_start_music+1),a ret pause_music ld a,0 cpl ld (pause_music+1),a or a jr nz,pause_music1 ld a,1 ld (music_sw+1),a jp lmb_ex pause_music1 xor a ld (music_sw+1),a call set_music_pages call music_player_mute call restore_music_pages jp lmb_ex menu_click ld a,(zifi_ready) or a jp z,lmb_ex ; Wi-Fi/NTP/download directory initialization still running ld a,(mouse_y) srl a srl a srl a srl a ld c,a ld a,(load_sw+1) ; 1-load now, check for download now or a jp nz,lmb_ex ld a,c call mouse_x_div8 cp 11 jp c,lmb_ex cp 29 jp nc,lmb_ex ; empty left/right menu cp 21 ; download / graphics jr c,menu_first cp 23 ; music/press jp c,lmb_ex ; subdivider menu_two ld a,c or a jr nz,menu_two_gfx ld a,music_sites menu_sw ld (sites_sw+1),a ld a,download_page ld (load_ram_page+1),a xor a ld (link_num+1),a inc a ld (lmb_click_sw+1),a xor a ld (do_after_link_list+1),a ; тип действия для данного сайта jp lmb_ex menu_two_gfx ld a,press_sites jr menu_sw menu_first ld a,c or a jr nz,menu_first_music ld a,download_sites jr menu_sw menu_first_music ld a,gfx_sites jr menu_sw mouse_x_div8 ld hl,(mouse_x) or a srl h rr l srl h rr l srl h rr l ld a,l ret key_wait equ #07 enter_search ld a,1 dec a ld (enter_search+1),a ret nz inc a ld (enter_search+1),a call Read_Keyboard or a ret z cp enter jr nz,es1 xor a ; press ENTER ld (enter_search_sw+1),a ld hl,search_textpage_adr ld (search_input_adress+1),hl main_site_url ld hl,0 ld bc,#0d0d ld de,search_url push de call find_copy_char ex de,hl ld (hl),"&" inc hl ld (hl),"s" ; page num inc hl ld (hl),"=" inc hl ex de,hl ld hl,search_textpage_adr call copy_ini dec de ld a,#0d ld (de),a pop hl ld (main_list_url+1),hl ld a,view_downloaded_list ld (do_after_load+1),a ld a,download_page; list_ram_page ld (load_ram_page+1),a call parse_url jp main_list_url ; готовим строку поиска es1 cp del jr nz,es2 ld hl,(search_input_adress+1) ld a," " ld (hl),a dec l ld a,l cp #08 ; начало строки поиска - 1 jr nc,search_input_adress2 ld hl,search_textpage_adr jr search_input_adress2 es2 cp #20 ret c push af call set_Textpage_lite pop af search_input_adress ld hl,search_textpage_adr ld (hl),a inc l ld a,l cp #08+32 ret z search_input_adress2 ld (search_input_adress+1),hl search_input_adress3 ld a,"_" ld (hl),a ld a,key_wait ld (enter_search+1),a ret mouse_proc call mouse_buttons call mouse_pos ld a,(mouse_y) ld (mouse_spr),a ; Y cp 8 jr nc,mouse_margin_y ld de,#fff8 ld b,d ld c,e jr mouse_mrg_y_top mouse_margin_y cp 240-16 jr c,mouse_margin_y_ex ld de,#0118 ld bc,#0008 mouse_mrg_y_top ld hl,0 add hl,bc ld a,h cp d jr nz,mouse_mrg_y_top2 ld a,l cp e jr z,mouse_margin_y_ex mouse_mrg_y_top2 ld (mouse_mrg_y_top+1),hl mouse_margin_y_ex ld hl,(mouse_x) ld bc,8 sub hl,bc jr nc,mouse_margin_x ld bc,#f8f8 jr mouse_mrg_x_top mouse_margin_x ld hl,(mouse_x) ld bc,320-16 sub hl,bc jr c,mouse_margin_x_ex ld bc,#c808 mouse_mrg_x_top ld a,0 add c cp b jr z,mouse_margin_x_ex ld (mouse_mrg_x_top+1),a mouse_margin_x_ex ld hl,(mouse_x) ld a,l ld (mouse_spr+2),a ; X ld a,(mouse_spr+3) and #fe or h ld (mouse_spr+3),a mouse_show_sw ld a,0 or a ret nz ld hl,sprites jp set_ports /* D0 - левая кнопка D1 - правая кнопка D2 - средняя кнопка D4-D7 - wheel Standard Kempston Mouse #FADF - buttons #FBDF - X coord #FFDF - Y coord */ mouse_pos LD BC,#FADF IN A,(C) ;читаем порт кнопок key_in ld (mouse_button),a LD BC,#FBDF IN A,(C) MOUSE11 LD d,0 LD (MOUSE11+1),A sub d CALL NZ,MOUSE_X_vector LD B,#FF IN A,(C) ; call key_scan MOUSE12 LD D,0 LD (MOUSE12+1),A SUB D CALL NZ,MOUSE_Y_vector RET MOUSE_X_vector JP M,MOUSE35 ; Sign Negative (M) ld e,a ld d,0 ld hl,(mouse_x) add hl,de ld (mouse_x),hl ld de,320 sub hl,de ret c 1 ld hl,320-1 jr 1f MOUSE35 neg ld e,a ld d,0 or a ld hl,(mouse_x) sub hl,de jr nc,1f ld hl,0 1 ld (mouse_x),hl RET MOUSE_Y_vector JP M,MOUSE45 ld e,a ld d,0 or a ld hl,(mouse_y) sub hl,de jr nc,2f ld hl,0 2 ld (mouse_y),hl ret MOUSE45 neg ld e,a ld d,0 ld hl,(mouse_y) add hl,de ld (mouse_y),hl ld de,240 sub hl,de ret c ld hl,240-1 jr 2b koorp ld a,c and #18 ; or #c0 ld h,a ld a,c and #07 rrca rrca rrca add a,b ld l,a ret ; 14 байт, 53 такта im2_init xor a ld bc,HSINT out (c),a ld bc,VSINTL out (c),a ld bc,VSINTH out (c),a ld e,4 ld b,high GXOFFSL call fill_ports ld e,7 ld b,high T0XOFFSL call fill_ports call spr_off ld a,#be ld i,a ld hl,int_gfx_view ld (#beff),hl im 2 ret fill_ports out (c),a inc b dec e jr nz,$-4 ret Read_Keyboard LD HL,Keyboard_Map ; Point HL at the keyboard list LD D,8 ; This is the number of ports (rows) to check LD C,#FE ; C is always FEh for reading keyboard ports Read_Keyboard_0 LD B,(HL) ; Get the keyboard port address from table INC HL ; Increment to list of keys IN A,(C) ; Read the row of keys in AND #1F ; We are only interested in the first five bits LD E,5 ; This is the number of keys in the row Read_Keyboard_1 SRL A ; Shift A right; bit 0 sets carry bit JR NC,Read_Keyboard_2 ; If the bit is 0, we've found our key INC HL ; Go to next table address DEC E ; Decrement key loop counter JR NZ,Read_Keyboard_1 ; Loop around until this row finished DEC D ; Decrement row loop counter JR NZ,Read_Keyboard_0 ; Loop around until we are done AND A ; Clear A (no key found) RET Read_Keyboard_2 ld a,(hl) cp "0" ret nz ld bc,#fefe in a,(c) bit 0,a ld a,(hl) ret nz ld a,del RET /* ld d,0 ld bc,#fefe ; check for CAPS SHIFT in a,(c) bit 4,a jr nz,1f ld d,#30 1 ld a,d add e */ Keyboard_Map: DB #FB,"q","w","e","r","t" DB #F7,"1","2","3","4","5" DB #EF,"0","9","8","7","6" DB #DF,"p","o","i","u","y" DB #BF,enter,"l","k","j","h" DB #7F," ",sym,"m","n","b" DB #FD,"a","s","d","f","g" DB #FE,caps,"z","x","c","v" caps equ #01 sym equ #02 enter equ #0d del equ #0c /* Рассмотрим рисунок клавиатуры: N:БИТA| 0| 1| 2| 3| 4| 4| 3| 2| 1| 0| ------+--+--+--+--+--+--+--+--+--+--+ N_ N_ 3 | 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| 4 П П +--+--+--+--+--+--+--+--+--+--+ О О 2 | Q| W| E| R| T| Y| U| I| O| P| 5 Л Л +--+--+--+--+--+--+--+--+--+--+ У У 1 | A| S| D| F| G| H| J| K| L|ENT 6 Р Р +--+--+--+--+--+--+--+--+--+--+ Я Я 0 |CS| Z| X| C| V| B| N| M|SS|SPC 7 Д Д +--+--+--+--+--+--+--+--+--+--+ А А 3-#F7 4-#EF 2-#FB 5-#DF 1-#FD 6-#BF 0-#FE 7-#7F */ fill_menu push bc fill_menu1 ld (hl),e inc l ld (hl),d inc l djnz fill_menu1 inc h ld l,b pop bc dec c jr nz,fill_menu ret all_init di ld bc,MEMCONFIG ld a,%00001110 out (c),a xor a call set_page0 call im2_init call mouse_pos ld bc,PAGE3 ld a,Vid_page out (c),a ld hl,#0000 ;1111 - white ld (#c000),hl ld hl,init_ts call set_ports ld hl,all_pals call set_ports ld hl,splash_copy jp set_ports gfx_init ld hl,cursor_copy call set_ports ld hl,menu_copy call set_ports ld hl,status_copy call set_ports ld hl,mouse_step xor a 1 ld b,4 ld (hl),a inc l djnz $-2 ld (hl),a inc a 2 inc l bit 7,l jr z,1b ld l,#80 ld d,h ld e,#80 3 ld a,(hl) neg ld (de),a inc e dec l jr nz,3b xor a ld (lmb_click_sw+1),a ret init_ts db #20,6 db high BORDER,GFX_BORDER ; border db high SGPAGE, Sprite_page db high CacheConfig,#0c ; cache for #8000 - #c000 clr_gfx256_screen defb #1a,0 ; defb #1b,0 ; defb #1c,Vid_page ; defb #1d,0 ; defb #1e,0 ; defb #1f,Vid_page ; defb #26,#ff ; defb #28,#ff ; defb #27,%00000100 db #ff clr_load_mem defb #1a,0 ; defb #1b,0 ; clr_load_mem1 defb #1c,0 ; defb #1d,0 ; defb #1e,0 ; clr_load_mem2 defb #1f,0 ; defb #26,#ff ; defb #28,32-1 ; defb #27,%00000100 db #ff gfx_copy db #1a,0 db #1b,0 ;#0210 - данные битмап db #1c,download_page db #1d,0 db #1e,0 db #1f,Gfx_vid_page gfx_copy_w db high DMALEN,0 gfx_copy_h db high DMANUM,0 gfx_copy_type db #27,DMA_RAM + DMA_DALGN;+DMA_ASZ db #ff view_image_pals db #1a,0 db #1b,0 db #1c,download_page db #1d,0 view_image_pals_vpal_adr db #1e,1 db #1f,0 view_image_pals_vpal db #26,#1f db #28,0 db #27,#84 db #ff clr_gfx_screen defb #1a,0 ; defb #1b,0 ; defb #1c,Gfx_vid_page ; defb #1d,0 ; defb #1e,0 ; defb #1f,Gfx_vid_page ; defb #26,#ff ; defb #28,#ff ; defb #27,%00000100 db #ff clr_analizator defb #1a,low analizator_screen_adr ; defb #1b,high analizator_screen_adr ; defb #1c,Vid_page+9 defb #1d,low analizator_screen_adr ; defb #1e,high analizator_screen_adr ; defb #1f,Vid_page+9 defb high DMALEN ,#f ; defb high DMANUM,3-1 ; defb #27,DMA_FILL+DMA_ASZ+DMA_DALGN db #ff clr_text_screen defb #1a,0 ; defb #1b,0 ; defb #1c,Text_page ; defb #1d,0 ; defb #1e,0 ; defb #1f,Text_page ; defb #26,#ff ; defb #28,32-1 ; defb #27,%00000100 db #ff link_page_copy db #1a,0 db #1b,0 db #1c,download_page db #1d,0 db #1e,0 db #1f,list_ram_page db #26,#ff db #28,32-1 db #27,DMA_RAM db #ff cursor_copy db #1a,low cursor_adr db #1b,high cursor_adr db #1c,cursor_page db #1d,0 db #1e,0 db #1f,Sprite_page db #26,32/4-1 db #28,16-1 db #27,DMA_RAM + DMA_DALGN db #ff menu_copy db #1a,0 db #1b,0 db #1c,menu_gfx_page db #1d,0 db #1e,0 db #1f,Vid_page db #26,320/2-1 db #28,32-1 db #27,DMA_RAM + DMA_DALGN +DMA_ASZ db #ff splash_copy db #1a,0 db #1b,0 db #1c,splash_gfx_page db #1d,40 db #1e,0 db #1f,Vid_page+2 db #26,240/2-1 db #28,109-1 db #27,DMA_RAM + DMA_DALGN +DMA_ASZ db #ff status_copy db #1a,0 db #1b,#28 db #1c,menu_gfx_page db #1d,0 db #1e,#3e-2 db #1f,Vid_page+8 db #26,320/2-1 db #28,9-1 db #27,DMA_RAM + DMA_DALGN +DMA_ASZ db #ff status_icon_copy db #1a,0 db #1b,0 db #1c,2 db #1d,4 db #1e,#3e-2 db #1f,Vid_page+8 db #26,10/2-1 db #28,9-1 db #27,DMA_BLT + DMA_DALGN +DMA_ASZ db #ff cancel_icon_copy db #1a,low cancel_icon db #1b,high cancel_icon db #1c,2 db #1d,4+4+128 db #1e,#3e-2 db #1f,Vid_page+8 db #26,8/2-1 db #28,7-1 db #27,DMA_BLT + DMA_DALGN +DMA_ASZ db #ff sprites db #1a,low spr_db db #1b,high spr_db db #1c,2 db #1d,0 db #1e,2 db #1f,0 db #26,#ff db #28,0 db #27,DMA_RAM_SFILE db #ff all_pals db #1a,low all_pal_bin db #1b,high all_pal_bin db #1c,2 db #1d,0 db #1e,0 db #1f,0 db #26,(256/2)-1 db #28,0 db #27,#84 db #ff zx_pals ; db #1a,low all_pal_bin ; db #1b,high all_pal_bin ; db #1c,2 db #1d,#e0 db #1e,1 db #1f,0 db #26,#0f db #28,0 db #27,#84 db #ff text_up_copy db #1a,0 db #1b,window_start_Y+2 db #1c,Text_page db #1d,0 db #1e,window_start_Y db #1f,Text_page db #26,#80-1 db #28,window_height*2-1 ;-1 db #27,DMA_RAM db #ff text_down_copy db #1a,0 ;low #c000+window_height*2*256 db #1c,Text_page db #1d,0 ;low #c200+window_height*2*256 db #1f,Text_page db #26,#7f db #28,0 db #ff /*include "../includes.asm" include "../tsconfig.asm"*/ include "includes.asm" include "tsconfig.asm" mouse_button db 0 zifi_ready db 0 /* D0 - левая кнопка D1 - правая кнопка D2 - средняя кнопка */ mouse_x dw 0 mouse_y dw 0 ; l - X, h- Y mouse_map dw 0 mouse_switch db 0 ALIGN 2 spr_db DB 0 DB %01000000 ; leap DB 0 DB %00010000 DB 0 DB %11100000 DB 0 DB %01000000 ; leap DB 0 DB %00010000 DB 0 DB %11100000 mouse_spr db 0 ;y db SP_SIZE16+SP_ACT db #0 ;x db SP_SIZE16 db #0 db Mouse_pal_num+#00 /* ; show text txt_spr db 240-96-16;+16 ;y db SP_SIZE16+SP_ACT db #0 ;x db SP_SIZE64 db #00 db #ef db 240-96-16;+16 ;y db SP_SIZE16+SP_ACT db #0+64 ;x db SP_SIZE64 db #08 db #ef */ DB 0 ;exit DB %01000000 ; leap DB 0 DB %00010000 DB 0 DB %11100000 spr_db_end ; init esp8266 cmd_at: defb "ATE0",13,10,0 cmd_gmr: defb "AT+GMR",13,10,0 ; 3. AT+GMR – View version info ;This AT command is used to check the version of AT commands and SDK that you are using, the type of which is "executed". cmd_uart db "AT+UART_CUR=115200,8,1,0,3",13,10,0 cmd_cwmode: defb "AT+CWMODE_DEF=1",13,10,0 ; Wi-Fi default mode(sta/AP/sta+AP) Save to Flash cmd_cipmux db "AT+CIPMUX=0",13,10,0 ; Выбрать режим одиночного или множественных подключений cmd_cwautoconn: defb "AT+CWAUTOCONN=0",13,10,0 ; Connect to AP automatically when power on cmd_cwqap: defb "AT+CWQAP",13,10,0 ; Disconnect from AP cmd_cwlap: defb "AT+CWLAP",13,10,0 ; Lists available APs cmd_cwjap: defb "AT+CWJAP_CUR=",0x22 ; Connect to AP, won’t save to Flash cmd_cwjap_pass ds 100 ; defb "wifitest123" ; SSID ; defb 0x22,0x2c,0x22 ; defb "ZXSpectrumForeverHelloEverybody321" ; password cmd_cipsta: defb "AT+CIPSTA?",13,10,0 ; AT+CIPSTA – Set IP address of station cmd_cipclose db "AT+CIPCLOSE",13,10,0 ; load data from server cmd_conn2site defb "AT+CIPSTART=" ;cmd_conn2site_task_num db "0," db 0x22 cmd_conn2site_type db "TCP" ; patched to "SSL" for https:// by parse_url db 0x22,",",0x22 ;AT+CIPSTART – Establish TCP connection or UDP transmission ;AT+CIPMODE – Set transfer mode ------!!!------ ; UART-WiFi passthrough mode (transparent transmission) can only be enabled in TCP single ; connection mode or UDP of which remote IP and port won’t change (parameter is 0 ; when using command “AT+CIPSTART” to create a UDP transmission) . cmd_conn2site_adr ds #40 ; defb "zxart.ee" ; site ; defb 0x22,",80",13,10 cmd_cipsend db "AT+CIPSEND=" ;download_task_num db "0," url_len ds 6 db 0 str_ok: defb "OK",13,0 str_already_con:defb "ALREADY CONNECT",13,0 str_error: defb "ERROR",13,0 str_fail: defb "FAIL",13,0 str_send_ok: defb "SEND OK",13,0 str_ipd db "+IPD,",0 current_load_page db 0 http_part1 db " HTTP/1.0",13,10 ;size=123 db "Host: " ;zxart.ee",13,10 http_part2 db "User-Agent: ZiFi (ZX Evo)",13,10 ; show off ;) db "Accept: */*",13,10 db "Connection: close",13,10,13,10 http_part3 zip_url_buffer db "http://zifi.vtrd.in/unzipremote.php?f=" zip_url_buffer_data ds 256 list_search_db db "Search:" dup 5 db #0a edup list_search_db_end align 256 all_pal_bin incbin "_spg/menu.tga.pal" incbin "_spg/pal_zx.tga.pal" search_url ds 64 align 256 mouse_step ds 256 parsed_link ds #080 modem_command ds 256+128 current_paging_url ds 150 sd_init call init_sd_card CALL DOS_SWP; DEPACK Driver CALL DEV_INI JP NZ,ER0 CALL HDD JP NZ,ER1 CALL SETROOT; SET ROOT DIR jp sd_exit /* [17:37:51] Koshi: ну вначале зайди в папко [17:37:55] Koshi: где файло настроек [17:38:02] Koshi: чтобы зайти в папко ннадо сделать [17:38:08] Koshi: LD HL,DIR1 CALL FENTRY [17:38:13] Koshi: затем CALL SETDIR [17:38:35] Koshi: затем запустить LD HL,FILE_INI:CALL FENTRY [17:38:40] Koshi: и тока потом уже можна LOAD512 [17:38:48] Koshi: если конечно файл нашелся [17:39:23] Koshi: FENTRY ищет файлы/каталоги [17:39:29] Koshi: и выдает длину оных в ответ [17:39:43] Koshi: плюс позиционирует на них [17:39:58] Koshi: но LOAD512 сразу после FENTRY, када искали дир [17:40:03] Koshi: буит читать САМ дир [17:40:10] Koshi: аля содержимое низкоуровневое дира [17:40:20] Koshi: чтобы перейти на дир [17:40:23] Koshi: надо сетнуть его [17:40:26] Koshi: и потом уже в НЕМ [17:40:28] Koshi: искать файло [17:40:34] Koshi: по то му же FENTRY */ ; on_int_dma/off_int_dma bracket EVERY SD operation (init_sd_card at ; the start, sd_exit at the end -- see their own call sites) -- but ; save_mode alone doesn't cover everything: int_main's pt_play (~line ; 2350) is gated by its OWN SEPARATE music_sw flag, not save_mode, and ; unconditionally repages PAGE0/PAGE1/PAGE3 for the music player ; (set_music_pages_lite) on every single interrupt a track is playing. ; PAGE0 changing mid-execution while our SD driver code is running ; FROM slot 0 (page #0F) crashes the instant the interrupt returns; ; PAGE3 changing mid-LOAD512/SAVE512 silently swaps the transfer's ; real source/dest for whatever the music player last pointed it at. ; wrap_load512/wrap_save512's own di/ei (zc_sd_driver.asm) only ; protects against the CRASH by blocking ALL interrupts for the whole ; multi-block transfer -- but that STARVES pt_play for however long ; the transfer takes (can be several video frames for a large file), ; which is exactly why music glitches/goes to noise and the screen ; flickers when switching tracks during any SD activity: pt_play ; simply never gets to run its own per-frame update while we're mid- ; transfer, then resumes abruptly once di/ei lets it back in. Clearing ; music_sw here too (not just save_mode) means pt_play's own "call ; nz,pt_play" check skips it ENTIRELY during SD operations -- a clean ; pause instead of a starve-then-jump-back-in glitch -- confirmed as ; the real cause of "noise mixed with melody" persisting even after ; the SAVE512 addressing fix (which was a real, separate bug, but not ; the only one). See [[project-zifi-custom-sd-driver]]. ; music_sw_saved: off_int_dma saves music_sw's real value here (which ; may already be 0 if the user paused music) before forcing it off, so ; on_int_dma can RESTORE that instead of blindly forcing it back to 1 ; -- otherwise an SD operation happening while music is paused would ; incorrectly un-pause it. music_sw_saved db 0 on_int_dma ld a,1 ld (save_mode+1),a ld a,(music_sw_saved) ld (music_sw+1),a ret off_int_dma ld a,(music_sw+1) ld (music_sw_saved),a xor a ld (save_mode+1),a ld (music_sw+1),a ret save_downloaded_file ; ld de,10884 ; file lenght call init_sd_card ld de,disk_icon call set_icon ld ix,read_threads ld de,(ix+thread.full_len) ld hl,FILE+1 ld (hl),e inc hl ld (hl),d inc hl ld a,(ix+thread.full_len_high) ld (hl),a ; ld (save_over_64+1),a ; ld c,a ex de,hl ld d,0 ld e,a call DEL512 ;расчёт длины в секторах: i:[DE,HL]/512 /* ld a,e or a jr z,1f inc d 1 bit 0,d jr z,1f inc d 1 srl c rr d ; d= sectors (512bytes) */ push hl ;Create File (flag,size,name,0): LD HL,FILE CALL MKFILE pop bc ; bc= num sectors JP Z,1f ;File Creation Failed /* [15:50:27] Way Be: если файло есть, то ;File Creation Failed получаем, так? [15:50:55] Koshi: и смотрим в A код ошибке [15:51:01] Koshi: если 3 - то имя уже занято ;i: HL - flag(1),ln(4),name(1-255),0 ; NZ - ERROR (NO ENOUGHT SPACE) ; A: 1 - ln not valid ; 2 - index fatality ; 3 - ln already exists ; 255 - unknown error ; Z - SUCCESS MKFILE EQU CORE+57 */ cp 3 jr z,2f cp 4 jr z,2f LD A,5:OUT (254),a jr 2f 1 ; check size>64kb /* save_over_64 ld a,0 or a jr z,save_64 */ ld a,b or a jr z,save_64 ;Save data into new file >128kb: ld a,c push af ld c,(ix+thread.page) ld hl,(ix+thread.adress) ld a,b 3 push af ld b,#80 call SAVE512 ld b,#80 call SAVE512 pop af dec a jr nz,3b pop af or a jr z,3f ld b,a jr 2f ;Save data into new file <128kb: save_64 ld b,c ld c,(ix+thread.page) ld hl,(ix+thread.adress) 2 call SAVE512 3 /* [11:50:29] Koshi: просто пишешь до посинения [11:50:35] Koshi: пока цепочка не кончиццо [11:50:59] Koshi: када цепочки конец - сейв512 и лоад512 выдадут в А=#0F */ ld hl,status_copy ; clear statusbar gfx call set_ports jp sd_exit DEL512 ;i:[DE,HL]/512 LD A,L,L,H,H,E,E,D,D,0 LD BC,1:OR A:CALL NZ,ADD4B LD A,2 DELITX2 ;i:[DE,HL]/A ; A - Power of Two ; o:[DE,HL] CP 2:RET C LD C,0 SRL A L33T SRL D:RR E,H,L,C SRL A:JR NC,L33T LD A,C:OR A:RET Z LD BC,1:CALL ADD4B RET ADD4B ADD HL,BC:RET NC:INC DE RET ; читаем настройки: load_ini call init_sd_card LD HL,DIR_zifi CALL FENTRY CALL SETDIR LD HL,FILE_INI CALL FENTRY JP Z,ini_not_found LD C,download_page ; page ini LD HL,#4000 ; LOAD512 uses the SAME slot-1/direct- ; address convention as SAVE512 -- see ; zc_sd_driver_body.asm's core_load512 ; comment for why this changed from ; #0000/PAGE3 LD B,#32 CALL LOAD512 CALL SETROOT; возвращаемся в коневой call sd_exit parse_ini ld a,download_page call set_page1 ld hl,#4000 IF !cable_zifi ld de,ini_db call cp_ini push hl call find_next_line call cp_ini ld (pass_ini+1),hl ssid_ini pop hl ld de,cmd_cwjap_pass call copy_ini ex de,hl ld bc,#222c ld (hl),b inc hl ld (hl),c inc hl ld (hl),b inc hl ex de,hl pass_ini ld hl,0 call copy_ini ex de,hl ld (hl),#22 inc hl ld (hl),13 inc hl ld (hl),10 inc hl ld (hl),13 inc hl ld (hl),10 inc hl ld (hl),0 ex de,hl call find_next_line ENDIF IF cable_zifi 2 ld a,(hl) cp "t" jr z,1f inc hl jr 2b 1 ENDIF ld de,ini_db_time call cp_ini cp "n" ret z ; time will not updated ld (update_rtc_sw+1),a ; set on update time cp "0" jr c,1f cp "9" jr c,2f 1 cp "+" ; set +/- gmt time jr nz,gmt_minus inc hl 2 call get_gmt ld (gmt_time+1),a ret gmt_minus cp "-" ret nz inc hl call get_gmt neg ld (gmt_time+1),a ret get_gmt ld b,(hl) inc hl ld a,(hl) cp #2f jr c,1f ld a,b ; tens digit (first char) *10 ... and #0f add a ld c,a add a add a add c ld c,a ld a,(hl) ; ... + ones digit (second char) and #0f add c ret 1 ld a,b and #0f ret find_next_line ld a,(hl) cp #0d+1 jr c,1f inc hl jr find_next_line 1 inc hl ld a,(hl) cp #0d+1 ret nc inc hl ret ini_not_found call set_Textpage ld hl,ini_not_found_msg ld b,1 call zifi_echo jr $ ini_not_found_msg db ' Error: zifi.ini not found',0,0 /* читаем настройки: LD HL,DIR_INI CALL FENTRY CALL SETDIR LD HL,FILE_INI CALL FENTRY LD C,0 LD HL,0 LD B,X CALL LOAD512 CALL SETROOT; возвращаемся в коневой */ ;CALL VYGREB; Выгребаем каталог, чисто по приколу ;LD HL,FILENAM ; ищем файл ;CALL FENTRY:JP Z,ER2 ;LD HL,#1000,C,#02 ; читаем файл (1 блок, 512 байт) ;LD B,1:CALL LOAD512 ; переходим в папку downloads/ set_download_dir call init_sd_card call SETROOT LD HL,DIR_download CALL FENTRY jr nz,current_dir ; Set DIR found by FENTRY active LD HL,DIR_download+1 CALL MKDIR JR Z,set_download_dir JP ER3 current_dir call SETDIR ; we in "download" dir LD HL,DIR_date ; check current date dir CALL FENTRY jr nz,sd_exit_date ; Set DIR found by FENTRY active LD HL,DIR_date+1 CALL MKDIR JR Z,current_dir jr sd_exit init_sd_card call off_int_dma ld a,sd_driver_page jp set_page0 sd_exit_date call SETDIR sd_exit call on_int_dma xor a jp set_page0 ; Standard ESP-AT SNTP commands (work on stock ESP-AT firmware, not just ours): ; AT+CIPSNTPCFG=1,0,"pool.ntp.org" - enable SNTP, UTC, one public server ; AT+CIPSNTPTIME? -> +CIPSNTPTIME:Www Mmm dd hh:mm:ss yyyy ; The reply is UTC asctime() text; gmt_time (below) applies the "time:" offset ; from zifi.ini same as before. SNTP syncs in the background after CFG, so ; CIPSNTPTIME? may still report the 1970 epoch placeholder for a moment - ; sntp_outer_left bounds how long we wait for a real value before giving up. ; update_rtc_sw/gmt_time are patched by parse_ini from the "time:" line in zifi.ini. update_rtc_sw ld a,0 ; do we need to sync the RTC at all? (patched: 0 = "none") cmd_sntp_cfg db 'AT+CIPSNTPCFG=1,0,"pool.ntp.org"',13,10,0 cmd_sntp_time db "AT+CIPSNTPTIME?",13,10,0 str_sntp_time db "+CIPSNTPTIME:",0 str_epoch_year db "1970" sntp_outer_left db 0 month_names db "JanFebMarAprMayJunJulAugSepOctNovDec" ; Five bounded attempts. On final failure CF=1; caller deliberately falls ; back to rtc_read_date so downloads still work with no network time. ntp_sync_rtc ld b,5 .retry push bc call ntp_sync_rtc_once pop bc ret nc djnz .retry scf ret ntp_sync_rtc_once call clear_input_fifo ; drop stale bytes before reading the reply ld hl,cmd_sntp_cfg call zifi_send ld b,15 ; bounded wait for CIPSNTPCFG's own OK sntp_cfg_wait ld de,str_ok call buffer_cmp jr z,sntp_cfg_ok call fifo_inir djnz sntp_cfg_wait scf ret ; module didn't even accept the config - give up sntp_cfg_ok ld a,15 ld (sntp_outer_left),a sntp_query call clear_input_fifo ; give the background sync a bit of real time each round ld hl,cmd_sntp_time call zifi_send ld b,15 ; bounded wait for THIS query's reply to arrive sntp_query_wait ld de,str_sntp_time call buffer_cmp jr z,sntp_have_line call fifo_inir djnz sntp_query_wait scf ret ; module never answered the query at all - give up sntp_have_line ; hl -> start of "Www Mmm dd hh:mm:ss yyyy" (buffer_cmp leaves it there) push hl ld de,20 add hl,de ld de,str_epoch_year ld b,4 sntp_epoch_chk ld a,(de) cp (hl) jr nz,sntp_real_time inc hl inc de djnz sntp_epoch_chk pop hl ; still the 1970 placeholder - SNTP hasn't synced yet ld a,(sntp_outer_left) dec a ld (sntp_outer_left),a jr z,sntp_no_sync ld b,50 ; ~1s before asking again call wait jr sntp_query sntp_no_sync scf ret ; this attempt exhausted its bounded epoch wait sntp_real_time pop hl ; hl -> string start, this is a real time now di ; keep CMOS unlock/select/write atomic vs the raster ISR ld bc,#eff7 ; #EFF7 is a SHARED system register (video mode/turbo/ in a,(c) ; cache/memlock bits, not just the CMOS-enable bit) - or #80 ; must read-modify-write it, not stomp it with a literal value out (c),a ; register b ld a,#0b ld b,#df out (c),a ld a,#82 ld b,#bf out (c),a ; day of week (3-letter name, offset 0..2), 0=Sunday push hl push hl pop ix push bc call day_of_week_index ; -> a = 0-6, 0=Sunday pop bc pop hl push af ld a,#06 ld b,#df out (c),a ld b,#bf pop af out (c),a ; year (last 2 of the 4 digits, offset 20..23) push hl ld de,22 add hl,de ld a,#09 ld b,#df out (c),a ld b,#bf call code_time_rtc out (c),a pop hl ; month (3-letter name, offset 4..6) push hl ld de,4 add hl,de push hl pop ix push bc call month_to_bcd ; -> a = BCD month pop bc pop hl push af ld a,#08 ld b,#df out (c),a ld b,#bf pop af out (c),a ; date of the month (offset 8..9, space-padded for single digits - and0 ; code_time_rtc's "and #0f" happens to treat a leading space as digit 0) push hl ld de,8 add hl,de ld a,#07 ld b,#df out (c),a ld b,#bf call code_time_rtc out (c),a pop hl ; hours (offset 11..12), adjusted by the configured GMT offset push hl ld de,11 add hl,de ld a,#04 ld b,#df out (c),a ld b,#bf ld a,(hl) and #0f add a ld e,a add a add a add e ld e,a inc hl ld a,(hl) and #0f add e inc hl ld e,0 ; calculate time with gmt offset, signed (-2 = #fe, +2 = 2 ) gmt_time add 0 jp m,3f cp 24 jr c,1f jr nc,1f add 24 jr 2f 3 add 24 1 cp 24 jr c,2f sub 24 2 4 cp 10 jr c,1f sub 10 inc e jr 4b 1 or a rl e rl e rl e rl e or e out (c),a pop hl ; minutes (offset 14..15) push hl ld de,14 add hl,de ld a,#02 ld b,#df out (c),a ld b,#bf call code_time_rtc out (c),a pop hl ; seconds (offset 17..18) push hl ld de,17 add hl,de ld a,#00 ld b,#df out (c),a ld b,#bf call code_time_rtc out (c),a pop hl ; register b ld a,#0b ld b,#df out (c),a ld a,#02 ld b,#bf out (c),a ld bc,#eff7 in a,(c) and #7f out (c),a ei ld hl,ntp_synced_msg ld b,1 call zifi_echo xor a ; NC = NTP date was written to RTC ret ; in: ix -> 3-letter month name (e.g. from CIPSNTPTIME's reply) ; out: a = BCD month 01-12 (clobbers af,bc,de,hl); defaults to January if not found month_to_bcd ld hl,month_names ld c,1 mtb_loop ld a,(ix+0) cp (hl) jr nz,mtb_next inc hl ld a,(ix+1) cp (hl) jr nz,mtb_rewind1 inc hl ld a,(ix+2) cp (hl) jr z,mtb_found dec hl mtb_rewind1 dec hl mtb_next ld de,3 add hl,de ld a,c cp 12 jr z,mtb_notfound inc c jr mtb_loop mtb_notfound ld c,1 mtb_found ld a,c cp 10 jr c,mtb_done sub 10 add a,#10 mtb_done ret ; in: ix -> 3-letter day-of-week name (e.g. from CIPSNTPTIME's reply) ; out: a = 0-6, 0=Sunday (clobbers af,bc,de,hl); defaults to Sunday if not found day_of_week_index ld hl,dow_names ld c,0 dow_loop ld a,(ix+0) cp (hl) jr nz,dow_next inc hl ld a,(ix+1) cp (hl) jr nz,dow_rewind1 inc hl ld a,(ix+2) cp (hl) jr z,dow_found dec hl dow_rewind1 dec hl dow_next ld de,3 add hl,de ld a,c cp 6 jr z,dow_notfound inc c jr dow_loop dow_notfound ld c,0 ; ran out of names - default to Sunday dow_found ld a,c ret dow_names db "SunMonTueWedThuFriSat" ntp_synced_msg db "Time synced via NTP.",0,0 ; Reads the current date straight back off the RTC chip into DIR_date, as ; "20YY_MM_DD" - used to name the downloads/ folder. Works regardless of ; whether "time:" is "none" or the NTP sync above failed: the chip keeps ; ticking on its own battery either way, so this is the one source of truth. rtc_read_date di ld bc,#eff7 in a,(c) or #80 out (c),a ld de,DIR_date+1 ld a,"2" ld (de),a inc de ld a,"0" ld (de),a inc de ; year ld a,#09 ld b,#df out (c),a ld b,#bf in a,(c) call bcd_to_ascii ld a,"_" ld (de),a inc de ; month ld a,#08 ld b,#df out (c),a ld b,#bf in a,(c) call bcd_to_ascii ld a,"_" ld (de),a inc de ; date of the month ld a,#07 ld b,#df out (c),a ld b,#bf in a,(c) call bcd_to_ascii ld bc,#eff7 in a,(c) and #7f out (c),a ei ret bcd_to_ascii ; in: a = BCD byte, de = destination; writes 2 ASCII digits, advances de push af rra rra rra rra and #0f add "0" ld (de),a inc de pop af and #0f add "0" ld (de),a inc de ret code_time_rtc ld a,(hl) and #0f rla rla rla rla ld e,a inc hl ld a,(hl) and #0f or e inc hl ret ;--------------------------------------- /* VYGREB LD DE,#8000 VYG CALL NXTETY:RET Z LD A,D:CP #C0:RET NC JR VYG */ ;--------------------------------------- ER0 ;Device not found ; (SD Card NOT ready!) LD A,1:OUT (254),a JP sd_exit ;------- ER1 ;FAT32 NOT FOUND LD A,2:OUT (254),a JP sd_exit ;------- ER2 ;File NOT FOUND LD A,3:OUT (254),a JP sd_exit ;------- ER3 ;Dir Creation Failed LD A,4:OUT (254),a JP sd_exit ;------- ER4 ;File Creation Failed /* [15:50:27] Way Be: если файло есть, то ;File Creation Failed получаем, так? [15:50:55] Koshi: и смотрим в A код ошибке [15:51:01] Koshi: если 3 - то имя уже занято */ LD A,5:OUT (254),a JP sd_exit ;--------------------------------------- /* FILENAM DB #00; 0 - file, 1 - DIR DB "WC_History.txt",0 */ FILE DB #00; flag ; DW #1000,#0000;length - 4kb DW #0000,#0000;length FILE_NAME ds 48 db 0 /* [14:12:36] Koshi: младший, старший вестимо [14:12:42] Way Be: ок [14:12:46 | Змінено в 14:12:49] Koshi: #0000 1000 = 4кб [14:13:03] Koshi: в примере же написано */ FILE_INI DB #00; 0 - file, 1 - DIR DB "zifi.ini",0 DIR_zifi DB #10 DB "zifi",0 DIR_download DB #10 DB "downloads",0 DIR_date DB #10 DB "00_00_0000",0 ;--------------------------------------- CORE EQU #2002 DEV_INI EQU CORE+3 HDD EQU CORE+9 ;------- ;i: CHL - Addres ; B - lenght (512b blocks) ;o: CHL - New Value ; A - EndOfChain (#0F) LOAD512 EQU CORE+21 ;i: CHL - Addres ; B - lenght ;o: CHL - New Value ; A - EndOfChain (#0F) SAVE512 EQU CORE+24 DOS_SWP EQU CORE+27 ;i: HL - flag(1),ln(4),name(1-255),0 ; NZ - ERROR (NO ENOUGHT SPACE) ; A: 1 - ln not valid ; 2 - index fatality ; 3 - ln already exists ; 255 - unknown error ; Z - SUCCESS MKFILE EQU CORE+57 ;i: HL - DirName(1-255,0) ;o: NZ - ERROR ; A: 1 - ln not valid ; 2 - index fatality ; 3 - ln already exists ; 255 - unknown error ; Z - SUCCESS MKDIR EQU CORE+60 ;i: HL - flag(1),name(1-255),0 ;o: Z - NOT FOUND ; NZ - FILE DELETED DELFL EQU CORE+63 ;i: HL - flag(1),oldname(1-255),0 ; DE - newname(1-255),0 ;o: Z - NOT FOUND ; NZ - SUCCESS RENAM EQU CORE+66 ;Search for entry in current DIR ;i: HL - flag(1),name(1-255),0 ;o: Z - NOT FOUND ; NZ - [DE,HL] - file length ; SEEK0 is automatically called FENTRY EQU CORE+78 ;Seek/Skip N sectors ;i: B - Number of sectors to process LOADNON EQU CORE+84 ;GetNextEntryFromActiveDir ;i: DE - Addres ;o: DE - New Value ; Z - EndOfDir ; NZ - OK ; ;STRUCTURE: ;fclus(4),size(4),date(2),time(2), ;!flag(1),name(1-255),#00 NXTETY EQU CORE+87 ;Set DIR found by ENTRY active SETDIR EQU CORE+93 ;Set ROOT DIR active SETROOT EQU CORE+96 SEEK0 EQU CORE+99 zifi_command_reg equ #C7EF zifi_error_reg equ #C7EF zifi_data_reg equ #BFEF zifi_input_fifo_status equ #C0EF zifi_output_fifo_status equ #C1EF cmd_clear_input_fifo equ 1 cmd_clear_output_fifo equ 2 struct thread num byte ; num thread -1 len word ; current ipd lenght adress word ; current adress page byte ; current page file_ext word ; file name adress full_len word ; lenght of file full_len_high byte ; ends read_threads thread;ds 6*5 db #ff ; modem_load_file's own private snapshot of load_ram_page, captured ; right before starting the actual network receive (zifi_get/psb_get) ; -- NOT the same as re-reading load_ram_page after the call returns. ; load_ram_page is a single shared global, written from several other ; places (catalog-link clicks, pagination, menu navigation -- see ; loadpage_after_link_list and the download_page writers). zifi_get can ; run for several seconds (WiFi connect/TLS handshake/HTTP wait, many ; wait_frame-yielded interrupt frames), during which the interrupt- ; driven UI can process a DIFFERENT click that overwrites load_ram_page ; before zifi_get returns. Re-reading load_ram_page at that point (the ; old code) stamps thread.page with whatever category was clicked LAST, ; not the one this download actually used. This is a real, still-latent ; hazard (kept as a defensive fix), but turned out NOT to be the cause ; of "every download saves as identical garbage" -- that bug was a ; stale IX left behind by MKFILE (see the wrap_* comment in ; zc_sd_driver.asm), which made save_64 read (ix+thread.page)/(ix+ ; thread.adress) from the wrong memory entirely, regardless of what ; read_threads itself held. See [[project-zifi-custom-sd-driver]] ; (2026-09-09). saved_thread_page db 0 init_zifi call set_Textpage ld bc,0xc7ef ld de,0xfff1 out (c),e ;Set API mode 1 out (c),d ;Get Version in a,(c) cp 0xff jp z,nozifi ld a,0x01 out (c),a ;Clear RX FIFO ld hl,cmd_at call zifi_send ;ld hl,cmd_uart ; call zifi_send ld hl,cmd_gmr call zifi_send_echo ld hl,cmd_cwmode call zifi_send ld hl,cmd_cwautoconn call zifi_send ld hl,cmd_cipmux call zifi_send ; ld hl,cmd_cwqap ; Disconnect from AP ; call zifi_send ; ld b,25 ; call wait ; call zifi_check_receive_command ; ret ld a,wifi_connect_retries_max ld (wifi_connect_retries_left),a ; wifi_connect_retry: (re)send AT+CWJAP_CUR and wait for "OK" -- up to ; wifi_connect_quanta quanta (~256 frames/quantum, ~5s each) per ; attempt, up to wifi_connect_retries_max attempts total. Was an ; unconditional "jr nz,2b" with NO timeout at all -- a real ESP module ; that never answers (bad credentials, out of range, module wedged) ; hung here forever with zero feedback. See [[project-zifi-custom-sd-driver]]. wifi_connect_retry ld hl,wifi_try_connect ld b,2 call zifi_echo ld hl,cmd_cwjap ; AT+CWJAP_CUR . Connect to AP, for current call zifi_send ld a,wifi_connect_quanta ld (wifi_connect_quantum_left),a wifi_connect_quantum xor a ld (wifi_connect_frame_left),a ; 0 wraps to 256 via dec below wifi_connect_poll ; NOT "call zifi_check_receive_command" -- that goes through ; zifi_input_fifo_check, which BLOCKS INTERNALLY for up to ; 256 frames (its own "call wait_frame / dec e / jr nz,3b") ; whenever the FIFO is empty, only returning immediately ; when data IS already waiting. With nothing new arriving, ; nearly every call to it here would burn a full internal ; 256-frame wait BEFORE this loop's own frame counter even ; gets to react -- confirmed live (wifi_connect_frame_left ; stayed frozen for 6500+ frames: this loop's "iterations" ; were each secretly taking up to 256 frames on their own). ; It also drives zifi_input_fifo_check's OWN separate ; download-timeout/retry state (dl_timeout_left etc, meant ; for actual file downloads, not this WiFi-connect wait) -- ; that's what caused the red border flashes. Doing our own ; quick, non-blocking FIFO peek here avoids both problems: ; only call the (bulk-read) fifo_inir when data is actually ; present, so it never falls into the internal wait either. ld bc,zifi_input_fifo_status in a,(c) or a jr z,wifi_connect_nodata call fifo_inir ld de,str_ok call buffer_cmp jr z,wifi_connect_ok wifi_connect_nodata call wait_frame ld hl,wifi_connect_frame_left dec (hl) jr nz,wifi_connect_poll ld a,(wifi_connect_quantum_left) dec a ld (wifi_connect_quantum_left),a jr nz,wifi_connect_quantum ; this attempt's quanta are exhausted -- retry if any left ld a,(wifi_connect_retries_left) dec a ld (wifi_connect_retries_left),a jr nz,wifi_connect_retry ; out of retries -- give up with a real message instead of ; hanging silently forever ld hl,wifi_connect_failed_msg ld b,1 call zifi_echo jr $ wifi_connect_ok ld hl,wifi_connected call zifi_echo ld a,(update_rtc_sw+1) ; "time:" in zifi.ini not "none"? or a call nz,ntp_sync_rtc call rtc_read_date ; name downloads/ from the RTC chip either way call set_download_dir ret wifi_connect_quanta equ 4 ; ~5s/quantum * 4 = ~20s per attempt wifi_connect_retries_max equ 5 wifi_connect_frame_left db 0 wifi_connect_quantum_left db 0 wifi_connect_retries_left db 0 wifi_connect_failed_msg db #0d,#0a,'WiFi connect failed',0,0 ; ld b,25 ; call wait ; ld hl,cmd_cipsta ; is Set IP address of station ? ; call zifi_send ; call zifi_check_receive_command ; ret /* ld b,25 call wait ret */ zifi_error ret nozifi ld hl,conf_not_found_msg ld b,1 call zifi_echo jr $ conf_not_found_msg db "Error: Please update TS Conf.",0,0 zifi_not_found_msg db "Error: ZiFi ESP8266 module not found.",0,0 /* Address Mode Name Description 0x00EF..0xBFEF R DR Data register (ZIFI or RS232). Get byte from input FIFO. Input FIFO must not be empty (xx_IFR > 0). 0x00EF..0xBFEF W DR Data register (ZIFI or RS232). Put byte into output FIFO. Output FIFO must not be full (xx_OFR > 0). Address Mode Name Description 0xC0EF R ZF_IFR ZIFI Input FIFO Used Register. Switch DR to ZIFI FIFO. 0 - input FIFO is empty, 191 - input FIFO contain 191 or more bytes. 0xC1EF R ZF_OFR ZIFI Output FIFO Free Register. Switch DR to ZIFI FIFO. 0 - output FIFO is full, 191 - output FIFO free 191 or more bytes. 0xC2EF R RS_IFR RS232 Input FIFO Used Register. Switch DR to RS232 FIFO. 0 - input FIFO is empty, 191 - input FIFO contain 191 or more bytes. 0xC3EF R RS_OFR RS232 Output FIFO Free Register. Switch DR to RS232 FIFO. 0 - output FIFO is full, 191 - output FIFO free 191 or more bytes. Address Mode Name Description 0xC7EF W CR Command register. Command set depends on API mode selected. All mode commands: Code Command Description 000000oi Clear ZIFI FIFOs i: 1 - clear input ZIFI FIFO, o: 1 - clear output ZIFI FIFO. 000001oi Clear RS232 FIFOs i: 1 - clear input RS232 FIFO, o: 1 - clear output RS232 FIFO. 11110mmm Set API mode or disable API: 0 API disabled. 1 transparent: all data is sent/received to/from external UART directly. 2..7 reserved. 11111111 Get Version Returns highest supported API version. ER=0xFF - no API available. Address Mode Name Description 0xC7EF R ER Error register - command execution result code. Depends on command issued. All mode responses: Code Description 0x00 OK - no error. 0xFF REJ - command rejected. -------------------------------------------------------------------------------- Until initialization sequence performed API is disabled and the only command recognized is 'Set API mode'. Initialization sequence: - Send 'Set API mode = 1' command, - Send 'Get Version' command, - Read highest supported API mode from ER, - Select desired API mode. zifi_init: ; select API mode 1 ld bc, 0xC7EF ld a, 0xF1 out (c), a ; get highest supported API mode ld a, 0xFF out (c), a in a, (c) ; select desired API mode, if need ld a, mode ; possible values are 0xF2..0xF7 out (c), a */ ;; PSB com driver --------------------------------- IF cable_zifi include "_rs232/sockets.mac" psb_start jp init psb_get jp get init ;init uart ld hl,1 ;BaudRate = 115200 / divfq; call uart.SetBaud ;init uart ld a,uart.WLSB1+uart.WLSB0 ;8 bit word, no parity call uart.SetLineControl ret ; BUFFER equ 0 ; BUFFER_SIZE equ 1 GET_HDR dw 0 GET_HDR_LEN dw 0 GET_PAGE db 0 host_addr_len dw 0 host_addr dw 0 ;in: ;a=page ;hl=get hdr ;out: ;a=0 - ok ;hl=len_l ;bc=len_h get ld (GET_HDR),hl ld (GET_PAGE),a ;get host name g1 ld a,(hl) or a:jp z,get_err cp 'H':jr z,get_h1 inc hl:jr g1 get_h1 inc hl ld a,(hl):cp 'o':jr nz,g1:inc hl ld a,(hl):cp 's':jr nz,g1:inc hl ld a,(hl):cp 't':jr nz,g1:inc hl ld a,(hl):cp ':':jr nz,g1:inc hl ld a,(hl):cp ' ':jr nz,g1:inc hl ld (host_addr),hl ld bc,0 gh1 ld a,(hl):cp 13:jr z,ghe cp ":":jr z,ghe cp "/":jr z,ghe ;? inc hl,bc:jr gh1 ghe ld (host_addr_len),bc ;get HDR len g2 ld a,(hl) or a:jr z,g3 inc hl:jr g2 g3 ld de,(GET_HDR):or a:sbc hl,de:ld (GET_HDR_LEN),hl ;gethostbyname ld hl,(host_addr),bc,(host_addr_len) call sockets.gethostbyname or a:jp nz,get_err ld (server_addr),hl,(server_addr+2),bc ;create socket socket AF_INET,SOCK_STREAM,0 cp INVALID_SOCKET:jp z,get_err ld (fd),a ;bind my socket bind fd,my_addr or a:jp nz,get_err ;connect to host connect fd,server_addr or a:jp nz,get_err ;send HTTP request send fd,(GET_HDR),(GET_HDR_LEN) or a:jr nz,get_err ld ix,0 ;full pages got ld hl,(zipd_adr+1) ; #c000 ----------- !!!!!!!!!! align 2 fix ------------------ set 7,h set 6,h xor a ld (sockets.recv_skip_header+1),a get_loop ld a,(GET_PAGE) call set_page3 ld de,#0000:ex de,hl:or a:sbc hl,de:ex de,hl ;de=len,hl=start ;recv data ; recv fd,BUFFER,BUFFER_SIZE push hl ld b,d,c,e ld a,(fd) call sockets.recv pop hl or a:jr nz,get_end ; ld a,b:or c:jr z,get_end call view_progress_bar add hl,bc ld a,h or a jr nz,get_loop ld hl,GET_PAGE:inc (hl) ld hl,#c000 inc ixl jr get_loop get_end ;res 6,h:res 7,h ld a,h and #3f ld h,a ld de,0,b,0,c,ixl srl c:rr d:rr e srl c:rr d:rr e add hl,de ;bc:hl=len get_e ld a,(fd):cp #ff:jr z,noclose push hl,bc ;close socket close fd pop bc,hl noclose ld a,#ff,(fd),a xor a ret get_err call get_e inc a ret cable_cancel_download_ex ld sp,#bfff xor a ld (uart.cable_cancel_download+1),a ld (load_sw+1),a close fd call noclose ld hl,status_copy ; clear statusbar gfx call set_ports jp main ;----------------------------------------------------------- fd db #ff ;socket fd my_addr db 0,0,0,0:dw 0 ;my ip+port server_addr db 93,158,134,3:dw 80 ;code include "_rs232/uart.a80" include "_rs232/sockets.a80" ; PSB com driver --------------------- ENDIF align 2 download_icon incbin "_spg/download.tga.pix" disk_icon incbin "_spg/disk.tga.pix" cancel_icon incbin "_spg/X.tga.pix" highlight_colors_buff ds 80 link_adreses ds 101*6 align 256 output_buff ds #100 end music_player equ #c000 music_player_init equ @music_player+3 music_player_play equ @music_player+5 music_player_mute equ @music_player+8 music_setup_vars equ music_player+#55 /* ; uni player org #c000 music_player INCLUDE "_pt\ptx.asm" music_player_init equ @music_player+3 music_player_play equ @music_player+5 music_player_mute equ @music_player+8 music_setup_vars equ music_player+#55 music_players_end SAVEBIN "_spg/ptplay.bin",music_player, music_players_end-music_player */ LABELSLIST "_spg/zifi.l" IF cable_zifi SAVEBIN "_spg/zifi_rs.bin",start, end-start ELSE SAVEBIN "_spg/zifi.bin",start, end-start ENDIF