commit e5b6f1e91e4800c2e8ae56543fc7b9787dd7f88a Author: nihirash Date: Tue Jun 25 22:27:29 2019 +0300 Version 0.1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a31e2af --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.tap +ugoph.bin +.vscode diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c4a4ffd --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all: ugoph.tap + +ugoph.tap: *.asm *.pg + sjasmplus main.asm + +clean: + rm *.tap diff --git a/esxdos.asm b/esxdos.asm new file mode 100644 index 0000000..b74d230 --- /dev/null +++ b/esxdos.asm @@ -0,0 +1,71 @@ +; API methods +ESX_GETSETDRV = #89 +ESX_FOPEN = #9A +ESX_FCLOSE = #9B +ESX_FSYNC = #9C +ESX_FREAD = #9D +ESX_FWRITE = #9E + +; File modes +FMODE_READ = #01 +FMODE_WRITE = #06 +FMODE_CREATE = #0E + +; Returns: +; A - current drive +getDefaultDrive: + ld a, 0 + rst #8 + defb ESX_GETSETDRV + ret + +; Opens file on default drive +; B - File mode +; HL - File name +; Returns: +; A - file stream id +fopen: + push bc + push hl + call getDefaultDrive + pop ix + pop bc + rst #8 + defb ESX_FOPEN + ret + +; A - file stream id +fclose: + rst #8 + defb ESX_FCLOSE + ret + +; A - file stream id +; BC - length +; HL - buffer +; Returns +; BC - length(how much was actually read) +fread: + push hl + pop ix + rst #8 + defb ESX_FREAD + ret + +; A - file stream id +; BC - length +; HL - buffer +; Returns: +; BC - actually written bytes +fwrite: + push hl + pop ix + rst #8 + defb ESX_FWRITE + ret + +; A - file stream id +fsync: + rst #8 + defb ESX_FSYNC + ret diff --git a/font.bin b/font.bin new file mode 100644 index 0000000..127dfe1 Binary files /dev/null and b/font.bin differ diff --git a/gopher.asm b/gopher.asm new file mode 100644 index 0000000..b6180fc --- /dev/null +++ b/gopher.asm @@ -0,0 +1,217 @@ +; hl - server +; de - path +; bc - port +openPage: + push hl + push de + push bc + + ex hl, de + + ld de, hist + ld bc, 147 + ldir + + ld hl, page_buffer + xor a + ld (hl), a + ld de, page_buffer + 1 + ld bc, 32767 + ldir + pop bc + pop de + pop hl + call makeRequest + ld hl, page_buffer + call loadData + xor a + ld (show_offset), a + ld a, 1 + ld (cursor_pos), a + ret + +; HL - domain stringZ +; DE - path stringZ +; BC - port stringZ +makeRequest: + push de + push bc + push HL + + + ld hl, downloading_msg + call showTypePrint + + ld hl, cmd_open1 ; Open TCP connection + call uartWriteStringZ + pop hl + call uartWriteStringZ + ld hl, cmd_open2 + call uartWriteStringZ + pop hl + call uartWriteStringZ + ld hl, cmd_open3 + call okErrCmd + cp 1 + jp nz, reqErr + + ld hl, cmd_send ; Send request + call uartWriteStringZ + pop hl + push hl + call getStringLength ; Calculate addr length + push bc + pop hl + inc hl ; CR + inc hl ; LF + call B2D16 ; To string + ld hl, B2DBUF + call SkipWhitespace + call uartWriteStringZ + + ld hl, crlf + call okErrCmd + cp 1 + jp nz, reqErr +wPrmt: + call uartReadBlocking + call pushRing + ld hl, send_prompt + call searchRing + cp 1 + jr nz, wPrmt + + pop hl + call uartWriteStringZ + + ld hl, crlf + call uartWriteStringZ + ld a, 1 + ld (connectionOpen), a + ret + +reqErr + ld hl, connectionError + call putStringZ + xor a + ld (connectionOpen), a + ret + +; Load data to ram via gopher +; HL - data pointer +; In data_recv downloaded volume +loadData: + ld (data_pointer), hl + ld hl, 0 + ld (data_recv), hl +lpLoop: + call getPacket + ld a, (connectionOpen) + and a + jp z, ldEnd + ld bc, (bytes_avail) + ld de, (data_pointer) + ld hl, output_buffer + ldir + ld hl, (data_pointer) + ld de, (bytes_avail) + push de + add hl, de + ld (data_pointer), hl + pop de + ld hl, (data_recv) + add hl, de + ld (data_recv), hl + jp lpLoop + +ldEnd + xor a + ld (data_pointer), a + ret + +; Download file via gopher +; HL - filename +downloadData: + ld b, FMODE_CREATE + call fopen + ld (fstream), a +dwnLp: + call getPacket + ld a, (connectionOpen) + and a + jp z, dwnEnd + ld bc, (bytes_avail) + ld hl, output_buffer + ld a, (fstream) + call fwrite + ld a, (fstream) + call fsync + jp dwnLp +dwnEnd: + ld a, (fstream) + call fclose + ret + +openURI: + call cleanIBuff + ld b, 19 + ld c, 0 + call gotoXY + + ld hl, cleanLine + call printZ64 + + ld b, 19 + ld c, 0 + call gotoXY + + ld hl, hostTxt + call printZ64 + + call input + + ld b, 19 + ld c, 0 + call gotoXY + + ld hl, cleanLine + call printZ64 + + ld hl, iBuff + + ld a, (hl) + and a + ret z + + ld de, d_host + ld bc, 65 + ldir + + ld hl, d_host + ld de, d_path + ld bc, d_port + call openPage + jp showPage + ret + +data_pointer defw #4000 +data_recv defw 0 +fstream defb 0 + +closed_callback + xor a + ld (connectionOpen), a + ret + +hostTxt db 'Enter host: ', 0 + +d_path db '/' + defs 69 +d_host defs 70 +d_port db '70' + defs 5 + +hist ds 147 +connectionOpen db 0 +downloading_msg db 'Downloading...', 0 +connectionError db 'Cant open TCP connection', 0 \ No newline at end of file diff --git a/http.asm b/http.asm new file mode 100644 index 0000000..dfa3905 --- /dev/null +++ b/http.asm @@ -0,0 +1,176 @@ +; Some parts taken from ZiFi sources + +; Performs HTTP-get request +; First packet will be in var 'output_buffer' +; received packet size in var 'bytes_avail' +; +; HL - url includes http:// header +httpGet 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 + +create_link1 ld hl,create_link_suffix + 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 + ex de,hl + ld de,modem_command + or a + sbc hl,de + 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 + jr firstPacket + +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 + +firstPacket: + call performRequest + +skipHeaders: + ld de, output_buffer + ld bc, 0 +shLp: + ld a, (de) + push de + push bc + call pushRing + ld hl, headers_end + call searchRing + pop bc + pop de + inc de + inc bc + cp 1 + jr nz, shLp + ld hl, (bytes_avail) + sbc hl, bc + ld (bytes_avail), hl + push hl + pop bc + push de + ld de, output_buffer + pop hl + ldir + ret + + +performRequest: + ld hl, cmd_conn2site + call okErrCmd + cp 1 + jr z, zg_ok + ld hl, cmd_close + call okErrCmd + jr performRequest +zg_ok: + ld hl, cmd_cipsend + call okErrCmd +guLp: + call uartReadBlocking + call pushRing + ld hl, send_prompt + call searchRing + cp 1 + jr nz, guLp + ld hl, modem_command + call okErrCmd + jp getPacket + +create_link_suffix + db #22,",80",13,10,0 + display $ +modem_command ds 256+128 + display $ +http_part1 db " HTTP/1.0",13,10 ;size=123 + db "Host: " +http_part2 db "User-Agent: ZX Uno(Z80 CPU)",13,10 ; show off ;) + db "Accept: */*",13,10 + db "Connection: close",13,10,13,10 +http_part3 + +cmd_conn2site defb "AT+CIPSTART=", 0x22,"TCP",0x22,",",0x22 +cmd_conn2site_adr ds #40 + +headers_end defb 13,10,13,10,0 +cmd_cipsend defb "AT+CIPSEND=" +url_len defs 6 + defb 0 diff --git a/index.pg b/index.pg new file mode 100644 index 0000000..cba9517 --- /dev/null +++ b/index.pg @@ -0,0 +1,13 @@ +iWecome to uGophy - ZX-Uno's gopher client! fake (NULL) 0 +i(c) 2019 Alexander Sharikhin aka Nihirash fake (NULL) 0 +iVersion 0.1 - First public release fake (NULL) 0 +i fake (NULL) 0 +iNavigation keys: fake (NULL) 0 +i Q - Up fake (NULL) 0 +i A - Down fake (NULL) 0 +i B - History back fake (NULL) 0 +i O - Enter server name to browse(using port 70) fake (NULL) 0 +i Enter - visit page/download file fake (NULL) 0 +i fake (NULL) 0 +iYou may visit: fake (NULL) 0 +1Nihirash.net - there you can download my software / nihirash.net 70 diff --git a/keyboard.asm b/keyboard.asm new file mode 100644 index 0000000..0445bdc --- /dev/null +++ b/keyboard.asm @@ -0,0 +1,99 @@ +CURKEY = 23560 + +; Returns in A key code or zero if key wans't pressed +inkey: + ld hl, CURKEY + ld a, (hl) + push af + xor a + ld (hl), a + pop af + ret + +findZero: + ld a, (hl) + or a + ret z + inc hl + jp findZero + +input: + ld b, 20 + ld c, 0 + call gotoXY + + ld hl, cleanLine + call printZ64 + ld hl, iBuff + call findZero +iLp: + halt + push hl + ld b, 20 + ld c, 0 + call gotoXY + + ld hl, iBuff + call printZ64 + + ld a, '_' + call putC + ld a, ' ' + call putC + + call inkey + + cp 0 + jr z, iNth + + cp 12 + jr z, iBS + + cp 13 + jr z, iRet + + pop hl + ld (hl), A + push hl + ld de, iBuff + 62 + sub hl, de + ld a, h + or l + jr z, iCr + pop hl + inc hl + jr iLp +iBS: pop hl + push hl + ld de, iBuff + sub hl, de + ld a, h + or l + pop hl + jr z, iLp + dec hl + ld (hl), 0 + jr iLp +iCr pop hl + xor a + ld (hl), a + push hl +iNth pop hl + jr iLp +cleanIBuff: + ld bc, 64 + ld hl, iBuff + ld de, iBuff + 1 + ld (hl), 0 + ldir + ret +iRet: + ld b, 20 + ld c, 0 + call gotoXY + + ld hl, cleanLine + call printZ64 + ret + +iBuff defs 65 \ No newline at end of file diff --git a/main.asm b/main.asm new file mode 100644 index 0000000..06c9ec2 --- /dev/null +++ b/main.asm @@ -0,0 +1,36 @@ + DEVICE ZXSPECTRUM48 + org 24100 +Start: + call renderHeader + call initWifi + jp showPage +wSec: ld b, 50 +wsLp halt + djnz wsLp + + include "screen64.asm" + include "keyboard.asm" + include "utils.asm" + include "wifi.asm" + include "gopher.asm" + include "render.asm" + include "textrender.asm" + include "uart.asm" + include "ring.asm" + include "esxdos.asm" + +open_lbl db 'Opening connection to ', 0 + +path db '/' + defs 69 +server db 'nihirash.net' + defs 58 +port db '70' + defs 5 + +data_buff defs 255 +page_buffer + incbin "index.pg" + db 0 +eop equ $ + SAVEBIN "ugoph.bin", Start, eop-Start diff --git a/render.asm b/render.asm new file mode 100644 index 0000000..3b77d13 --- /dev/null +++ b/render.asm @@ -0,0 +1,451 @@ +showPage: + xor a + ld (show_offset), a + ld a, 1 + ld (cursor_pos), a + call renderScreen + call showCursor +showLp: + call controls + dup 5 + halt + edup + jr showLp + +controls: + call inkey + + cp 0 + ret z + + cp 'q' + jr z, pageCursorUp + + cp 'a' + jr z, pageCursorDown + + cp 13 + jp z, selectItem + + cp 'b' + jr z, historyBack + + cp 'o' + jp z, openURI + ret + +historyBack: + ld hl, server + ld de, path + ld bc, port + call openPage + jp showPage + +pageCursorUp: + ld a, (cursor_pos) + dec a + cp 0 + jp z, pageScrollUp + + push af + call hideCursor + pop af + ld (cursor_pos), a + call showCursor + ret + +pageCursorDown: + ld a, (cursor_pos) + inc a + cp 21 + jp z, pageScrollDn + + push af + call hideCursor + pop af + ld (cursor_pos), a + call showCursor + ret + +pageScrollDn: + ld hl, (show_offset) + ld de, 20 + add hl, de + ld (show_offset), hl + ld a, 1 + ld (cursor_pos), a + call renderScreen + call showCursor + ret + +pageScrollUp: + ld a, (show_offset) + and a + ret z + + ld hl, (show_offset) + ld de, 20 + sub hl, de + ld (show_offset), hl + + ld a, 20 + ld (cursor_pos), a + call renderScreen + call showCursor + ret + +selectItem: + ld a, (cursor_pos) + dec a + ld b, a + ld a, (show_offset) + add b + ld b, a + call findLine + ld a, h + cp l + ret z + ld a, (hl) + + cp '1' + jr z, downPg + + cp '0' + jr z, downPg + + cp '9' + jp z, downFl + + ret + +downPg: + push af + call extractInfo + + ld hl, hist + ld de, path + ld bc, 147 + ldir + + ld hl, server_buffer + ld de, file_buffer + ld bc, port_buffer + call openPage + pop af + + cp '1' + jp z,showPage + + cp '0' + jp z, showText + + ret + +downFl: + call extractInfo + + call cleanIBuff + ld hl, file_buffer + call findFnme + ld de, iBuff + ld bc, 65 + ldir + call input + ld hl, server_buffer + ld de, file_buffer + ld bc, port_buffer + call makeRequest + + ld hl, iBuff + call downloadData + call showCursor + ret + +findFnme: + push hl + pop de +ffnmlp: + ld a, (hl) + + cp 0 + jr z, ffnmend + + cp '/' + jr z, fslsh + + inc hl + jp ffnmlp +fslsh: + inc hl + push hl + pop de + jp ffnmlp +ffnmend: + push de + pop hl + ret + +showType: + ld a, (cursor_pos) + dec a + ld b, a + ld a, (show_offset) + add b + ld b, a + call findLine + ld a, h + cp l + jr z, showTypeUnknown + + ld a, (hl) + + cp 'i' + jr z, showTypeInfo + + cp '9' + jr z, showTypeDown + + cp '1' + jr z, showTypePage + + cp '0' + jr z, showTypeText + + jr showTypeUnknown + +showTypeText: + ld hl, type_text + call showTypePrint + call showURI + ret + +showTypeInfo: + ld hl, type_info + jp showTypePrint + +showTypePage: + ld hl, type_page + call showTypePrint + call showURI + ret + +showTypeDown: + ld hl, type_down + call showTypePrint + call showURI + ret + +showURI: + call extractInfo + ld hl, server_buffer + call printZ64 + + ld hl, file_buffer + call printZ64 + ret +showTypeUnknown: + ld hl, type_unkn + jp showTypePrint + +showTypePrint: + push hl + + ld b, 21 + ld c, 0 + call gotoXY + ld hl, cleanLine + call printZ64 + + ld b, 21 + ld c, 0 + call gotoXY + ld a, 3 + ld (attr_screen), a + pop hl + call printZ64 + ld a, #7 + ld (attr_screen), a + ret + +showCursor: + ld a, (cursor_pos) + ld c, 0 + ld b, a + call bc_to_attr + ld (hl), #C + ld de, hl + inc de + ld bc, 31 + ldir + call showType + ret + +hideCursor: + ld a, (cursor_pos) + ld b, a + ld c, 0 + call bc_to_attr + ld (hl), #07 + ld de, hl + inc de + ld bc, 31 + ldir + ret + +renderHeader: + call clearScreen + ld a, #0F + ld (attr_screen), a + ld bc, 0 + call gotoXY + ld hl, head + call printZ64 + + ld a, #07 + ld (attr_screen), a + ret + +renderScreen: + call renderHeader + ld b, 20 +renderLp: + push bc + ld a, 20 + sub b + ld b, a + ld a, (show_offset) + add b + ld b, a + call renderLine + pop bc + djnz renderLp + ret + +; b - line number +renderLine: + call findLine + + ld a, h + or l + ret z + + ld a, (hl) + and a + ret z + inc hl + call printT64 + call mvCR + ret + +; B - line number +; HL - pointer to line(or zero if doesn't find it) +findLine: + ld hl, page_buffer +fndLnLp: + ld a, b + and a + ret z + + ld a, (hl) + + and a ; Buffer ends? + jr z, fndEnd + + cp 10 ; New line? + jr z, fndLnNL + inc hl + jp fndLnLp + +fndLnNL: + dec b + inc hl + jp fndLnLp +fndEnd: + ld hl, 0 + ret + +extractInfo: + ld a, (cursor_pos) + dec a + ld b, a + ld a, (show_offset) + add b + ld b, a + call findLine + ld a, h + cp l + ret z + + call findNextBlock + inc hl + ld de, file_buffer + call extractCol + inc hl + ld de, server_buffer + call extractCol + inc hl + ld de, port_buffer + call extractCol + ret + +extractCol: + ld a, (hl) + + cp 0 + jr z, endExtract + + cp 09 + jr z, endExtract + + cp 13 + jr z, endExtract + + ld (de), a + inc de + inc hl + jr extractCol + +endExtract: + xor a + ld (de), a + ret + +findNextBlock: + ld a, (hl) + + cp 09 ; TAB + ret z + + cp 13 ; New line + ret z + + cp 0 ; End buffer + ret z + + inc hl + jp findNextBlock + +show_offset db 0 + display $ +cursor_pos db 1 + +head db " UGophy - ZX-UNO Gopher client v. 0.1 (c) Alexander Sharikhin ",0 + +cleanLine db " ",0 + +type_text db "Text file: ", 0 +type_info db "Information ", 0 +type_page db "Page: ", 0 +type_down db "File to download: ", 0 +type_unkn db "Unknown type ", 0 + + display $ + +file_buffer defs 70 ; URI path +server_buffer defs 70 ; Host name +port_buffer defs 7 ; Port + +end_inf_buff equ $ + + + \ No newline at end of file diff --git a/ring.asm b/ring.asm new file mode 100644 index 0000000..2b13381 --- /dev/null +++ b/ring.asm @@ -0,0 +1,60 @@ +; Pushes A to ring buffer +pushRing + push af + ld b, 32 + ld hl, ring_buffer + 1 + ld de, ring_buffer +ringL + ld a, (hl) + ld (de), a + inc hl + inc de + djnz ringL + pop af + ld hl, ring_buffer + 31 + ld (hl), a + ret + +; HL - Compare string(null terminated) +; A - 0 NOT Found +; 1 Found +searchRing: + ld b, 0 + push hl +serlp: + ld a, (hl) + inc hl + inc b + and a + jp nz, serlp + dec b + pop hl + push bc + push hl +SRWork: + pop hl + ld de, ring_buffer + 32 +srcLp + dec de + djnz srcLp + pop bc +ringCmpLp + push bc + push af + ld a, (de) + ld b, a + pop af + ld a, (hl) + cp b + pop bc + ld a, 0 + ret nz + inc de + inc hl + djnz ringCmpLp + ld a, 1 + ret + +ring_buffer dup 33 + defb 0 + edup \ No newline at end of file diff --git a/screen64.asm b/screen64.asm new file mode 100644 index 0000000..e61cbe7 --- /dev/null +++ b/screen64.asm @@ -0,0 +1,414 @@ +clearScreen: + ld c, #fe + ld a, 0 + out (c), a + ld hl, #4000 + ld (hl), 0 + ld de, #4001 + ld bc, #17FF + ldir + ld hl, #5800 + ld a, (attr_screen) + ld (hl), a + ld de, #5801 + ld bc, #2FF + ldir + ld bc, 0 + call gotoXY + ret + +; +; Print just one symbol +; A - symbol +putC + cp 13 + jr z, mvCR + or a + cp ' ' + ret c + ld hl, single_symbol + ld (hl), a + ld hl, single_symbol_print + jp print64 + +mvCR + ld bc, (col_screen) + inc b + ld c, 0 + ld a, 0 + ld (half_tile_screen), a + call gotoXY + ret + +; Set console coordinates +; b = row(0..23), c = column (0..63) +; +gotoXY: + ld a, 0 + ld (half_tile_screen), a + ld (col_screen), bc + ld a, 22 + cp b + jp s, scrl + ret +scrl + ld b, 22 + ld (col_screen) ,bc + jp scroll_up8 + +; Print zero-terminated string +; HL - string pointer +putStringZ: +printZ64: + ld a,(hl) + and a + ret z + push hl + call putC + pop hl + inc hl + jr printZ64 + +printT64: + ld a, (hl) + + and a + ret z + + cp 09 + ret z + + push hl + call putC + pop hl + inc hl + jr printT64 + +printL64: + ld a, (hl) + + and a + ret z + + cp #0A + ret z + + cp #0D + ret z + + push hl + call putC + pop hl + inc hl + jr printL64 + + +; Put string with coordinates +; b= row (0..23), c=col (0..63) +; hl - string pointer that's begins from symbol count +printAt64: + call gotoXY + +; Put string +; hl - string pointer that's begins from symbol count +print64 + ld a,(hl) + and a + ret z + + push hl + call calc_addr_attr + ld a,(attr_screen) + ld (hl),a + pop hl + + call calc_addr_scr + + ld a,(half_tile_screen) + bit 0,a + ld a,(hl) + jp nz,print64_4 +print64_3 + push af + push hl + call calc_addr_attr + ld a,(attr_screen) + ld (hl),a + pop hl + + inc hl + push hl + + ld a,(hl) + sub 32 + ld l,a + ld h,0 + add hl,hl + ld c,l + ld b,h + add hl,hl + add hl,bc + ld bc,font64 + add hl,bc + + push de + + ld b,6 + xor a + ld (de),a +print64_1 + inc d + ld a,(hl) + and #f0 + ld (de),a + inc hl + djnz print64_1 + + inc d + xor a + ld (de),a + + ld a,1 + ld (half_tile_screen),a + + pop de + pop hl + pop af + + dec a + ret z + +print64_4 + push af + + inc hl + push hl + + ld a,(hl) + sub 32 + ld l,a + ld h,0 + add hl,hl + ld c,l + ld b,h + add hl,hl + add hl,bc + ld bc,font64 + add hl,bc + + push de + + ld b,6 + xor a + ld (de),a +print64_2 + inc d + ld a,(hl) + and #0f + ld c,a + ld a,(de) + or c + ld (de),a + inc hl + djnz print64_2 + + inc d + xor a + ld (de),a + + ld (half_tile_screen),a + + pop de + + call move_cr64 + + pop hl + pop af + dec a + + jp nz,print64_3 + + ret + +; move cursor +move_cr64 + inc de + + ld hl,col_screen + inc (hl) + ld a,(hl) + + cp 32 + ret c + + xor a + ld (half_tile_screen),a + ld (hl),a + ld c,a + + inc hl + inc (hl) + ld a,(hl) + ld b,a + + cp 24 + jp c,move_cr64_01 + + ld a,23 + ld (hl),a + ld b,a + + push bc + call scroll_up8 + pop bc + +move_cr64_01 + call calc_addr_scr + ret + +calc_addr_scr + ld a,b + ld d,a + rrca + rrca + rrca + and a,224 + add a,c + ld e,a + ld a,d + and 24 + or 64 + ld d,a + ret + +calc_addr_attr + ld bc,(col_screen) +bc_to_attr: + ld a,b + rrca + rrca + rrca + ld l,a + and 31 + or 88 + ld h,a + ld a,l + and 252 + or c + ld l,a + ret + +scroll_up8 + ld hl,table_addr_scr + ld b,184 + +scroll_up8_01 + push bc + + ld e,(hl) + inc hl + ld d,(hl) + inc hl + + push hl + + ld bc,14 + add hl,bc + ld c,(hl) + inc hl + ld b,(hl) + + ld h,b + ld l,c + + ld bc,32 + ldir + + pop hl + pop bc + djnz scroll_up8_01 + + ld b,8 + +scroll_up8_02 + push bc + + ld e,(hl) + inc hl + ld d,(hl) + inc hl + + push hl + + ld h,d + ld l,e + inc de + ld (hl),0 + ld bc,31 + ldir + + pop hl + pop bc + djnz scroll_up8_02 + + ld de,#5800 + ld hl,#5820 + ld bc,736 + ldir + + ld a,(de) + + ld hl,#5ae0 + ld de,#5ae1 + ld (hl),a + ld bc,31 + ldir + + ret + + +font64 incbin "font.bin" +table_addr_scr + defw #4000,#4100,#4200,#4300,#4400,#4500,#4600,#4700 + defw #4020,#4120,#4220,#4320,#4420,#4520,#4620,#4720 + defw #4040,#4140,#4240,#4340,#4440,#4540,#4640,#4740 + defw #4060,#4160,#4260,#4360,#4460,#4560,#4660,#4760 + defw #4080,#4180,#4280,#4380,#4480,#4580,#4680,#4780 + defw #40a0,#41a0,#42a0,#43a0,#44a0,#45a0,#46a0,#47a0 + defw #40c0,#41c0,#42c0,#43c0,#44c0,#45c0,#46c0,#47c0 + defw #40e0,#41e0,#42e0,#43e0,#44e0,#45e0,#46e0,#47e0 + + defw #4800,#4900,#4a00,#4b00,#4c00,#4d00,#4e00,#4f00 + defw #4820,#4920,#4a20,#4b20,#4c20,#4d20,#4e20,#4f20 + defw #4840,#4940,#4a40,#4b40,#4c40,#4d40,#4e40,#4f40 + defw #4860,#4960,#4a60,#4b60,#4c60,#4d60,#4e60,#4f60 + defw #4880,#4980,#4a80,#4b80,#4c80,#4d80,#4e80,#4f80 + defw #48a0,#49a0,#4aa0,#4ba0,#4ca0,#4da0,#4ea0,#4fa0 + defw #48c0,#49c0,#4ac0,#4bc0,#4cc0,#4dc0,#4ec0,#4fc0 + defw #48e0,#49e0,#4ae0,#4be0,#4ce0,#4de0,#4ee0,#4fe0 + + defw #5000,#5100,#5200,#5300,#5400,#5500,#5600,#5700 + defw #5020,#5120,#5220,#5320,#5420,#5520,#5620,#5720 + defw #5040,#5140,#5240,#5340,#5440,#5540,#5640,#5740 + defw #5060,#5160,#5260,#5360,#5460,#5560,#5660,#5760 + defw #5080,#5180,#5280,#5380,#5480,#5580,#5680,#5780 + defw #50a0,#51a0,#52a0,#53a0,#54a0,#55a0,#56a0,#57a0 + defw #50c0,#51c0,#52c0,#53c0,#54c0,#55c0,#56c0,#57c0 + defw #50e0,#51e0,#52e0,#53e0,#54e0,#55e0,#56e0,#57e0 + + +string_temp defb 0 + dup 255 + defb 32 + edup + +col_screen defb 0 +row_screen defb 0 +half_tile_screen defb 0 +attr_screen defb 07 + +col_screen_temp defw 0 +half_tile_screen_temp defb 0 + +single_symbol_print defb 1 +single_symbol defb 0 \ No newline at end of file diff --git a/textrender.asm b/textrender.asm new file mode 100644 index 0000000..3070d9e --- /dev/null +++ b/textrender.asm @@ -0,0 +1,78 @@ +showText: + xor a + ld (show_offset), a + call renderTextScreen +showTxLp: + call txControls + dup 5 + halt + edup + jp showTxLp + +txControls: + call inkey + + and a + ret z + + cp 'q' + jp z, txUp + + cp 'a' + jp z, txDn + + cp 'b' + jp z, historyBack + + cp 'o' + jp z, openURI + + ret + +txUp: + ld a, (show_offset) + and a + ret z + + sub 20 + ld (show_offset), a + call renderTextScreen + ret + +txDn: + ld a, (show_offset) + add 20 + ld (show_offset), a + call renderTextScreen + ret + +renderTextScreen: + call renderHeader + ld b, 20 +txRenderLp: + push bc + ld a, 20 + sub b + ld b, a + ld a, (show_offset) + add b + ld b, a + call renderTextLine + pop bc + djnz txRenderLp + ret + + +renderTextLine: + call findLine + + ld a, h + or l + ret z + + ld a, (hl) + and a + ret z + call printL64 + call mvCR + ret \ No newline at end of file diff --git a/uart.asm b/uart.asm new file mode 100644 index 0000000..c0820ed --- /dev/null +++ b/uart.asm @@ -0,0 +1,194 @@ +UART_DATA_REG = #c6 +UART_STAT_REG = #c7 +UART_BYTE_RECIVED = #80 +UART_BYTE_SENT = #40 +ZXUNO_ADDR = #FC3B +ZXUNO_REG = #FD3B + +; Enable UART +; Cleaning all flags by reading UART regs +; Wastes AF and BC +uartBegin: + ld bc, ZXUNO_ADDR + ld a, UART_STAT_REG + out (c), a + + ld bc, ZXUNO_REG + in A, (c) + + ld bc, ZXUNO_ADDR + ld a, UART_DATA_REG + out (c), a + + ld bc, ZXUNO_REG + in A, (c) + ret + +; Pushes to UART zero-terminated string +; HL - string poiner +uartWriteStringZ: + ld a, (hl) + and a + ret z + push hl + call uartWriteByte + pop hl + inc hl + jp uartWriteStringZ + +; Blocking read one byte +uartReadBlocking: + call uartRead + push af + ld a, 1 + cp b + jr z, urb + pop af + ret nz + jp uartReadBlocking +urb: + pop af + ret + +; Write single byte to UART +; A - byte to write +; BC will be wasted +uartWriteByte: + push af + ld bc, ZXUNO_ADDR + ld a, UART_STAT_REG + out (c), a + +waitWriteReady: + ld bc, ZXUNO_REG + in A, (c) + and UART_BYTE_RECIVED + jr nz, is_recvF +checkSent: + ld bc, ZXUNO_REG + in A, (c) + and UART_BYTE_SENT + jr nz, checkSent + + ld bc, ZXUNO_ADDR + ld a, UART_DATA_REG + out (c), a + ld bc, ZXUNO_REG + pop af + out (c), a + ret +is_recvF: + push af + push hl + ld hl, is_recv + ld a, 1 + ld (hl), a + pop hl + pop af + jr checkSent + +; Is data avail in UART +; NZ - Data Presents +; Z - Data absent +uartAvail: + ld a, (is_recv) + and 1 + ret nz + + ld a, (poked_byte) + and 1 + ret nz + + call uartRead + + push af + ld a, b + and 1 + jr z, noneData + pop af + push af + ld hl, byte_buff + ld (hl), a + ld hl, poked_byte + ld a, 1 + ld (hl), a + pop af + ld b, a + ld a, 1 + or a + ld a, b + ret +noneData: + pop bc + xor a + ret + +; Read byte from UART +; A: byte +; B: +; 1 - Was read +; 0 - Nothing to read +uartRead: + ld a, (poked_byte) + and 1 + jr nz, retBuff + + ld a, (is_recv) + and 1 + jr nz, recvRet + + ld bc, ZXUNO_ADDR + ld a, UART_STAT_REG + out (c), a + + ld bc, ZXUNO_REG + in a, (c) + and UART_BYTE_RECIVED + jr nz, retReadByte + + ld b, 0 + ret + +retReadByte: + ld a, 0 + ld (poked_byte), a + ld (is_recv), a + + ld bc, ZXUNO_ADDR + ld a, UART_DATA_REG + out (c), a + + ld bc, ZXUNO_REG + in a, (c) + + ld b, 1 + ret + +recvRet: + ld bc, ZXUNO_ADDR + ld a, UART_DATA_REG + out (c),a + + ld bc, ZXUNO_REG + in a, (c) + + ld hl, is_recv + ld (hl), 0 + + ld hl, poked_byte + ld (hl), 0 + + ld b, 1 + ret + +retBuff + ld a, 0 + ld (poked_byte), a + + ld a, (byte_buff) + ld b, 1 + ret + +poked_byte defb 0 +byte_buff defb 0 +is_recv defb 0 \ No newline at end of file diff --git a/utils.asm b/utils.asm new file mode 100644 index 0000000..59ced8a --- /dev/null +++ b/utils.asm @@ -0,0 +1,140 @@ +; HL - string +; Return: bc - len +getStringLength: + ld bc, 0 +strLnLp + ld a, (hl) + and a + ret z + inc bc + inc hl + jr strLnLp + +SkipWhitespace: + ld a, (hl) + cp ' ' + ret nz + inc hl + jr SkipWhitespace + +;;;;;;;;;;;;;;;;;;;;;;;; + +; Binary to decimal stuff +; From https://www.msx.org/forum/development/msx-development/32-bit-long-ascii + +; Combined routine for conversion of different sized binary numbers into +; directly printable ASCII(Z)-string +; Input value in registers, number size and -related to that- registers to fill +; is selected by calling the correct entry: +; +; entry inputregister(s) decimal value 0 to: +; B2D8 A 255 (3 digits) +; B2D16 HL 65535 5 " +; B2D24 E:HL 16777215 8 " +; B2D32 DE:HL 4294967295 10 " +; B2D48 BC:DE:HL 281474976710655 15 " +; B2D64 IX:BC:DE:HL 18446744073709551615 20 " +; +; The resulting string is placed into a small buffer attached to this routine, +; this buffer needs no initialization and can be modified as desired. +; The number is aligned to the right, and leading 0's are replaced with spaces. +; On exit HL points to the first digit, (B)C = number of decimals +; This way any re-alignment / postprocessing is made easy. +; Changes: AF,BC,DE,HL,IX +; P.S. some examples below + +; by Alwin Henseler + +B2D8: LD H,0 + LD L,A +B2D16: LD E,0 +B2D24: LD D,0 +B2D32: LD BC,0 +B2D48: LD IX,0 ; zero all non-used bits +B2D64: LD (B2DINV),HL + LD (B2DINV+2),DE + LD (B2DINV+4),BC + LD (B2DINV+6),IX ; place full 64-bit input value in buffer + LD HL,B2DBUF + LD DE,B2DBUF+1 + LD (HL)," " +B2DFILC: EQU $-1 ; address of fill-character + LD BC,18 + LDIR ; fill 1st 19 bytes of buffer with spaces + LD (B2DEND-1),BC ;set BCD value to "0" & place terminating 0 + LD E,1 ; no. of bytes in BCD value + LD HL,B2DINV+8 ; (address MSB input)+1 + LD BC,0x0909 + XOR A +B2DSKP0: DEC B + JR Z,B2DSIZ ; all 0: continue with postprocessing + DEC HL + OR (HL) ; find first byte <>0 + JR Z,B2DSKP0 +B2DFND1: DEC C + RLA + JR NC,B2DFND1 ; determine no. of most significant 1-bit + RRA + LD D,A ; byte from binary input value +B2DLUS2: PUSH HL + PUSH BC +B2DLUS1: LD HL,B2DEND-1 ; address LSB of BCD value + LD B,E ; current length of BCD value in bytes + RL D ; highest bit from input value -> carry +B2DLUS0: LD A,(HL) + ADC A,A + DAA + LD (HL),A ; double 1 BCD byte from intermediate result + DEC HL + DJNZ B2DLUS0 ; and go on to double entire BCD value (+carry!) + JR NC,B2DNXT + INC E ; carry at MSB -> BCD value grew 1 byte larger + LD (HL),1 ; initialize new MSB of BCD value +B2DNXT: DEC C + JR NZ,B2DLUS1 ; repeat for remaining bits from 1 input byte + POP BC ; no. of remaining bytes in input value + LD C,8 ; reset bit-counter + POP HL ; pointer to byte from input value + DEC HL + LD D,(HL) ; get next group of 8 bits + DJNZ B2DLUS2 ; and repeat until last byte from input value +B2DSIZ: LD HL,B2DEND ; address of terminating 0 + LD C,E ; size of BCD value in bytes + OR A + SBC HL,BC ; calculate address of MSB BCD + LD D,H + LD E,L + SBC HL,BC + EX DE,HL ; HL=address BCD value, DE=start of decimal value + LD B,C ; no. of bytes BCD + SLA C ; no. of bytes decimal (possibly 1 too high) + LD A,"0" + RLD ; shift bits 4-7 of (HL) into bit 0-3 of A + CP "0" ; (HL) was > 9h? + JR NZ,B2DEXPH ; if yes, start with recording high digit + DEC C ; correct number of decimals + INC DE ; correct start address + JR B2DEXPL ; continue with converting low digit +B2DEXP: RLD ; shift high digit (HL) into low digit of A +B2DEXPH: LD (DE),A ; record resulting ASCII-code + INC DE +B2DEXPL: RLD + LD (DE),A + INC DE + INC HL ; next BCD-byte + DJNZ B2DEXP ; and go on to convert each BCD-byte into 2 ASCII + SBC HL,BC ; return with HL pointing to 1st decimal + RET + +AppendB2D: +; Append results of B2D to string at HL + ex de, hl ; Get destination into DE + ld hl, B2DBUF + call SkipWhitespace + ldir + ex de, hl ; Get destination into DE + ret + +B2DINV: DS 8 ; space for 64-bit input value (LSB first) +B2DBUF: DS 20 ; space for 20 decimal digits +B2DEND: DB 0 ; space for terminating 0 \ No newline at end of file diff --git a/wifi.asm b/wifi.asm new file mode 100644 index 0000000..92cc7d1 --- /dev/null +++ b/wifi.asm @@ -0,0 +1,258 @@ +; Initialize WiFi chip and connect to WiFi +initWifi: + call loadWiFiConfig + + ld hl, cmd_plus + call uartWriteStringZ + ld b,#ff +wlp: + push bc + ld b, #ff + djnz $ + pop bc + djnz wlp + + ld hl, cmd_rst + call uartWriteStringZ +rstLp: + call uartReadBlocking + call pushRing + ld hl, response_rdy + call searchRing + cp 1 + jr nz, rstLp + + ld hl, cmd_at ; Disable ECHO. BTW Basic UART test + call okErrCmd + and 1 + jr z, errInit + + ld hl, cmd_cwqap ; Lets disconnect from last AP + call okErrCmd + and 1 + jr z, errInit + + ld hl, cmd_cmux ; Single connection mode + call okErrCmd + and 1 + jr z, errInit + + ld hl, cmd_inf_off ; FTP enables this info? We doesn't need it :-) + call okErrCmd + and 1 + jr z, errInit + + ld hl, cmd_cwjap1 ; Access Point connection + call uartWriteStringZ + ld hl, ssid + call uartWriteStringZ + ld hl, cmd_cwjap2 + call uartWriteStringZ + ld hl, pass + call uartWriteStringZ + ld hl, cmd_cwjap3 + call okErrCmd + and 1 + jr z, errInit + + ld hl, log_ok + call putStringZ + + ret +errInit + ld hl, log_err + call putStringZ + jr $ + + +; Send AT-command and wait for result. +; HL - Z-terminated AT-command(with CR/LF) +; A: +; 1 - Success +; 0 - Failed +okErrCmd: + call uartWriteStringZ +okErrCmdLp: + call uartReadBlocking + call pushRing + + ld hl, response_ok + call searchRing + cp 1 + jr z, okErrOk + + ld hl, response_err + call searchRing + cp 1 + jr z, okErrErr + + ld hl, response_fail + call searchRing + cp 1 + jr z, okErrErr + + + jp okErrCmdLp +okErrOk + ld a, 1 + ret +okErrErr + ld a, 0 + ret + +; Gets packet from network +; packet will be in var 'output_buffer' +; received packet size in var 'bytes_avail' +; +; If connection was closed it calls 'closed_callback' +getPacket + call uartReadBlocking + call pushRing + + ld hl, closed + call searchRing + cp 1 + jp z, closed_callback + + ld hl, ipd + call searchRing + cp 1 + jr nz, getPacket + + call count_ipd_lenght + ld (bytes_avail), hl + push hl + pop bc + ld hl, output_buffer +readp: + push bc + push hl + call uartReadBlocking + pop hl + ld (hl), a + pop bc + dec bc + inc hl + ld a, b + or c + jr nz, readp + ld hl, (bytes_avail) + ret + +count_ipd_lenght + ld hl,0 ; count lenght +cil1 push hl + call uartReadBlocking + push af + call pushRing + pop af + pop hl + 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 + +; HL - z-string to hostname or ip +; DE - z-string to port +startTcp: + push de + push hl + ld hl, cmd_open1 + call uartWriteStringZ + pop hl + call uartWriteStringZ + ld hl, cmd_open2 + call uartWriteStringZ + pop de + call uartWriteStringZ + ld hl, cmd_open3 + call okErrCmd + ret + +; Returns: +; A: 1 - Success +; 0 - Failed +sendByte: + push af + ld hl, cmd_send_b + call okErrCmd + cp 1 + jr nz, sbErr +sbLp + call uartReadBlocking + ld hl, send_prompt + call searchRing + cp 1 + jr nz, sbLp + pop af + ld (sbyte_buff), a + call okErrCmd + ret +sbErr: + pop af + ld a, 0 + ret + +loadWiFiConfig: + ld b, FMODE_READ + ld hl, conf_file + call fopen + + push af + ld hl, ssid + ld bc, 160 + call fread + pop af + + call fclose + ret +cmd_plus defb "+++", 0 +cmd_rst defb "AT+RST",13, 10, 0 +cmd_at defb "ATE0", 13, 10, 0 ; Disable echo - less to parse +cmd_mode defb "AT+CWMODE_DEF=1",13,10,0 ; Client mode +cmd_cmux defb "AT+CIPMUX=0",13,10,0 ; Single connection mode +cmd_cwqap defb "AT+CWQAP",13,10,0 ; Disconnect from AP +cmd_inf_off defb "AT+CIPDINFO=0",13,10,0 ; doesn't send me info about remote port and ip + +cmd_cwjap1 defb "AT+CWJAP_CUR=", #22,0 ;Connect to AP. Send this -> SSID +cmd_cwjap2 defb #22,',',#22,0 ; -> This -> Password +cmd_cwjap3 defb #22, 13, 10, 0 ; -> And this + +cmd_open1 defb "AT+CIPSTART=", #22, "TCP", #22, ",", #22, 0 +cmd_open2 defb #22, ",", 0 +cmd_open3 defb 13, 10, 0 +cmd_send defb "AT+CIPSEND=", 0 +cmd_close defb "AT+CIPCLOSE",13,10,0 +cmd_send_b defb "AT+CIPSEND=1", 13, 10,0 +closed defb "CLOSED", 13, 10, 0 +ipd defb 13, 10, "+IPD,", 0 +crlf defb 13,10, 0 + +response_rdy defb 'ready', 0 +response_ok defb 'OK', 13, 10, 0 ; Sucessful operation +response_err defb 13,10,'ERROR',13,10,0 ; Failed operation +response_fail defb 13,10,'FAIL',13,10,0 ; Failed connection to WiFi. For us same as ERROR + +log_err defb 'Failed connect to WiFi!',13, 0 +log_ok defb 'WiFi connected!', 13, 0 + +ssid defs 80 +pass defs 80 + +bytes_avail defw 0 +sbyte_buff defb 0, 0 + +send_prompt defb ">",0 +output_buffer defs 2048 ; buffer for downloading data + +; WiFi configuration +conf_file defb "/sys/config/iw.cfg",0 \ No newline at end of file