From 2973d0c78e9b8eed3c5af239927c6bd36af64604 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Wed, 13 Mar 2019 02:50:42 -0400 Subject: initial commit --- README | 191 + doc/Compatibility.txt | 33 + doc/HOWTO | 161 + doc/README | 396 + doc/about.txt | 35 + doc/newdesign.txt | 81 + doc/notes.txt | 281 + src/ChangeLog | 349 + src/Makefile | 102 + src/Makefile.include | 47 + src/Makefile.webclient.ok | 50 + src/about.c | 53 + src/aexec.dasm | 206 + src/aexec.h | 7 + src/aextest.dasm | 52 + src/aextest2.dasm | 27 + src/atari850.ser | Bin 0 -> 88 bytes src/atariserver.sh | 33 + src/atariserver_slip.sh | 70 + src/atariserver_slirp.sh | 48 + src/bobvert.com | Bin 0 -> 1369 bytes src/clear_rts | Bin 0 -> 11016 bytes src/clear_rts.c | 42 + src/clock-arch.c | 49 + src/clock-arch.h | 41 + src/col64/autorun.sys | Bin 0 -> 1039 bytes src/col64/col64.bin | Bin 0 -> 1039 bytes src/col64/col64.dasm | 1194 +++ src/col64/col64_ext.inc | 48 + src/col64/cruft/col64.dasm | 1194 +++ src/col64/cruft/col64.dasm.works | 731 ++ src/col64/cruft/col64.sh | 6 + src/col64/cruft/col64_ext.inc | 48 + src/col64/cruft/col64font.bdf | 11993 ++++++++++++++++++++++++ src/col64/cruft/col64font.hex | 920 ++ src/col64/cruft/col64font_almost.bdf | 11994 +++++++++++++++++++++++++ src/col64/cruft/col64font_ext.bdf | 11994 +++++++++++++++++++++++++ src/col64/cruft/col64font_ext.hex | 920 ++ src/col64/cruft/col64font_new.bdf | 11994 +++++++++++++++++++++++++ src/col64/cruft/coltbl.pl | 17 + src/col64/equates.inc | 1386 +++ src/col64/font4x5.inc | 48 + src/col64/test.atr | Bin 0 -> 92176 bytes src/col80_modified/Makefile | 15 + src/col80_modified/autorun.sys | Bin 0 -> 1152 bytes src/col80_modified/col80_hacked.dasm | 906 ++ src/col80_modified/col80_hacked.xex | Bin 0 -> 1152 bytes src/col80_modified/cruft/Makefile | 45 + src/col80_modified/cruft/README.txt | 89 + src/col80_modified/cruft/autorun.sys | Bin 0 -> 1095 bytes src/col80_modified/cruft/col80.atasm | 6 + src/col80_modified/cruft/col80.dasm | 10 + src/col80_modified/cruft/col80.info | 152 + src/col80_modified/cruft/col80.s | 21 + src/col80_modified/cruft/col80.xex | Bin 0 -> 1163 bytes src/col80_modified/cruft/col80_cc65_hack.cfg | 41 + src/col80_modified/cruft/col80_dosini_seg.s | 12 + src/col80_modified/cruft/col80_entry.s | 61 + src/col80_modified/cruft/col80_header_seg.s | 6 + src/col80_modified/cruft/col80_include.s | 50 + src/col80_modified/cruft/col80_init.s | 35 + src/col80_modified/cruft/col80_main.s | 824 ++ src/col80_modified/cruft/col80_main.s.orig | 895 ++ src/col80_modified/cruft/col80_main.xex | Bin 0 -> 1047 bytes src/col80_modified/cruft/col80_orig.xex | Bin 0 -> 1429 bytes src/col80_modified/cruft/col80_runad_seg.s | 13 + src/col80_modified/cruft/col80_startaddr.s | 7 + src/col80_modified/cruft/col80_startup.s | 4 + src/col80_modified/cruft/dasm2atasm | 362 + src/col80_modified/cruft/dos_20s.atr | Bin 0 -> 92176 bytes src/col80_modified/cruft/font.bin | Bin 0 -> 384 bytes src/col80_modified/cruft/font.s | 54 + src/col80_modified/cruft/font2xbm.pl | 47 + src/col80_modified/cruft/new_font.s | 48 + src/col80_modified/cruft/new_font.xbm | 35 + src/col80_modified/cruft/test.atr | Bin 0 -> 92176 bytes src/col80_modified/cruft/xbm2font.pl | 29 + src/col80_modified/dos_20s.atr | Bin 0 -> 92176 bytes src/col80_modified/font2xbm.pl | 48 + src/col80_modified/icet.xbm | 43 + src/col80_modified/icet_packed.fnt | Bin 0 -> 512 bytes src/col80_modified/icet_to_col80 | Bin 0 -> 8996 bytes src/col80_modified/icet_to_col80.c | 26 + src/col80_modified/icet_vt.fnt | Bin 0 -> 1024 bytes src/col80_modified/icetmod.raw | Bin 0 -> 384 bytes src/col80_modified/icetmod.s | 48 + src/col80_modified/icetmod.xbm | 35 + src/col80_modified/icetmod_maybe.xbm | 35 + src/col80_modified/icetmod_old.xbm | 35 + src/col80_modified/lsr.pl | 29 + src/col80_modified/new_font.s | 48 + src/col80_modified/t.dasm | 3 + src/col80_modified/test.atr | Bin 0 -> 92176 bytes src/col80_modified/xbm2font.pl | 29 + src/commands.c | 206 + src/common.c | 255 + src/common.h | 27 + src/dns.c | 130 + src/dos25_4drives.atr | Bin 0 -> 92176 bytes src/dos_20s.atr | Bin 0 -> 92176 bytes src/env.sh | 10 + src/equates.inc | 1386 +++ src/features.h | 102 + src/fuji6432.atr | Bin 0 -> 92176 bytes src/fuji80.atr | Bin 0 -> 92176 bytes src/fuji_asm.s | 3016 +++++++ src/fujichat-0.1.atr | Bin 0 -> 92176 bytes src/fujichat-0.3.atr | Bin 0 -> 92176 bytes src/fujichat.atr | Bin 0 -> 92176 bytes src/fujichat.atr.ok | Bin 0 -> 92176 bytes src/fujichat.c | 1054 +++ src/fujichat.cfg | Bin 0 -> 173 bytes src/fujichat.h | 136 + src/fujiconf.c | 359 + src/fujimenu.c | 90 + src/fujiput.s | 21 + src/fujitest.atr | Bin 0 -> 92176 bytes src/getsmess.c | 66 + src/hex2inc.pl | 31 + src/irc_notes | 95 + src/keybuf.h | 26 + src/keybuf.s | 94 + src/keybuftest.c | 51 + src/loadchat.dasm | 54 + src/loadmenu.dasm | 69 + src/loadmkau.dasm | 69 + src/loadtest.c | 12 + src/logcomptest.pl | 229 + src/logtest.c | 53 + src/main.c | 1184 +++ src/makeauto.c | 177 + src/mkdisk.sh | 48 + src/mkfuji64.sh | 4 + src/mkfuji80.sh | 4 + src/new_format_ip.s | 54 + src/notes.64x34 | 176 + src/prconn.ser | Bin 0 -> 94 bytes src/put.c | 12 + src/rs232dev.c | 299 + src/rs232dev.h | 54 + src/rvert.com | Bin 0 -> 1369 bytes src/slattach_rts.diff | 26 + src/slirp_debug | 2 + src/start_getty.sh | 19 + src/start_slip.sh | 56 + src/start_slirp.sh | 29 + src/test.atr | Bin 0 -> 92176 bytes src/testip.c | 10 + src/uip-conf.h | 180 + src/uip_arch.h | 0 src/uip_asm_output.s | 5253 +++++++++++ uip/README.uIP | 13 + uip/apps/README | 2 + uip/apps/dhcpc/Makefile.dhcpc | 1 + uip/apps/dhcpc/dhcpc.c | 356 + uip/apps/dhcpc/dhcpc.h | 68 + uip/apps/hello-world/Makefile.hello-world | 1 + uip/apps/hello-world/hello-world.c | 100 + uip/apps/hello-world/hello-world.h | 52 + uip/apps/resolv/Makefile.resolv | 1 + uip/apps/resolv/resolv.c | 464 + uip/apps/resolv/resolv.h | 75 + uip/apps/smtp/Makefile.smtp | 1 + uip/apps/smtp/makestrings | 40 + uip/apps/smtp/smtp-strings | 11 + uip/apps/smtp/smtp-strings.c | 70 + uip/apps/smtp/smtp-strings.h | 46 + uip/apps/smtp/smtp.c | 262 + uip/apps/smtp/smtp.h | 103 + uip/apps/telnet/Makefile.telnet | 1 + uip/apps/telnet/telnet.c | 151 + uip/apps/telnet/telnet.h | 67 + uip/apps/telnetd/Makefile.telnetd | 1 + uip/apps/telnetd/shell.c | 123 + uip/apps/telnetd/shell.h | 104 + uip/apps/telnetd/telnetd.c | 350 + uip/apps/telnetd/telnetd.h | 63 + uip/apps/webclient/Makefile.webclient | 1 + uip/apps/webclient/makestrings | 40 + uip/apps/webclient/webclient-strings | 31 + uip/apps/webclient/webclient-strings.c | 93 + uip/apps/webclient/webclient-strings.h | 31 + uip/apps/webclient/webclient.c | 439 + uip/apps/webclient/webclient.h | 228 + uip/apps/webserver/Makefile.webserver | 1 + uip/apps/webserver/http-strings | 35 + uip/apps/webserver/http-strings.c | 102 + uip/apps/webserver/http-strings.h | 34 + uip/apps/webserver/httpd-cgi.c | 203 + uip/apps/webserver/httpd-cgi.h | 84 + uip/apps/webserver/httpd-fs.c | 132 + uip/apps/webserver/httpd-fs.h | 57 + uip/apps/webserver/httpd-fs/404.html | 8 + uip/apps/webserver/httpd-fs/fade.png | Bin 0 -> 196 bytes uip/apps/webserver/httpd-fs/files.shtml | 35 + uip/apps/webserver/httpd-fs/footer.html | 2 + uip/apps/webserver/httpd-fs/header.html | 18 + uip/apps/webserver/httpd-fs/index.html | 29 + uip/apps/webserver/httpd-fs/processes.shtml | 5 + uip/apps/webserver/httpd-fs/stats.shtml | 31 + uip/apps/webserver/httpd-fs/style.css | 92 + uip/apps/webserver/httpd-fs/tcp.shtml | 5 + uip/apps/webserver/httpd-fsdata.c | 607 ++ uip/apps/webserver/httpd-fsdata.h | 64 + uip/apps/webserver/httpd.c | 338 + uip/apps/webserver/httpd.h | 62 + uip/apps/webserver/makefsdata | 78 + uip/apps/webserver/makestrings | 40 + uip/apps/webserver/webserver.h | 49 + uip/lib/memb.c | 104 + uip/lib/memb.h | 142 + uip/uip-1.0-changelog.txt | 98 + uip/uip/Makefile.include | 47 + uip/uip/clock.h | 88 + uip/uip/lc-addrlabels.h | 83 + uip/uip/lc-switch.h | 76 + uip/uip/lc.h | 131 + uip/uip/psock.c | 338 + uip/uip/psock.h | 380 + uip/uip/pt.h | 323 + uip/uip/timer.c | 127 + uip/uip/timer.h | 86 + uip/uip/uip-fw.c | 532 ++ uip/uip/uip-fw.h | 176 + uip/uip/uip-neighbor.c | 159 + uip/uip/uip-neighbor.h | 61 + uip/uip/uip-split.c | 136 + uip/uip/uip-split.h | 96 + uip/uip/uip.c | 1912 ++++ uip/uip/uip.h | 1603 ++++ uip/uip/uip_arch.h | 138 + uip/uip/uip_arp.c | 423 + uip/uip/uip_arp.h | 144 + uip/uip/uiplib.c | 74 + uip/uip/uiplib.h | 71 + uip/uip/uipopt.h | 544 ++ uip/unix/Makefile | 44 + uip/unix/clock-arch.c | 55 + uip/unix/clock-arch.h | 40 + uip/unix/main.c | 218 + uip/unix/tapdev.c | 152 + uip/unix/tapdev.h | 45 + uip/unix/uip-conf.h | 157 + 243 files changed, 90518 insertions(+) create mode 100644 README create mode 100644 doc/Compatibility.txt create mode 100644 doc/HOWTO create mode 100644 doc/README create mode 100644 doc/about.txt create mode 100644 doc/newdesign.txt create mode 100644 doc/notes.txt create mode 100644 src/ChangeLog create mode 100644 src/Makefile create mode 100644 src/Makefile.include create mode 100644 src/Makefile.webclient.ok create mode 100644 src/about.c create mode 100644 src/aexec.dasm create mode 100644 src/aexec.h create mode 100644 src/aextest.dasm create mode 100644 src/aextest2.dasm create mode 100644 src/atari850.ser create mode 100755 src/atariserver.sh create mode 100755 src/atariserver_slip.sh create mode 100755 src/atariserver_slirp.sh create mode 100644 src/bobvert.com create mode 100755 src/clear_rts create mode 100644 src/clear_rts.c create mode 100644 src/clock-arch.c create mode 100644 src/clock-arch.h create mode 100644 src/col64/autorun.sys create mode 100644 src/col64/col64.bin create mode 100644 src/col64/col64.dasm create mode 100644 src/col64/col64_ext.inc create mode 100644 src/col64/cruft/col64.dasm create mode 100644 src/col64/cruft/col64.dasm.works create mode 100644 src/col64/cruft/col64.sh create mode 100644 src/col64/cruft/col64_ext.inc create mode 100644 src/col64/cruft/col64font.bdf create mode 100644 src/col64/cruft/col64font.hex create mode 100644 src/col64/cruft/col64font_almost.bdf create mode 100644 src/col64/cruft/col64font_ext.bdf create mode 100644 src/col64/cruft/col64font_ext.hex create mode 100644 src/col64/cruft/col64font_new.bdf create mode 100644 src/col64/cruft/coltbl.pl create mode 100644 src/col64/equates.inc create mode 100644 src/col64/font4x5.inc create mode 100644 src/col64/test.atr create mode 100644 src/col80_modified/Makefile create mode 100644 src/col80_modified/autorun.sys create mode 100644 src/col80_modified/col80_hacked.dasm create mode 100644 src/col80_modified/col80_hacked.xex create mode 100644 src/col80_modified/cruft/Makefile create mode 100644 src/col80_modified/cruft/README.txt create mode 100644 src/col80_modified/cruft/autorun.sys create mode 100644 src/col80_modified/cruft/col80.atasm create mode 100644 src/col80_modified/cruft/col80.dasm create mode 100644 src/col80_modified/cruft/col80.info create mode 100644 src/col80_modified/cruft/col80.s create mode 100644 src/col80_modified/cruft/col80.xex create mode 100644 src/col80_modified/cruft/col80_cc65_hack.cfg create mode 100644 src/col80_modified/cruft/col80_dosini_seg.s create mode 100644 src/col80_modified/cruft/col80_entry.s create mode 100644 src/col80_modified/cruft/col80_header_seg.s create mode 100644 src/col80_modified/cruft/col80_include.s create mode 100644 src/col80_modified/cruft/col80_init.s create mode 100644 src/col80_modified/cruft/col80_main.s create mode 100644 src/col80_modified/cruft/col80_main.s.orig create mode 100644 src/col80_modified/cruft/col80_main.xex create mode 100644 src/col80_modified/cruft/col80_orig.xex create mode 100644 src/col80_modified/cruft/col80_runad_seg.s create mode 100644 src/col80_modified/cruft/col80_startaddr.s create mode 100644 src/col80_modified/cruft/col80_startup.s create mode 100755 src/col80_modified/cruft/dasm2atasm create mode 100755 src/col80_modified/cruft/dos_20s.atr create mode 100644 src/col80_modified/cruft/font.bin create mode 100644 src/col80_modified/cruft/font.s create mode 100644 src/col80_modified/cruft/font2xbm.pl create mode 100644 src/col80_modified/cruft/new_font.s create mode 100644 src/col80_modified/cruft/new_font.xbm create mode 100755 src/col80_modified/cruft/test.atr create mode 100644 src/col80_modified/cruft/xbm2font.pl create mode 100755 src/col80_modified/dos_20s.atr create mode 100644 src/col80_modified/font2xbm.pl create mode 100644 src/col80_modified/icet.xbm create mode 100644 src/col80_modified/icet_packed.fnt create mode 100755 src/col80_modified/icet_to_col80 create mode 100644 src/col80_modified/icet_to_col80.c create mode 100644 src/col80_modified/icet_vt.fnt create mode 100644 src/col80_modified/icetmod.raw create mode 100644 src/col80_modified/icetmod.s create mode 100644 src/col80_modified/icetmod.xbm create mode 100644 src/col80_modified/icetmod_maybe.xbm create mode 100644 src/col80_modified/icetmod_old.xbm create mode 100644 src/col80_modified/lsr.pl create mode 100644 src/col80_modified/new_font.s create mode 100644 src/col80_modified/t.dasm create mode 100755 src/col80_modified/test.atr create mode 100644 src/col80_modified/xbm2font.pl create mode 100644 src/commands.c create mode 100644 src/common.c create mode 100644 src/common.h create mode 100644 src/dns.c create mode 100644 src/dos25_4drives.atr create mode 100644 src/dos_20s.atr create mode 100644 src/env.sh create mode 100644 src/equates.inc create mode 100644 src/features.h create mode 100644 src/fuji6432.atr create mode 100644 src/fuji80.atr create mode 100644 src/fuji_asm.s create mode 100644 src/fujichat-0.1.atr create mode 100644 src/fujichat-0.3.atr create mode 100644 src/fujichat.atr create mode 100644 src/fujichat.atr.ok create mode 100644 src/fujichat.c create mode 100644 src/fujichat.cfg create mode 100644 src/fujichat.h create mode 100644 src/fujiconf.c create mode 100644 src/fujimenu.c create mode 100644 src/fujiput.s create mode 100644 src/fujitest.atr create mode 100644 src/getsmess.c create mode 100644 src/hex2inc.pl create mode 100644 src/irc_notes create mode 100644 src/keybuf.h create mode 100644 src/keybuf.s create mode 100644 src/keybuftest.c create mode 100644 src/loadchat.dasm create mode 100644 src/loadmenu.dasm create mode 100644 src/loadmkau.dasm create mode 100644 src/loadtest.c create mode 100644 src/logcomptest.pl create mode 100644 src/logtest.c create mode 100644 src/main.c create mode 100644 src/makeauto.c create mode 100644 src/mkdisk.sh create mode 100644 src/mkfuji64.sh create mode 100644 src/mkfuji80.sh create mode 100644 src/new_format_ip.s create mode 100644 src/notes.64x34 create mode 100644 src/prconn.ser create mode 100644 src/put.c create mode 100644 src/rs232dev.c create mode 100644 src/rs232dev.h create mode 100644 src/rvert.com create mode 100644 src/slattach_rts.diff create mode 100644 src/slirp_debug create mode 100644 src/start_getty.sh create mode 100755 src/start_slip.sh create mode 100644 src/start_slirp.sh create mode 100644 src/test.atr create mode 100644 src/testip.c create mode 100644 src/uip-conf.h create mode 100644 src/uip_arch.h create mode 100644 src/uip_asm_output.s create mode 100644 uip/README.uIP create mode 100644 uip/apps/README create mode 100644 uip/apps/dhcpc/Makefile.dhcpc create mode 100644 uip/apps/dhcpc/dhcpc.c create mode 100644 uip/apps/dhcpc/dhcpc.h create mode 100644 uip/apps/hello-world/Makefile.hello-world create mode 100644 uip/apps/hello-world/hello-world.c create mode 100644 uip/apps/hello-world/hello-world.h create mode 100644 uip/apps/resolv/Makefile.resolv create mode 100644 uip/apps/resolv/resolv.c create mode 100644 uip/apps/resolv/resolv.h create mode 100644 uip/apps/smtp/Makefile.smtp create mode 100755 uip/apps/smtp/makestrings create mode 100644 uip/apps/smtp/smtp-strings create mode 100644 uip/apps/smtp/smtp-strings.c create mode 100644 uip/apps/smtp/smtp-strings.h create mode 100644 uip/apps/smtp/smtp.c create mode 100644 uip/apps/smtp/smtp.h create mode 100644 uip/apps/telnet/Makefile.telnet create mode 100644 uip/apps/telnet/telnet.c create mode 100644 uip/apps/telnet/telnet.h create mode 100644 uip/apps/telnetd/Makefile.telnetd create mode 100644 uip/apps/telnetd/shell.c create mode 100644 uip/apps/telnetd/shell.h create mode 100644 uip/apps/telnetd/telnetd.c create mode 100644 uip/apps/telnetd/telnetd.h create mode 100644 uip/apps/webclient/Makefile.webclient create mode 100755 uip/apps/webclient/makestrings create mode 100644 uip/apps/webclient/webclient-strings create mode 100644 uip/apps/webclient/webclient-strings.c create mode 100644 uip/apps/webclient/webclient-strings.h create mode 100644 uip/apps/webclient/webclient.c create mode 100644 uip/apps/webclient/webclient.h create mode 100644 uip/apps/webserver/Makefile.webserver create mode 100644 uip/apps/webserver/http-strings create mode 100644 uip/apps/webserver/http-strings.c create mode 100644 uip/apps/webserver/http-strings.h create mode 100644 uip/apps/webserver/httpd-cgi.c create mode 100644 uip/apps/webserver/httpd-cgi.h create mode 100644 uip/apps/webserver/httpd-fs.c create mode 100644 uip/apps/webserver/httpd-fs.h create mode 100644 uip/apps/webserver/httpd-fs/404.html create mode 100644 uip/apps/webserver/httpd-fs/fade.png create mode 100644 uip/apps/webserver/httpd-fs/files.shtml create mode 100644 uip/apps/webserver/httpd-fs/footer.html create mode 100644 uip/apps/webserver/httpd-fs/header.html create mode 100644 uip/apps/webserver/httpd-fs/index.html create mode 100644 uip/apps/webserver/httpd-fs/processes.shtml create mode 100644 uip/apps/webserver/httpd-fs/stats.shtml create mode 100644 uip/apps/webserver/httpd-fs/style.css create mode 100644 uip/apps/webserver/httpd-fs/tcp.shtml create mode 100644 uip/apps/webserver/httpd-fsdata.c create mode 100644 uip/apps/webserver/httpd-fsdata.h create mode 100644 uip/apps/webserver/httpd.c create mode 100644 uip/apps/webserver/httpd.h create mode 100755 uip/apps/webserver/makefsdata create mode 100755 uip/apps/webserver/makestrings create mode 100644 uip/apps/webserver/webserver.h create mode 100644 uip/lib/memb.c create mode 100644 uip/lib/memb.h create mode 100644 uip/uip-1.0-changelog.txt create mode 100644 uip/uip/Makefile.include create mode 100644 uip/uip/clock.h create mode 100644 uip/uip/lc-addrlabels.h create mode 100644 uip/uip/lc-switch.h create mode 100644 uip/uip/lc.h create mode 100644 uip/uip/psock.c create mode 100644 uip/uip/psock.h create mode 100644 uip/uip/pt.h create mode 100644 uip/uip/timer.c create mode 100644 uip/uip/timer.h create mode 100644 uip/uip/uip-fw.c create mode 100644 uip/uip/uip-fw.h create mode 100644 uip/uip/uip-neighbor.c create mode 100644 uip/uip/uip-neighbor.h create mode 100644 uip/uip/uip-split.c create mode 100644 uip/uip/uip-split.h create mode 100644 uip/uip/uip.c create mode 100644 uip/uip/uip.h create mode 100644 uip/uip/uip_arch.h create mode 100644 uip/uip/uip_arp.c create mode 100644 uip/uip/uip_arp.h create mode 100644 uip/uip/uiplib.c create mode 100644 uip/uip/uiplib.h create mode 100644 uip/uip/uipopt.h create mode 100644 uip/unix/Makefile create mode 100644 uip/unix/clock-arch.c create mode 100644 uip/unix/clock-arch.h create mode 100644 uip/unix/main.c create mode 100644 uip/unix/tapdev.c create mode 100644 uip/unix/tapdev.h create mode 100644 uip/unix/uip-conf.h diff --git a/README b/README new file mode 100644 index 0000000..25ef2cb --- /dev/null +++ b/README @@ -0,0 +1,191 @@ +FujiChat - an Atari 8-bit IRC client. + +Features: + +- Join and chat in an IRC channel (only one at a time, for now). +- Send and receive private messages to/from other users. +- Runs a TCP/IP stack on the Atari, including TCP, DNS, and SLIP. +- Works with all Atari 8-bit computers (400/800/XL/XE) provided they + have at least 48K of RAM and a supported RS232 port. +- Works with SIO2PC, Atari 850, or ICD P:R: Connection RS232 ports. +- Supports up to 9600 baud serial connection (depending on hardware used). +- Fully open source (BSD licensed). +- Ready-to-boot ATR image also supplied (fujichat.atr). + +Contents: + +README - you're reading it now. +doc/ - documentation, including (possibly obsolete) design notes. +src/ - FujiChat source, excluding uIP library. +uip/ - Modified/hacked-up version of Adam Dunkels' uIP, used as a library. + +To compile FujiChat: + +- First, install cc65. Needs to be a snapshot or release later than the + 2.11.0 release, but older than about December, 2015. Version 2.13.3 is + what the author currently uses. The code uses the old cc65 rs232.h API, + which was replaced with a new serial.h API sometime in 2015. This will + be rectified eventually. + +- Next, install axe. This can be found at http://urchlay.naptime.net/repos/axe/ + or use the clone URL git://urchlay.naptime.net/axe.git + +Make sure cc65 and axe are both found in your $PATH, then: + +$ cd src +$ make +$ make disk + +This will build an ATR image called fujichat.atr. This is a bootable image +with DOS 2.0S and everything you need to run FujiChat. See doc/README +for more detail. + +Running FujiChat: + +fujichat.atr is a bootable DOS 2.0S floppy disk. It must be booted with +BASIC disabled (remove cartridge on 400/800/1200XL, hold Option down +on XL/XE). + +The first time FujiChat boots, it'll ask what serial port driver you +want to use. Once you've selected this, you'll be prompted to reboot. +It's not recommended to choose 1 (no driver/manual setup); this option +exists mainly for testing. + +After the serial driver has been selected, FujiChat will boot into +its main menu. The first thing you'll want to do is choose S for Setup. +You'll be prompted for all the settings. The main ones are: + +- Baud rate. 4800 is the "safe" choice here, and works on most hardware. + 9600 baud may or may not work for you. 19200 baud probably won't work + for anyone (yet?) + +- Local IP address and Peer IP address. You shouldn't have to change + these (just press Enter for the defaults), *unless* your LAN is + already using the 192.168.0/24 net block! If this is the case, try + 10.0.0.1 and 10.0.0.2 for these. + +- DNS server. Most people will enter their ISP-assigned DNS server here. + In a pinch, you might try 8.8.8.8 (Google's public DNS server). + If you run DNS service on your local Linux/whatever system, you can + use the same IP as you entered for Peer IP address here. + +- IRC server. You can choose one of the listed servers, or enter any + hostname or IP address instead. + +- Server port. Normally 6667. Some servers may support other port numbers, + but there doesn't seem to be any real advantage to using them. Do NOT + enter the port number for secure IRC here; FujiChat does NOT support + SSL/TLS encryption (and never will: the Atari would take a week to + do the math needed to initiate a secure connection). + +- Your nickname. The name you want to be known by, on IRC. This should + be a short name, and different IRC networks allow different lengths. All + networks allow at least 9 characters here, and FujiChat is limited to + 20. If you're new to IRC, you should know that spaces are not allowed + here, and only some punctuation is allowed. Best bet is to stick with + alphanumerics. Mixed case is allowed (you could be johnsmith, Johnsmith, + or JohnSmith). Try to choose a name unlikely to already be in use. + +- Your 'real' name. This is visible to all users on IRC, so you probably + don't want to put your *real* name. The default is "FujiChat User", which + is fine. Unlike the nickname, this doesn't have to be unique. + +- Autojoin channel. If you enter 0 here, FujiChat won't automatically join + any channel (you would use the /join command after connecting, instead). + Normally channel names are prefixed with a # (e.g. #atari), but on + Freenode, some channels have two # instead (e.g. ##atari). If the + channel you want to join requires a NickServ login or similar, don't + try to autojoin it. You'll have to connect, then manually authenticate + (e.g. /m NickServ id ), then manually join + the channel. + +- Background and foreground colors. Standard decimal Atari color register + values (hue * 16 + luminance). The defaults are 192 and 12, which gives + a dark green background with very bright green text. + +- Disable bell. FujiChat is capable of using either the regular Atari + "buzzer" audio bell, or a visible "bell" that briefly flashes the + border color. Saying Y here disables both visual and audio bells. + +- Visual bell. When you say Y here, you'll get the visual bell described + above, and no audio bell. If you say N, you'll get the audio bell. + +- Bell on msg. If you like to be notified when you get a private message, + say Y here. If you find this annoying or distracting, say N. + +- Show ping/pong. Default is N, and most people will want to leave it this + way. Every few minutes, the IRC server sends a "ping" to FujiChat (or + any other IRC client), and FujiChat responds with a "pong" to let the + server know it's still "alive". If the pong never arrives, the server + assumes the client is dead, and drops the connection. Showing the + ping/pong messages is probably only useful for development/testing; in + normal use they just waste screen space. + +- Hide MOTD. Every time you connect to an IRC server, it sends you a + "message of the day", which contains lots of general info about the + IRC network. Unfortunately, on some networks, the MOTD is really + long and verbose, and takes several minutes to receive and display + on the Atari. There's no way to prevent the server sending the MOTD, + and the server won't respond to commands (such as joining a channel) + until it's done sending the MOTD. However, hiding the MOTD (not + printing it) will speed up connection times, because the Atari isn't + very fast at printing text and scrolling its sreen. Leave this option + enabled, unless you're very curious about what's in the MOTD (and + also very patient). + +- Is this correct [Y/n]. If you made a mistake entering one of the + settings, say N here and you'll get a chance to re-enter them. + +- Save this config [Y/n]. Normally you'll say Y here, to save the config + to D:FUJICHAT.CFG. If you're just testing a different config, you can + say N. The config will remain in memory and FujiChat will use it. If + you reload the setup/config program from within FujiChat, the settings + from memory will be used as defaults for the prompts. + +- Start FujiChat now [Y/n]. Does just what it says. If you're using the + SIO2PC for both disk emulation and RS232, wait for FujiChat to finish + loading (it'll show a "connect to server" prompt), then exit your disk + emulation software (or e.g. "stop emulation" in Respeqt), then run the + start_slip.sh script (or whatever else you use to start SLIP service + on your PC/Mac/whatever). Press Enter to connect to the IRC server, + and if you did everything just right, it should Just Work... + +Notes: + +Docs for uIP have been removed from this distribution, partly to save +space, and partly because the included version of uIP has been modified. +If you want to write a new app using uIP, you're better off starting +with the original sources, not my hacked-up mess. + +Limitations: + +As said before, FujiChat is only able to join one IRC channel at a time. + +If your channel requires authentication with e.g. Freenode's NickServ +before being allowed to join it, you'll have to configure FujiChat +*not* to auto-join the channel. Once connected, you'll have to manually +authenticate, then manually /join the channel. + +A lot of features found on IRC clients for more modern systems just +don't exist, either because of limited memory on the Atari, or because +the author just hasn't gotten around to adding them yet. There's no nick +list, logging, multiple windows, scrollback, triggers... channel text +from channel operators doesn't show an @ next to their nick... nick +completion (tab completion) doesn't exist, although you *can* use the +Tab key to respond to the most recent user who sent you a PM. + +There are known bugs in FujiChat: + +The /msg command (and several others) doesn't correctly quote its +argument, which means if you say "/msg somebody Hello, I'm on my Atari", +they'll receive only the first word (the "Hello,"). Temporary workaround: +say "/msg somebody :Hello, I'm on my Atari" (in other words prefix your +message with a colon). + +The /ping command doesn't play nice with modern FreeNode servers, meaning +you get either no ping responses, or else it prints a ping time >= 2500 +seconds. + +Not really a bug, but a missing feature: non-ASCII characters (accented +letters, British pound symbol, etc) are printed as inverse video +gibberish. At some point these will be handled more gracefully. diff --git a/doc/Compatibility.txt b/doc/Compatibility.txt new file mode 100644 index 0000000..cc47ab5 --- /dev/null +++ b/doc/Compatibility.txt @@ -0,0 +1,33 @@ +FujiChat has so far been tested with: + +Serial Interfaces: + +SIO2PC + Bob-Verter driver [*] +ATR8000 serial port [*] +Atari 850 (Atari driver) [!] +Black Box [!] +P:R: Connection + +[*] = hardware handshaking not supported or not tested; requires patched +slattach binary for higher baud rates; probably limited to 4800 baud. + +[!] = hardware handshaking tested and working (with unpatched slattach) + +DOSes: + +Atari DOS 2.0S +SpartaDOS X 4.x (use 'X' command) +MyDOS 4.5 + +Display drivers: + +XEP-80 (ABBUC driver) +CON80.SYS and CON64.SYS (Sparta X) +Omniview 80 + +FujiChat is known not to work with ClausB's old E80 driver, and probably +won't work with ACE-80 either (untested). + +Misc: + +Atari CX-85 (numeric keypad) diff --git a/doc/HOWTO b/doc/HOWTO new file mode 100644 index 0000000..53bbe5c --- /dev/null +++ b/doc/HOWTO @@ -0,0 +1,161 @@ +How to run a TCP/IP stack on an Atari 8-bit +------------------------------------------- + +You will need: + +1. An Atari 8-bit computer with at least 48K of RAM +2. A Linux box with: +3. A recent snapshot of cc65. 2.12.0 won't work. I used 2.12.9.20080831. +4. SLIP support in your Linux kernel (try "modprobe slip") +5. Some way to get an Atari program from your Linux box to your Atari, so + you can run it. I use an SIO2PC cable and AtariSIO, and "axe" for + writing files into an ATR image. +6. An RS232 serial interface for your Atari. I use the same SIO2PC cable + as (5) for this. Other possibilities are an 850, P:R: Connection, + R-Verter, etc. + + +Before building the Atari program, you should get a copy of the R: +handler (device driver) that's needed for your Atari to talk over the +serial port, and copy it to rhandler.xex in the source directory. In +general, whatever R: handler you use with Bobterm or Ice-T will work +fine. The shipped copy of rhandler.xex is the Bob-Verter driver, which +works great with an SIO2PC cable. + +Run "make" to compile and "make disk" to build the ATR image uiptest.atr. +This is a bootable disk with DOS 2.0S and the uIP demo program as +AUTORUN.SYS (with R: handler prepended to it). + +Boot the disk, wait for it to finish loading. You should see "Press Return +to connect". At this point, you should start SLIP on your serial port, +then press Return on the Atari. If you've done everything right, the Atari +should connect to the remote host! + +What you have to do to start a SLIP interface depends on what you're +using as a serial interface on the Atari, and whether it's the same +device as you'll use to load the code into the Atari. Most motherboards +these days have only one serial port (if any), so if you're doing drive +emulation, you'll have to switch between the drive emulator software +(e.g. atariserver) and SLIP mode on the same serial port (or run drive +emulation on one machine and SLIP mode on a second). If you're lucky +enough to have two serial ports on your Linux box, and own an SIO2PC +and an 850 or other Atari RS232 interface, you can run SLIP on one Linux +serial port all the time and atariserver on the other all the time. + +Note: atariserver will NOT work with USB-to-RS232 adaptors. sio2linux +theoretically might, but in practice usually doesn't. It *should* be +possible to run SLIP over a USB adaptor though (but I haven't tried it). + +Another note: For some reason, the uIP code doesn't run if it's loaded +from MyPicoDOS (the built-in loader in atariserver). This is why you +need to create an actual DOS ATR image for use with atariserver. + + +850, P:R: Connection, R-Verter, or "dumb" SIO2PC as serial device +----------------------------------------------------------------- + +To start SLIP mode on your Linux machine's serial port, you should be able +to use the "slattach" that came with your system. If you don't have this +program installed, you'll have to find out what package it belongs to +(on Slackware and Debian, that's the net-tools package, and it's highly +unlikely that it wouldn't already be installed). + +Actually, slattach won't work if your R: device doesn't have the hardware +handshaking lines connected (this is true of the SIO2PC, and for most +other devices it depends on how your cable was made). From slattach's +documentation, it looks like the -L option (local mode, no HW handshake) +should work, but it won't due to a bug in slattach. You can use the +patched version (see next section) if you don't have HW handshaking. + +The start_slip.sh script does everything that's needed to fire up a SLIP +connection for uIP to use. There are some config options at the top of +the script (to set the port, baud rate, etc), make sure these are correct. + +If you've got working hardware handshaking, you should be able to do +9600 baud. This has been tested on the 850 and works well. 19200 may +even work, if your device & driver support it. Without handshaking, +the maximum reliable speed seems to be 4800 baud (you could try 9600, +but it probably won't work). Speed isn't really *that* important for +IRC anyway. + + +Auto-sensing SIO2PC as serial device +------------------------------------ + +If using a Steve Tucker SIO2PC (the auto-sensing kind), slattach has to +be patched slightly. Get net-tools-1.60, patch it up to 1.60-19, then +apply slattach_rts.diff. Compile net-tools, copy slattach to someplace on +your PATH (don't overwrite the one in /sbin or /usr/sbin! I renamed my +patched version to a8_slattach). You can find the net-tools-1.60 source +and the 1.60.19 patch here: + +ftp://ftp.slackware.com/pub/slackware/slackware-12.1/source/n/net-tools + +(Note: you don't have to be running Slackware to use the sources, +that's just a handy place to download them from) + +Run "make" to build. It'll ask you a lot of questions about what protocols +& hardware your system supports; the answers are not too important, +so long as you say yes to SLIP support and TCP/IP. Don't do a "make +install", just copy slattach somewhere like /usr/local/bin/a8_slattach + + +Using the same serial port for drive emulation and SLIP +------------------------------------------------------- + +If using atariserver, you have to load & unload the atarisio module, +it won't play nice with SLIP. Use atariserver_slip.sh (which can be +configured a bit by changing the variables at the top). If you prefer, you +could use sio2linux instead of atariserver, but it's slow and occasionally +just fails to work on my system. If sio2linux works OK for you, it's +easier to deal with because it just uses the serial port device instead of +loading a kernel module that "takes over" the port the way atarisio does. + + +Other hardware +-------------- + +If you've got some other way to get the code to your Atari that doesn't +involve a serial port (such as a MyIDE or S-Drive, or maybe a Black Box +with removable media, or just another Linux box with its own serial port), +you can run start up SLIP on your serial port with start_slip.sh and +leave it running forever. Unlike PPP, the SLIP protocol doesn't really +"connect" to the other side of the serial line, so there's no need to +restart SLIP if you reboot the Atari. + + +Other OS +-------- + +If you aren't running Linux, you can still use SLIP. + +- Free/Net/OpenBSD: follow the Handbook for setting up a SLIP connection, + plus NAT or Masquerading (whatever the BSD terminology is). + Unknown whether it'll work without hardware handshaking. + +- Mac OS X: has slattach, which appears to be the same as the Linux version. + Unknown whether it'll work without hardware handshaking. No idea whether + OSX supports NAT/masquerade (bet it does though). + +- Windows: in theory it's possible to either use SLIrP with Cygwin, or + else the built-in "Direct Cable Connection" (which exists in at least + Windows 98 through XP, but has been dropped in Vista). You'd want to + enable "Internet Connection Sharing", too. + + It also should be possible to run SLIrP on a TCP port on either your + Windows machine or some other host, and configure APE's R: TCP/IP + emulation to connect to this host and port. In effect you'd be running + SLIP over TCP. + + Yet another way to use uIP with Windows would be to use a virtual (emulated) + machine running Linux (e.g. using qemu or possibly VirtualBox). At least + one user has successfully done this. + +- Some "serial terminal server" devices may support SLIP. I'm pretty sure + at least one model made by Lantronix does. If you have one of these, + let me know how (or if) it works. + +NOTE: If your OS has "Compressed SLIP", "CSLIP", "VJ Compression", or any +SLIP-related option named similarly, DISABLE it. uIP does not support +compressed SLIP. + diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..24d40b0 --- /dev/null +++ b/doc/README @@ -0,0 +1,396 @@ +FujiChat v0.1: An IRC client for the Atari 8-bit +------------------------------------------- + +FujiChat is a simple IRC (Internet Relay Chat) client for Atari 8-bit +(400/800/XL/XE) computers, based on the uIP TCP/IP stack. It uses a SLIP +connection to talk to the outside world, and supports a subset of the IRC +commands available in full-featured clients. 48K of memory is required +(and extended memory is not used, so it can coexist with RAMdisk drivers +and such). + +Capabilities: + +- Can connect to an IRC server, and: +- Join a channel +- Send and receive channel and private messages +- Actions (/me does whatever) are supported +- Part the channel and join a new channel +- Most IRC slash-commands are available +- Client responds to CTCP PING and VERSION requests +- Client can send CTCP PING and VERSION requests +- Client responds correctly to server PINGs (with PONG) + +Limitations: + +These are listed approximately in order of severity, and will be addressed +in future versions in approximately the order shown here. + + +- The user interface is extremely crude (almost non-existent) +- Try not to accidentally hit the Break key. It may result in weird + behaviour (though it usually doesn't) +- Editing is extremely crude: only backspace, delete line, and delete + word are supported + (future versions will probably support emacs-like key bindings) +- Currently, the client can only join one channel at a time. Attempts + to join a second channel before parting the first will fail. (future + versions may allow joining multiple channels, but probably no windowing, so + the channels' text will appear mixed together on the screen) +- Many client features like logging, scrollback, nick highlighting, DCC, + multiple windows, nick completion, etc are missing. Some of these will + be added in future versions, but some would just take too much memory + to fit in 48K. (future versions are planned to have at least tab-completion + of nicks, and possibly a small scrollback buffer. A limited number of + multiple channel/msg windows is not out of the question) +- There is no nick list displayed. At any time you can use /names #channel + or /who #channel to see who else is in the channel (or press ctrl-N + or ctrl-W), but the client doesn't attempt to track other users' + joins/parts/quits. (future versions may track the nick list and display + it as a separate screen, e.g. you press Option to see it) +- The characters {, }, `, and ~ are not printable on the Atari. Instead they + are rendered as inverse-video [, ], ', and ^, respectively (future versions + will probably use a custom font to display these characters) +- mIRC-style color and bold codes are not interpreted at all. They will + be displayed as ATASCII graphics characters (future versions will strip + color codes and may display bold as inverse video) +- Most CTCP commands are unsupported (and DCC will likely never be supported) +- Private messages from other users appear mixed in with channel text +- Text is displayed in GRAPHICS 0, meaning it's 40 columns by 24 lines, + with no support for multi-colored text or anything fancy like italics + or underlines. It might be possible to do an Ice-T style 80 column + display, but it's a pig (8K for the graphics mode, plus at least 1K + for the font, plus rendering/scrolling is slow and might result in + serial buffer overruns if I'm not careful). It might instead be possible + to do a 40-column display with 4 or 8 character colors, using P/M overlays, + which would result in some visible flicker, but the overall effect isn't + too painful. This would require a lot less RAM and CPU cycles than the + 80-column mode. + +As you can see, FujiChat is more defined by what it can't do than what it +can, at the moment :) + +Configuration: + +The default config is stored in the file FUJICHAT.CFG in a binary format +(not human readable). If the config file is missing at startup, FujiChat +will start up in its config menu. If the config file was loaded, you +will be asked "Use defaults [Y/n]?"; answering N will take you to the +config menu. + +The first step in the config menu is to choose an IRC server. FujiChat +comes with a short list of server IP addresses, which you may select +from by entering the number of the server. You may also enter any IP +address at the prompt, to use a server not in the built-in list. (As +soon as I've debugged the DNS code, you'll be able to use hostnames, but +for this release we're stuck with IP addresses only) + +The next step is to choose your IRC nickname. The different IRC networks +have different limits on the maximum length of a nick, but all networks +support at least 9 characters. FujiChat limits your nick to 20 characters. + +IRC forbids certain characters in a nickname: they may not start with +a hyphen, and must consist of letters, numbers, or the characters: +- [ ] { } ` _ \ ^ +Note that FujiChat does NO checking for invalid characters in your nick! + +The next two options are the background and foreground colors. These are +standard Atari color register values (chroma/luma) to be used for the +GRAPHICS 0 text background and foreground registers. Try not to set +them to the same thing; you won't be able to see any text if you do! + +When you're done, you'll be asked whether or not you want to save the +config. If you answer N, the options you just entered will be used for +the current session only. + +Connecting to IRC: + +To set up a SLIP connection between your Atari and another host on your +network, see the file HOWTO. + +The following instructions assume you have a properly configured SLIP +connection, including NAT/Masquerade if required. + +The default IRC server is in the US, and is known not to work well for +users in Europe. FujiChat has a short list of NewNet IRC servers built +in (accessible from the "IRC Server" config menu), or you can enter any +other IP address. To find the IP address of a server, you can use a tool +such as "nslookup" or "dig", or simply ping the host from your Linux box. + +To connect to the IRC server, choose "Connect" from the main config menu. +At this point, FujiChat will open a TCP connection to the server. Within +a few seconds, you should start seeing messages from the IRC server. + +Once the connection is made, FujiChat will attempt to register +your nickname and host. If your primary nickname is already in use, +registration will fail, and you will see a server message informing you +of this. If this happens, choose a different nickname and type "/nick +" (and press Return). + +After your nickname is registered, the server will send its "message of +the day" (the MOTD). On NewNet, the MOTD tends to be very long, and there's +no way to skip or abort it, so be patient. + +Once the MOTD has finished, the connection is ready to use. At this point, +you can use the /join command to join a channel and start chatting! + +[Note: There's no way to tell the server not to send the MOTD. I could +add an option to FujiChat to make it not *display* the MOTD, but your +serial port's bandwidth would still be starved, and you wouldn't be able +to get much chatting done] + +How to use IRC: + +[This section is written as an intro for someone who's completely new +to IRC. Apologies if it seems condescending...] + +Before you can chat with other users, you must find some users to chat to. +The normal place to do this is in an IRC "channel". Think of the IRC network +as a giant building (a castle, or maybe a convention center). Each channel +is like a room within the larger building. + +Channels have names that usually start with a # character. The rest of +the name usually describes the usual topic of conversation on the +channel. For instance, the channel #atari is about (you can guess this +but...) Atari computers and video games. + +The act of entering a channel (room) is known as "joining" the channel. +To do this, you connect to the IRC server, then type "/join" followed +by the channel name. Example: + +/join #atari + +[FujiChat only allows joining one channel at a time, in the current +version. Future versions may support multiple channels] + +Unlike a real room, the IRC channel will be created if it doesn't already +exist. You'll know this happened if the channel's names list only shows +your nickname. + +It's possible to get a complete list of channels from the IRC server, but +this is really time-consuming (there are thousands on a typical network), +and FujiChat doesn't provide a way to scroll through them. You can search +for channels by name by using wildcards with the /list command. Example: +you want to talk about cars. Try the following command: + +/list *cars* + +(Also, /list *auto*, since a car channel might be called something with +"automobile" or "automotive" in its name). + +Also, for many common topics, you can just try using the topic name as +the channel name (/join #music, /join #beer, /join #unix). Chances are +it exists, and no harm is done if it doesn't. + +Once you've joined a channel, you'll be presented with a list of all +the users in the channel, and anything you type (other than commands +beginning with a slash (/)) will be sent to everyone in the channel. + +Text from other users will appear like this: + + Hi there! + +Text you type will appear in inverse video. It will only be sent to the +server when you press Return. You can use the backspace key to correct +typos, or press shift-backspace to delete the entire message without +sending it. (Future FujiChat versions will support the other Atari +editing keys) + +IRC also supports private messages, which are sent to only one user. +To send someone a private message, use the /msg (or /m) command: + +/msg Bob Hello + +When you receive a private message, it looks like this: + +MSG: Howdy + +To reply, you would type "/msg Bob whatever you want to say". + +When you receive a private message, you can press the Tab key at the +start of a new message to insert "/msg ", where is the user +who last sent you a private message. This is handy for carrying on long +private conversations, though you should be careful: Tab always sends +to the last person who messaged you. If you unexpectedly get a message +from a third party during a private conversation, you might accidentally +send to the wrong person! Future versions of FujiChat will track more +than one conversation, using Tab to cycle through all recent message +recipients. + +IRC also supports the concept of channel operators (known as "ops"). These +are people who "own" the channel, and have the power to kick other users +out, ban them from the channel, set the channel topic, and a few other +things. Channel operators' nicknames will be display in the nick list +with an @ in front of them. Most channel operators are friendly folk +who will help you out and answer "newbie" IRC questions, unless you're +rude or repeatedly break the channel rules. + +Higher up on the food chain are IRC server operators (known as "opers"). +These godlike entities shouldn't be bothered with everyday mortal +concerns, but sometimes you have a real problem and they're the only ones +who can help. Most IRC networks have a channel where the opers hang out +(usually listed in the MOTD text). + +IRC commands: + +[This is far from a complete list. Actually, different IRC servers/networks +may have their own custom commands, so it would be very difficult to +give a 100% complete list] + +IRC commands begin with a slash (/) character, and may take zero or more +parameters. In the list the following conventions are used: + + represents a channel name, including the leading # character. +IRC channel names generally always start with a #, but some servers may +support special types of channels that begin with a different character. + + represents a user's nickname. + + represents chat message text (whatever you want to say). This +is free-form and generally should only include printable characters. IRC +limits the length of a message to 510 characters. FujiChat further limits +outgoing messages to 256 bytes, and will ring the Atari's "bell" if you +try to type a message longer than this. + +If any of the above are shown in [] (square brackets), suck as [], +this means the parameter is optional. + +/join + +Join a channel. You may only chat in one channel at a time in the current +version of FujiChat. If you attempt to join a channel that does not already +exist, most IRC servers will create the channel for you. The /join +command may be abbreviated "/j". + +/part + +Leave the current channel. You must do this before joining a different +channel. If you want to leave IRC (disconnect from the server), you +don't have the /part the channel (simply use the /quit command) + +/nick + +Change your nickname. The server will respond with an error message if +you try to use an invalid nick, or one that's already in use. If the +command succeeds, there will be no response. + +/me + +Send an "action". Other users will see your nick prefixed to the message, +so that it looks like a sentence. + +Example: If your nick is Bob, and you type "/me is using FujiChat", +it will appear to other users as something like: + +* Bob is using FujiChat + +/msg + +Send a private message to another user. The /msg command may be abbreviated +as "/m" or spelled the long way as "/privmsg". + +/quit + +Quit IRC. The server will disconnect you, and FujiChat will give you +the option to reconnect or return to the main menu. The +is optional. All users in the current channel will see the , +which could be something like "Nice talking to everyone", or give the +reason why you're leaving IRC ("Wife needs to play M.U.L.E."). If you +don't supply , the server will just use your nick in place of it. + +/ping + +Send a CTCP PING request to a user. When the user's client receives the +request, it will respond with a "pong". This is useful for determining +whether the user is still connected to the IRC network. Also, if the +response takes a long time to show up, you'll know there's a lot of +network lag between you and the other user. (Future versions of FujiChat +may calculate & display the lag time for you) + +/version + +Send a CTCP VERSION request to a user. The user's client will usually +respond with the name of the client software and its version, although +most clients can be set up to say anything the user wants, or nothing +at all. FujiChat responds to other users' version requests with +"FujiChat 0.1 (Atari 8-bit)". + +/ignore + +Ignore (don't print) any and all messages from . If no +is given, /ignore shows the list of nicks that are being ignored. +Up to 10 nicks can be ignored in the current version of FujiChat. +When you ignore someone, they don't have any way to know that you're +ignoring them (they don't get a message telling them). + +/unignore + +Stop ignoring a user. To clear the entire list (stop ignoring all ignored +users at once), use "/unignore -a". + +/quote + +Send a string directly to the server, verbatim, instead of to the current +channel you've joined. If you don't know what this command is good for, +don't worry about it: it's mostly used by the author as a debugging tool. + +Keyboard Macros: + +These are only active at the beginning of a line (in other words, you +can't send them when you're in the middle of typing a message). The +macros are: + +Control-N: performs a "/names #channel" for the currently joined channel. +Control-W: performs a "/who #channel" for the currently joined channel. +Tab: inserts the text "/msg nick" at the beginning of the line, where + the nick is that of the last user who sent you a private message. + +There may be a user-definable keyboard macro facility in a future version +of FujiChat (or maybe not, if it'd make the client too bloated). + +Other IRC commands: + +Most other commands are supported in a dumb kind of way. Anything you +type that starts with a slash, and isn't one of the recognized commands +listed above, will be sent to the server with the slash removed and +the command name converted to uppercase. This works pretty well for +commands like /away, /kick, /mode, /topic, etc: + +Kick a user from a channel (if you're a channel operator): +/kick [] + +Ban a user from a channel (again, you must be a chanop): +/mode +b + +Get a list of who's in a channel: +/names + +Get a fancier list: +/who + +NewNet-specific command: log in to NickServ +/ns id + +See RFC1459 for a complete protocol specification. Any of the commands +shown there can be sent by prefixing them with a / character. + +RFC1459 on the web: +http://www.rfc-editor.org/cgi-bin/rfcdoctype.pl?loc=RFC&letsgo=1459&type=http&file_format=txt + +Credits: + +FujiChat is written by B. Watson (aka Urchlay on NewNet). + +FujiChat includes software (the uIP TCP/IP) stack by Adam Dunkels. Without +Mr. Dunkels' excellent and well-documented software, FujiChat probably +would never have been more than a pipe dream. + +FujiChat also includes the Bob-Verter driver by Bob Puff. + +Special thanks to SteveS and Beetle for being my guinea pigs (erm, I mean, +beta testers) + +You're invited to come hang out in #atari on NewNet any time. You can +usually find me there, although I may be asleep at the keyboard. If you +have trouble getting FujiChat to work, or have a bug report or feature +request, or if you just use FujiChat, I'd like to hear from you. + diff --git a/doc/about.txt b/doc/about.txt new file mode 100644 index 0000000..28f5a73 --- /dev/null +++ b/doc/about.txt @@ -0,0 +1,35 @@ +# Try to keep the lines <= 39 chars, +# but the reader can handler up to 199 char/line. +# Comment lines (like this one) are ignored. +FujiChat: an Atari 8-bit IRC client +(c) 2008 B. Watson (aka Urchlay) + +Version 0.4, 20081019 + +This program includes the uIP TCP/IP +stack, (c) Adam Dunkels. + +Bob-Verter driver (c) 1989, Bob Puff + +[insert legalese krap here] +[more legalese] +[it's going to take up a few lines] +[...] +[...] +[I hate legalese] + +[Long line that should be handled correctly by the line-counting logic. It's 3 screen lines.] + +Special thanks to the FujiChat alpha +testers: + +- Beetle +- charliec +- SteveS + +...and the rest of the NewNet #atari +crowd. + +Stop by #atari sometime and say hi, +everyone's welcome! + diff --git a/doc/newdesign.txt b/doc/newdesign.txt new file mode 100644 index 0000000..8e45fab --- /dev/null +++ b/doc/newdesign.txt @@ -0,0 +1,81 @@ +/* TODO: move the non-IRC-related config to a separate SETUP program, + and a separate UIP.CFG file. This will be shared by all apps that + use uIP, such as the planned telnet and FTP clients. Also it means + we don't have to bloat each program with a complete config UI + for things like the local/peer/DNS IP addresses. + + In fact the SETUP utility might resolve IP addresses for us, so + each app might not need its own copy of the resolver... though + that's maybe a bit clumsy to use for FTP, since you generally want + to easily be able to connect to arbitrary servers (unlike, say, IRC + where you usually use the same server all the time). Perhaps SETUP + could resolve arbitrary hostnames, then write them to a /etc/hosts + type of file. Parsing /etc/hosts entries is fairly lightweight, + could be done in all the client programs... + + ...or maybe what should happen is that there should be a RESOLV + program that can resolve hostnames, and read/write them in text + form to a HOSTS.TXT file... and also parses the HOSTS file and + stores the hostname strings and 4-byte IP addresses in a fixed + area of memory. The app programs could just look up hostnames in + this memory area, without having to open & parse HOSTS themselves. + cc65 programs by default start at $2E00. The Bob-verter driver ends + around $2200 (other R: drivers should be comparable), which gives + us around 3K of unallocated memory. Assuming the average hostname/IP + pair is 50 bytes, that'd give us about 60 of them. The RESOLV program + would stop the user from adding more hostnames when there's no space + for them (and let them delete some to make room, maybe commenting them + out so they remain in the HOSTS file for future uncommenting). + + Ultimately there should be a master AUTORUN.SYS file with a menu + that runs the other sub-apps (or lets you exit to DUP). Menu would + have options like "DNS", "IRC", "FTP", "Telnet", and "Network + Setup". Of course I need to write a program loader, there's no + exec* functions in cc65! The Network Setup option would let you + specify the R: driver you want to load, so it wouldn't have to + be prepended to any of the executables, and would be auto-loaded + the first time you try to run any of the apps that need it. It'd + be nice if the main menu program had at least a few DOS functions + as well (delete/copy/rename/lock/unlock, format too?) + + Probably, FujiChat's 1.0 release will be as a standalone IRC client, + with the current config UI stuff as-is. The other stuff would be + released months from now, under the label "FujiNet" or something, and + include a new version of FujiChat as one of several apps. + + The final distibution disk will need at least some documentation in + Atari-readable text format, plus a doc-reader program. + + All the subprograms need to end with RTS to the menu program, which + shold be small and stay resident in addresses not touched by cc65 + (I've got 128 bytes each in the cassette buffer and page 5, also + 256 more in page 6. Should be easy to squeeze into 512 bytes, no?) + + So a disk directory would contain: + + DOS.SYS, DUP.SYS + AUTORUN.SYS - the main menu and subprogram loader + BOBVERT.XEX - the Bob-verter R: driver + A850.XEX - the 850 R: driver (from DOS 2.0S I guess) + MIO.XEX, BLACKBOX.XEX, etc, drivers for other serial ports + HOSTS.TXT - the /etc/hosts file, human-readable and -editable + README.TXT - docs + MORE.XEX - doc reader (should handle ASCII or ATASCII EOLs) + SETUP.XEX - set up global network settings (local/remote/dns IPs, also + things like screen colors, key-repeat rate, etc). + DNS.XEX - lookup hostnames, maintain and parse HOSTS.TXT + FTP.XEX, TELNET.XEX, IRC.XEX, PING.XEX - the apps + FTP.CFG, TELNET.CFG, IRC.CFG, etc - app-specific settings + FUJINET.CFG - global settings + ...if there's room on the disk, a small text editor might be nice + to include. + + The whole thing should be distributed as a bootable, single-density + DOS disk (undecided which DOS, either 2.0S or MyDOS 4.5). + + Alternatively, all the XEX files might be named COM, and the whole + thing could run under a CLI DOS like Sparta (if it'll actually + run). The apps could take optional CLI arguments, also... and the + AUTORUN.SYS would actually be unnecessary! + + */ diff --git a/doc/notes.txt b/doc/notes.txt new file mode 100644 index 0000000..3f25388 --- /dev/null +++ b/doc/notes.txt @@ -0,0 +1,281 @@ +Definitely need to rewrite huge swathes of code in asm. +Candidates are: + +fujichat.c: main(), handle_keystroke(), and the protocol parsing +routines + +rs232dev.c: the whole thing could be rewritten in asm for speed, +but the size isn't so bad. + +uIP itself: have to investigate. Some of the code is pretty +hairy. Before rewriting in asm, should make it so we can +compile without TCP listen support, since we don't use it. + + +Need to re-do the R: handler stuff. At least one driver (the +plain Atari 850 one) actually crashes when loaded from either +the DOS menu or aexec. Apparently it *only* works if it's +loaded as autorun.sys. So, something like this: + +- Initial autorun.sys on disk loads a program called makeauto. +[done] + +- makeauto asks for the serial driver, then concatenates the +driver + menu.com into a new autorun.sys (renaming the old +one to autorun.old or something), then asks user to reboot. +[done] + +- Any time fujiconf loads and can't find an R: handler, it tells the +user and runs makeauto for him (or anyway asks, with default Yes). The +"set R: driver" stuff in fujiconf needs to move to makeauto (and be +changed so it appends files instead copy). + +- FujiChat itself still won't contain any R: detection or +anything, beyond the RS232 Not Initialized error message +[done] + +- While I'm at it, fix the filename paths so they *all* begin with +the D: prefix. +[done] + +- Possibly menu.com has a new menu item, "RS232 Setup", and warns +the user "You must run RS232 Setup before using FujiChat" + +20081124 bkw: Add /peek, /poke, /fgcolor, /bgcolor commands. + +Also, now that we're parsing numerics from the server, it'd be +nice to do the alternate-nick thing, for when the nick is in use. + +20081124 bkw: Keep a time-of-day clock (don't use RTCLOK to store +it though). At connect, send /TIME to the server, parse the results. +The config file will need a timezone setting. + +20081121 bkw: Feature idea: auto-away when attract mode kicks in, +with default away message (but don't announce to channel). Un-away +as soon as a key is hit. Possibly let the user set a timeout +instead of letting the OS default to 9 minutes. +[done, using default OS timeout only] + +Ideas for logging: + +Will anyone give a shit about logging to disk? If so, it wouldn't +be impossible... but we'd likely drop packets (or does uip_stop() +gracefully handle this, maybe with a callback?) + +/log [on|off|flush|file filename|search ] + +Keep the disk file open? Log stuff to memory, then just before +the buffer fills, write it out to disk. + +Logging to memory, looks like we have a little over 5K for this. +When we get ready to log a message that would put us past the end +of the buffer, memmove() the buffer down by some amount (say 1/4 +of its size). + +Log viewing is a mode. While enabled, handle_keystroke() will do +the --more-- thing. Traffic indicator's still active, and we +still log stuff to memory, but *don't* print it. If the log +has to be shifted down, also shift down the currently-viewing +pointer. If the view pointer points too low to move, set it +to the bottom of the log buffer if it isn't already (user will +get confused, but what you gonna do?). Forward/backward searches +should work. Filtering by nick should work. + +When entering logviewer mode, save the current end-of-log address. +Any time the log moves while viewing, also subtract from this +address. More stuff can be coming in & being logged above this +address... on exiting logviewer mode, anything aboved the saved +address should be printed to the screen immediately. + +In this model of "scrollback" support, we actually don't scroll +per se, we're *still* using stdio to print stuff. It might be +that on entering logviewer mode, we should run through the log, +counting characters, so we'll know where each screens' worth +starts (for going back/up in the viewer). Either that, or we +could print the damn thing backwards? + +At a price of 3 bytes per message, we can store timestamps. Not +sure if it's worth it. Actually maybe we can just store a single +byte in the buffer every N minutes, to give a rough guide to +how long ago the next bunch of messages were. + +How bout this for a lightly compressed format: we're only storing +7-bit printable ascii, in 8-bit bytes, so... + +1st byte: + +0-31 - No message, just timestamp. Next message starts at +next byte in buffer. The value is the minutes-1 since the +last timestamp. Basically, every minute of wall-clock time, +a timestamp of 0 is added to the buffer if someone has said +something in the past minute. If not, there will already +be a timestamp at the end of buffer, so just increment it +(unless it's at the max value, in which case add a zero +timestamp after it). We can use these to e.g. print +"(42 minutes silence)" or such. I'd like to be able to +do "N minutes ago" type messages, but to do that I have to +run through the buffer backwards to calculate what they +should be (then forwards to actually read messages from it). + +Anything else: 1st char of nick, or 0x80 meaning "same nick as last +message" (or 0x81 meaning "my nick"?). Some care has to be taken when +memmoving the buffer: blocks of messages from the same user need to be +treated as a unit (kept entirely, or disposed of entirely). For this +to make sense, such blocks have to be kept short (say, less than the +move-amount). + +Next bytes are the rest of the nick, with bit 7 set for the last +one. In case of a 1-char nick, 1st and only char has bit 7 set. + +After last nick char comes the message. +For the first byte, if the top bit is set, the bottom 7 bits are: + +0 - empty message +1-31 - stuff like join/quit/part (don't bother to store part, +quit, or kick messages? or store normally?) +Anything else - normal message character (the only one, if the +top bit is set). + +Further message bytes are stored with the top bit of the last byte +being set. + +So if someone joins, says hello, and parts ( means 'c' with high +bit set: + +Use\x01\x80Hello\x80\x02 + +(Assuming \x01 is the join code and \x02 is the part code) + +This is 13 bytes. If we stored what a normal client stores in its +log, it might look like: + +User has joined\n + Hello\n +User has left\n + +Which is 16+13+14 = 43 bytes. Most clients would actually store the +channel name with the joins/parts; I left them out to make the +comparison more fair (we don't penalize them for storing info that +we don't store, only for storing the same info less densely). + + +20081120 bkw: smallest 0.4 binary, with all FEAT_* turned off except +for FEAT_LOW_RAM_BUFFERS, the BSS ends at $920E. With COL80E relocated +to $9A00, that gives us 1K for stack. Not great, but might work. It's +still too big to use with E80 (by about 3K, counting the stack). + +COL80E loads at $7A00-$7F80, but doesn't really seem to use any RAM +from $8000-A000 with BASIC disabled. If the code could be relocated so +it loads at $9A00, we'd have a fighting chance of squeezing fujichat to +fit. Currently fujichat loads $2E00-8D3B... meaning there'd be a little +over 3K for stack & data/bss variables. Need to examine cc65's map file, +see how high the data/bss stuff goes. Moving the input and output buffers +to low RAM is going to help a lot. It also might be possible to move +the stack to low RAM (it's supposed to sit right above the heap, but +fujichat isn't using malloc(), which unless I'm mistaken means no heap +usage... though some of the libraries it links with might be using it). + +Try compiling uip without UDP checksums, with fewer TCP/UDP conns, +asm optimize anything that doesn't compile efficiently? + +It looks like TCP listen support could be made a compile-time option +that could be disabled. IRC doesn't need to listen on ports except +for DCCs, and we probably can't ever make those work anyway. It +won't save much (guesstimate is 50-75 bytes)... + +Each TCP conn is supposed to take 30 bytes. For now we only need one, +but we have 5, so wasting 120 bytes there. + +[so far, changing max. tcp conns, listen ports, and udp conns to 1, +and disabling udp cksums, has saved 325 bytes. Worth it, but need to +make sure the app still works!] + +[also, make some of FujiChat's features able to be removed at +compile-time. Removing them all saves 963 bytes, and makes the BSS +end at $96cb! If COL80E were relocated to $9A00, we'd have 800-odd +bytes for the heap/stack, which still ain't enough... Possibly +the stack could be shrunk by 256 bytes and relocated to $2700?] + +E80 is probably a lost cause. It seems to take 12K, which seems like an +awful lot. Screen is hard-wired to $6E70, but it seems to not use any +RAM from $A000-BFFF with BASIC disabled. moving the whole thing up 8K +(assuming I can relocate the code) gives us a start address of $8E70, +or 3K lower than COL80E, or 130-odd bytes(!) above the end of cc65's +code segment (ouch!)... however maybe I could leave it unrelocated, and +use a linker script to move all the data/bss/heap/stack/etc (everything +but the code, and maybe some of the code too) to the $A000-BFFF area +(8K seems like a good bit, the stack is 2K). + +Fast E40 driver doesn't have to be a full E: replacement! Instead, we only +need to hook the "put 1 byte" routine, and do the following: + +Check & see if byte-to-print is printable or an EOL. If it's neither, +jump to the OS's print-one-byte routine. + +If the screen is about to scroll (if we're on bottom line and byte is +0x9b, or if we're on bottom line + last column and byte is printable), +we capture the top line (first 40 bytes) of screen RAM and store in +scrollback buffer. We can probably detect when the line ends in >1 +spaces, and not store those. + +If a screen scroll is needed, do it ourselves, *fast*. This may turn +out to be too messy or bloated to deal with, but I think it might not +be so bad. + +If the char is printable, print it, *fast*. Fast E40 doesn't have to +support margins other than 0 and 39, which should help. Also we can +make assumptions about where the screen RAM is if need be, and use +multiple ZP pointers into it (using the FP zero page area). + +However much scrollback RAM we have, we have to subtract 1K from it for +a viewing buffer. This allows us to keep printing to the main screen +RAM while it's not showing, and buffering it as it scrolls, without the +viewing buffer changing while we look at it... also when done viewing, +we toggle back to displaying main screen RAM instantly. + +I'm thinking there have to be separate builds for Fast E40 and whatever +80-col driver I get working. The 80 version won't have any support for +scrollback at all, not least because there's no RAM for the buffer! + +Also if there's ever going to be a separate edit buffer "window", +or multiple channel windows, fast E40 is where they'll live. + +It might also be possible to do word-wrap. Not sure whether that's better +done in the driver or in the app. Doing it in the app means it'll work +in 80-column mode, too. + +...potential new feature: should be able to do ping times by sending the +low 2 RTCLOK bytes in numeric form, then when the response comes back, +decode back into 2 bytes, subtract from current RTCLOK, convert to +10ths of a second, and print. + +I *really* wish I could do CSLIP. Maybe later. Not delved too deeply +into the guts of uIP... maybe the serial driver could transparently +do the comp/decomp, and speak plain SLIP to uIP? (would this be +too slow, cause drops? Even if it doesn't make us drop packets, would +the CPU overhead negate any benefit to be gained from it?) + +Also on the drawing board, keyboard buffering during rs232 I/O. Fairly +straightforward, I think. Don't actually cgetc() or anything, just +save the contents of CH in a buffer if it's not $FF, and set it +to $FF to clear the keystroke. In fact, there's a prototype of it +in keybuftest.c (just needs to be integrated). + +Another idea: a status line wouldn't be so hard to do, even without a +fancy E: driver. Could write directly into the first 40 bytes of screen +RAM. I don't want to give up a line of display though... but instead of +a full status line, it'd be cool to display a little up or down arrow +in the upper-right corner during rs232 sends/receives (save & restore +the character that really goes there). The screen codes for the up +and down arrows are $5C and $5D ($DC and $DD for inverse). + +/j or /join without a channel should rejoin the current channel, if +FujiChat thinks it's in a channel. This would give us an easy way +to rejoin the channel if kicked. + +There needs to be an extra-dumb terminal program for use with manual +login systems. It should fit in 1K or so, load on top of fujichat's +input/output/msg buffer space, and RTS back to fujichat when it's +done. Later on there should be a chatscript engine that loads in +the same space and works the same way. + diff --git a/src/ChangeLog b/src/ChangeLog new file mode 100644 index 0000000..6b95059 --- /dev/null +++ b/src/ChangeLog @@ -0,0 +1,349 @@ +- 20190313 bkw: + +FujiChat is back! + +The source is now developed using git, meaning you'll find low-level +details about changes in the git log. I'll try to remember to update +this ChangeLog to document major new features and such. + +- 20081201 bkw: + +Rewrote & reorganized handle_command(). It now lives in commands.c, +and loops over a table of commands (cmd_list), rather than the old +messy chain of if/else/if. Moved all the logic for each command into +their own cmd_whatever() functions (the addresses of which are in the +table). Not only did this save a couple hundred bytes of object code, +it also means adding new commands is less expensive. + +Instead of telnet_send(tstate, serv_msg_buf, strlen(serv_msg_buf)) strewn +about the code, there's now a send_serv_msg_buf(void) function. Rather +than use strlen() to calculate, we set the new serv_msg_buf_len variable +to the length... which works out great as almost all the telnet_send() +instances were preceded by a sprintf(), which already returns the length +(was just throwing away the return value! Old habits...) + +Added /fgcolor and /bgcolor commands (enable with FEAT_COLOR_COMMAND). +These don't change the colors in the config, and they get reset before +every new IRC connection, but it does mean you don't have to reload the +config menu to try out new colors. Especially important for COL80 users, +since it takes some fiddling to find a color set that looks good on your +monitor (if you can!) + +Completely removed all attempts to do a software cursor when +FEAT_COL80_HACK is enabled. It wasn't working anyway, and needs further +thought before hacking away at it any more (should the COL80 driver +respond to CRSINH at 752, like the real E: does?)... Actually it's +perfectly usable without the cursor anyway, you always know where you +are because you're always at the bottom of the screen. When/if arrow +key editing is supported, there will have to be a cursor... + + +- 20081130 bkw: + +More major surgery: there's now a hacked-up, cut-down version of the +old COL80 driver, and Fujichat support for it. FEAT_COL80_HACK, which +defines its own set of features. Currently the code is a mess of #ifdefs, +but working (still some issues with the cursor not working right in 80 +cols). The 4x8 font is a slightly modified version of Itay Chamiel's +Ice-T font (characters 32-127 only, I made the ampersand and the capital +N look more like I expect them to). Current version of col80 uses the +cassette buffer for a private input buffer for CIO get calls, but +it could just as well use input_buf (though it can't know where that +is, unless FEAT_LOW_RAM_BUFFERS is also enabled). So far, COL80 hack +only tested with Bob-verter. Scroll speed is slower than Ice-T or +E80/ACE80, but TCP has those pauses built into it... someone needs +to try it at 9600 baud. An interesting thing about COL80 is that +it's not limited to 128-char fonts (neither is Ice-T, Itay does a +full 256-char set)... unicode anyone? SW underlining? + +Got rid of redraw_buf (was at $2800), calling fuji_putchar() in a loop +is about as fast as fputs() a whole string. Allows user an extra page +in low memory, unless I find a burning need to use it for something +else... + +- 20081127 bkw: + +Expunged putchar() and cgetc(), from fujichat.c, gained over 200 bytes +(replaced with "indirect JSR" technique using put/get address-minus-one +in OS ROM). BSS now ends at $9515. We almost have enough room for an +80-column software driver (the stack is 2K, so MEMTOP needs to be $9d15 +or higher since we don't use the heap). Default GR.0 setup, MEMTOP +is $bc1f, which is where the stack starts (and grows downward for 2K, +ending at $b41f). $B41F minus $9515 is 7946 bytes, almost 8K. In GR.8 +mode, MEMTOP is $A04F. Subtract $9515 (end of BSS), add 2K ($9D15, +end of stack). Subtract from $A04F and we get $33a, or 826 bytes. This +is not enough room for a GR.8 software 80-column driver's code + font +(COL80E uses more like twice that), but it's a whole lot closer than +FujiChat 0.4 was. + +Strip leading colons from the text of server messages. + +BSS at $977E (got rid of cursor() and replaced cgetc() with version +that doesn't contain setcursor junk (we don't want to ever disable +the cursor). In fact conio.h is gone now. + +Expunged fread() from common.c (replaced with read()), gained over +1/2K. + +Made TCP listen support optional in uIP, and turned it off for +FujiChat. This save about 1200 bytes in the binary. + +Starting to rewrite bits in asm. I've got the end of the BSS +down to $97ED now, and I've barely started... + +Fixed bug in config_is_valid() that made fujichat always use +built-in defaults. Thanks to Beetle for spotting this. + +- 20081126 bkw: + +Renamed menu.com to fujimenu.com (apparently on SpartaDOS X, +trying to load D:MENU.COM ends up loading CAR:MENU.COM instead). +Thanks to Beetle for spotting this. + +makeauto.com now cats the serial driver and loadmenu.com (instead +of menu.com) to make autorun.sys. Saves like 70 sectors on the +disk image. + +Added some test code (FEAT_UNICODE_TEST) that converts an input ctrl-P +(clubs symbol) into the UTF-8 sequence for a Unicode "card suit clubs" +symbol. It looked fine in irssi with univga font, but for some reason 3 +other people saw it as a spades symbol... Eventually it'd be possible to +have a little table to convert all the ATASCII graphics chars into UTF-8 +on keyboard input, and convert the UTF-8 versions back into the ATASCII +chars on screen output. Thanks to Redb3ard for coming up with the idea +and doing the research on this... though it can't be fully implemented +any time soon (FujiChat needs to go on a major diet before I add any +more features, I'm running out of RAM). + + +- 20081125 bkw: + +Added keyboard buffer. Needs lots of testing, but initially appears +to work OK (FEAT_KEYBOARD_BUFFER) + +Added autojoin to fujichat. + +Rearranging things. The Atari 850 driver *crashes* if it's loaded +from the DOS menu even (it *has* to be autorun.sys), so instead +of the default.ser and such, the RS232 driver + menu now get +catted together to create an autorun.sys (and the user is asked +to reboot, to load it). + +Added auto-away on attract mode + +Added alt_nick and timezone fields to cfg file (not used yet), +bumped CONF_VERSION. + +Rearrange fujichat numeric server message stuff, add autojoin capability. +Also add autojoin prompt to fujiconf. + +Change the leading character for local message from * to > (e.g. +"> Registering Nick"), and privmsgs to us now show up as +"-> message" + +- 20081120 bkw: + +Fixed bug in conf menu (IRC server was getting reset to the first in the +list if the user hit Return, instead of keeping his existing one). Thanks +to Slor for spotting this. + +Added (attempted) 19200 baud support. cc65 doesn't define RS_BAUD_19200 in +rs232.h. Slor suggested defining it as 0x0f (since the baud rate constants +run 0x00 to 0x0e). It almost works: FujiChat is able to send & receive, +but even with hardware handshaking, it can't keep up (lots of incoming +packets get dropped, and the connection eventually stalls). Since Slor's +HW handshaking is known to work (he can do 9600 baud reliably, and runs +unpatched slattach without -L), I assume the trouble is that the loop +in rs232dev.c is too slow. Recoding it in asm may help. It may have to +use SIO instead of CIO though... or would that make it HW-specific? +Guess it would. + +Added (bloated implementation of) ping time calculation. In the ping +request, we send the contents of the 3 bytes of RTCLOK, and when we get +them back, we subtract them from the current RTCLOK value and format +as number of seconds + 10ths of seconds. Code uses CLOCKS_PER_SECOND, +which means it auto-adjusts for PAL vs. NTSC timing. If RTCLOK rolled over +between request & response, it'll appear to be a huge negative number... +but I think uIP fails when RTCLOK rolls over anyway. Most people won't +leave their Atari up for 3+ days anyway I guess. + +Clean up the raw IRC protocol server messages. We now strip the server +hostname, parse numerics, and (for a few numerics) print meaningful +message like "Topic". This could use a lot more work, but it does save +our limited screen space. + +Implemented UIFLAG_HIDE_MOTD in fujichat.c. The traffic indicator still +appears, to let the user know something's going on. Initial pre-MOTD +server messages are not suppressed. + +- 20081119 bkw: + +*Major* surgery! The patient's vitals are strong, and the operation +is a tentative success. + +fujichat's config menu has been split off into a separate executable. +This keeps the menu from sitting around taking up memory while we're +actually chatting. Also it paves the way for a fancier config menu with +more options and a nice UI. + +While I was at it, I added a top-level menu program and an "about" +option, with a separate viewer program that's a simple version of "more" +from UNIX. + +All the programs (fujichat, fujiconf, menu) are able to load & run +each other thanks to aexec (aka atari_exec()). This is a teensy little +binary-file loader that fits into page 6, and gets prepended to +all the other programs. + +Also, the Bob-verter driver is no longer baked into fujichat. Instead, +we've got a tiny little loader called "loadchat", which does this: + +- Check for the existence of an R: device in HATABS +- If not found, load the file DEFAULT.SER (ignoring "file not found") +- Load fujichat.com + +DEFAULT.SER is just a binary load file. By default it'll be a copy +of Bob-verter (also there's a copy called BOBVERT.SER). + +The config menu (fujiconf) allows the user to choose which serial +device he has (by user-friendly name), and copies the appropriate +driver (named something.SER) to DEFAULT.SER. Nota bene: + +- The driver is only loaded when the user chooses to run FujiChat +itself, from either menu.com or fujiconf.com + +- If the driver setting gets changed before any R: driver is loaded, +loadchat will load the new driver. + +- The menu allows the user to type a filename, to use a driver not +in the built-in list (which is good as it's not a very complete +list yet) + +- The menu also allows "none" as a choice, meaning he's taking +responsibility for providing an R: handler himself (e.g. as an +AUTORUN.SYS, or loaded from a SpartaDOS batch file or whatever). +In this case, DEFAULT.SER will be deleted, and loadchat will +silently fail to load it, and then FujiChat will just use the +preloaded R: handler (or if it's missing, it'll give an error +and let the user go back & reconfigure). + +- The way this is set up, it means the user can just use fujichat.com +as a standalone executable, without the presence of menu.com, loadchat.com, +fijuconf.com, or any other stuff from the disk. He can prepend his +R: handler to it and load it from anywhere. It'll use the default +config, but that's OK (most people would set up their SLIP host +with the defaults anyway). He'll have to enter his server every +time, and use /nick, but the program will *work*. + +- It's also possible to run fujiconf once to create a config file, then +copy fujichat.com and fujichat.cfg to some other disk or directory +or whatever, and run it without having the menu/loadchat/fujiconf/etc. +The only missing capability is that he can't create a new config file. + +- The de luxe option: it should be fully possible to copy the contents +of the FujiChat floppy image to a MyDOS or SpartaDOS subdirectory +(obviously don't copy autorun.sys, dos.sys, dup.sys). All the filenames +used by the program begin with D:, not D1:, so they should use the +current drive and directory. (Eventually I'll write an INSTALL.COM +that makes the directory & copies the stuff for you!) + +Other changes: + +Break key is now disabled. No more accidentally sending a line when +you meant to hit Backspace. + +There's now a tiny AUTORUN.SYS that finishes the DOS boot stuff, then +runs MENU.COM (the main menu) for us. + +MENU.COM, FUJICONF.COM, and FUJICHAT.COM all look in page 5 for the +config, which stays resident when switching between programs. If it's +not there, they all try to load it from FUJICHAT.CFG. If that fails, +they use built-in defaults. + +FujiChat (FUJICHAT.COM) *can not* create FUJICHAT.CFG itself. + +Had to use memcpy() instead of Adam's uip_sethostaddr() and +uip_setdraddr() macros (they have trouble when their arguments are +dereferenced pointers; probably this is a deficiency in cc65). + +The config menu is a lot more user-friendly. It stops the user from +setting unreadable colors (where fg/bg have equal luma values), and +the long, long list of questions is broken up into sections. + +rs232dev_init() now returns a status. If it's not RS_ERR_OK, something +went wrong. If this happens, FujiChat allows the user to retry, +run fujiconf, or exit to DOS. + +I won't be providing single-file .xex downloads any more. The ATR image +will be the main distribution (possibly I'll also offer the contents +in a zip file, for S-Drive or MyIDE users). The main executable still +works standalone, but is not fully functional, so I'd rather discourage +'noobs' from running it that way (non-noobs know how to extract the +.xex from the .atr image themselves). + +Changed uip-conf.h, now uIP is compiled with support for only one +TCP conn, one UDP conn, and one TCP listen port (TCP listen support +isn't disable-able in uIP; I'll change that later). Also disabled +UDP checksums. + +Added FEAT_* macros to remove some FujiChat features at compile time. +See fujichat.c for the list of features and how much code space they +take up. + +Added network traffic indicator in upper right corner of screen: +up arrow for transmit, down arrow for receive. FEAT_TRAFFIC_INDICATOR + +/j or /join with no argument now tries to rejoin the current channel +(use if you get kicked). Also, fixed bug where /j with no argument +tried to join a bogus (null) channel. + +/nick now tracks your nick changes. This fixes the bug where, after +a nick change, private messages to your new nick appear to be +channel traffic. + + +- 20081116 bkw: +Fixed bug in 0.3.0 (ctcp responses didn't work when a ctcp request came +back in the middle of typing a line) +Made baud rate selectable in the UI (there was already a config file entry +for it) +0.3.0 released +Added ^W and ^U (delete last word, delete-line, emacs-style) +Added simulated edit buffer using delete-line and cursor controls. This +isn't as nice as a custom display list, but it stays compatible with (most) +80-column drivers. +Added option to run config menu from the "return to connect" prompt, got rid +of "Use defaults [y/n]" prompt. +Added support for selecting the server port (default still 6667) +Added support for real name field +We now close the serial port when disconnected (needed for the config menu +to be able to save to disk, at least with bob-verter driver) + +- 20081115 bkw: +Changed uIP packet buffer size to 576. This will help with those DNS aliases +that return 15 hostnames + aliases (like irc.freenode.org). TCP MSS is still +set to 160 - header_len, to keep it feeling like an interactive app. + +strcmp against config.nick changed to strcasecmp, so we can correctly +handle messages/ctcps to the lowercase (or whatever) version of our nick. + +Added option to enter an IRC server instead of just "press return +to connect". The default is the config file server, or last server +connected to. + +- 20081113 bkw: +0.2 released +Added option to exit to DOS +FujiChat now works with FreeNode (mostly) +Made local/peer/DNS IP configurable +Server hostname now configurable +UI flags configurable: visual bell, no bell, msg bell, show ping +Default server list is now hostnames +Consolidate some UI I/O code +Initial support for DNS resolution + +- 20081112 bkw: +Added visual bell support +Added ` (backtick) support (prints as inverse single quote) + +- 20081105: 0.1 released diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..a942af8 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,102 @@ +# Copyright (c) 2001, Adam Dunkels. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote +# products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# This file is part of the uIP TCP/IP stack. +# +# $Id: Makefile,v 1.13 2006/06/11 21:55:03 adam Exp $ +# + +all: uip fujiconf.xex aexec.xex fujimenu.xex makeauto.xex about.xex loadmkau.xex loadmenu.xex keybuf.o clear_rts + +CC = cl65 +AR = ar65 +APPS = telnet resolv +CFLAGS = -t atari -I../uip/uip -I. -O + +-include Makefile.include + +uip: $(addprefix $(OBJECTDIR)/, fujichat.o common.o commands.o rs232dev.o clock-arch.o) keybuf.o apps.a uip.a fujiput.s + +#fujichat.o: common.h features.h fujichat.h # no worky? + +keybuf.o: keybuf.s + ca65 -t atari -l -o keybuf.o keybuf.s + +common.o: common.c common.h + $(CC) $(CFLAGS) -c -o common.o common.c + +fujiconf.xex: fujiconf.c fujichat.h common.o + $(CC) $(CFLAGS) -o fujiconf.xex fujiconf.c common.o obj/uiplib.o + +fujimenu.xex: fujimenu.c fujichat.h aexec.xex common.o + $(CC) $(CFLAGS) -o fujimenu.xex fujimenu.c common.o + +about.xex: about.c fujichat.h aexec.xex common.o + $(CC) $(CFLAGS) -o about.xex about.c common.o + +#loadchat.xex: loadchat.c fujichat.h +# $(CC) $(CFLAGS) -o loadchat.xex loadchat.c + +#loadchat.xex: loadchat.dasm +#dasm loadchat.dasm -f3 -oloadchat.xex + +makeauto.xex: makeauto.c + $(CC) $(CFLAGS) -o makeauto.xex makeauto.c common.o + +loadmenu.xex: loadmenu.dasm + dasm loadmenu.dasm -f3 -oloadmenu.xex + +loadmkau.xex: loadmkau.dasm + dasm loadmkau.dasm -f3 -oloadmkau.xex + +aexec.xex: aexec.dasm + dasm aexec.dasm -f3 -oaexec.xex + +test: newdisk + atariserver fujitest.atr + sudo sh ./start_slip.sh + +disk: newdisk + +newdisk: all + sh mkdisk.sh + +old_disk: uip + cat rvert.com uip > autorun.sys + axe -w autorun.sys uiptest.atr + #xterm -e atariserver uiptest.atr + +clean: + rm -fr *.xex obj/ *.o *~ *core uip $(OBJECTDIR) *.a + mkdir obj + +keybuftest.xex: keybuftest.c keybuf.o + $(CC) $(CFLAGS) -o keybuftest.xex keybuftest.c keybuf.o + +# native, not Atari! +clear_rts: clear_rts.c + cc -o clear_rts clear_rts.c diff --git a/src/Makefile.include b/src/Makefile.include new file mode 100644 index 0000000..05ce291 --- /dev/null +++ b/src/Makefile.include @@ -0,0 +1,47 @@ + + +ifdef APPS + APPDIRS = $(foreach APP, $(APPS), ../uip/apps/$(APP)) + -include $(foreach APP, $(APPS), ../uip/apps/$(APP)/Makefile.$(APP)) + CFLAGS += $(addprefix -I../uip/apps/,$(APPS)) +endif + +ifndef CCDEP + CCDEP = $(CC) +endif +ifndef CCDEPCFLAGS + CCDEPCFLAGS = $(CFLAGS) +endif +ifndef OBJECTDIR + OBJECTDIR = obj +endif + +ifeq (${wildcard $(OBJECTDIR)},) + DUMMY := ${shell mkdir $(OBJECTDIR)} +endif + + +vpath %.c . ../uip/uip ../uip/lib $(APPDIRS) + +$(OBJECTDIR)/%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(OBJECTDIR)/%.d: %.c + @set -e; rm -f $@; \ + $(CCDEP) -MM $(CCDEPCFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,$(OBJECTDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +UIP_SOURCES=uip.c uip_arp.c uiplib.c psock.c timer.c uip-neighbor.c + + +ifneq ($(MAKECMDGOALS),clean) +-include $(addprefix $(OBJECTDIR)/,$(UIP_SOURCES:.c=.d) \ + $(APP_SOURCES:.c=.d)) +endif + +uip.a: ${addprefix $(OBJECTDIR)/, $(UIP_SOURCES:.c=.o)} + $(AR) a $@ $^ + +apps.a: ${addprefix $(OBJECTDIR)/, $(APP_SOURCES:.c=.o)} + $(AR) a $@ $^ diff --git a/src/Makefile.webclient.ok b/src/Makefile.webclient.ok new file mode 100644 index 0000000..24f4746 --- /dev/null +++ b/src/Makefile.webclient.ok @@ -0,0 +1,50 @@ +# Copyright (c) 2001, Adam Dunkels. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote +# products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# This file is part of the uIP TCP/IP stack. +# +# $Id: Makefile,v 1.13 2006/06/11 21:55:03 adam Exp $ +# + +all: uip + +CC = cl65 +AR = ar65 +APPS = webclient resolv +CFLAGS = -t atari -I../uip -I. -O + +-include Makefile.include + +uip: $(addprefix $(OBJECTDIR)/, main.o rs232dev.o clock-arch.o) apps.a uip.a + +test: uip + cat rvert.com uip > autorun.sys + axe -w autorun.sys uiptest.atr + #xterm -e atariserver uiptest.atr + +clean: + rm -fr *.o *~ *core uip $(OBJECTDIR) *.a diff --git a/src/about.c b/src/about.c new file mode 100644 index 0000000..01d6fcb --- /dev/null +++ b/src/about.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include "fujichat.h" +#include "common.h" + +/* TODO: rewrite in asm. This does NOT need to + be 7K of object code. */ + +void more(char *file) { + char c, line = 0; + char buf[200]; + FILE *f = fopen(file, "r"); + + putchar(0x7d); + + if(!f) { + printf("%s not found\n", file); + cgetc(); + return; + } + + while(fgets(buf, 200, f)) { + if(*buf == '#') continue; + + line += (strlen(buf) / 40 + 1); + if(line > 23) { + fputs("--more--", stdout); + fflush(stdout); + + c = cgetc(); + if(c == 27) + break; + + putchar(A_DEL); + line = 0; + } + + fputs(buf, stdout); + } + + fclose(f); + + fputs("--any key--", stdout); + fflush(stdout); + + c = cgetc(); +} + +int main(int, char **) { + more("D:ABOUT.TXT"); + atari_exec(MENU_FILENAME); +} diff --git a/src/aexec.dasm b/src/aexec.dasm new file mode 100644 index 0000000..9338c4c --- /dev/null +++ b/src/aexec.dasm @@ -0,0 +1,206 @@ + +; Load an Atari DOS executable, including support for init and run vectors +; Parameters: nul-terminated filename pointer in A/X (lo/hi) +; Return value: 0 for success, nonzero on error, never returns if exe has +; a run address. + +; TODO: learn ca65 syntax better, port this to ca65 + +; Usage: build with "dasm aexec.dasm -f3 -oaexec.xex" +; "Link" to your program with "cat aexec.xex yourprog.xex > newprog.xex" + +; int __fastcall__ (*atari_exec_p)(char *) = (int __fastcall__ (*)(char *))0x600; +; #define atari_exec(x) ((*atari_exec_p)(x)) +; then call with: atari_exec("D:PROGRAM.XEX"); + +; If the file can't be opened for whatever reason, atari_exec() returns a +; nonzero result (the Atari error number). + +; If the file loads OK and has a run address, atari_exec() never returns +; (runs the loaded program, then exits to DOS if/when the program exits). +; This means there's no memory conflict between caller and callee. + +; If there was no run address, atari_exec returns 0 to the caller. +; The caller is responsible for making sure the loaded program doesn't +; step on the memory used by the caller or atari_exec itself! + +; If the file is openable but invalid (not a XEX, or truncated), current +; atari_exec() implementation hangs the machine with a red screen, since +; there's no way to know whether the partially-loaded program overwrote +; the caller... + + + processor 6502 + include "equates.inc" + +tmp = $d4 ; aka FR0 +loadaddr = $d6 + +main = $0600 + + org main-6 + word $FFFF + word main + word endmain-1 + + org main + pha + txa + pha + jsr fclose + pla + tax + pla + + sta ICBAL+16 + stx ICBAH+16 + sta tmp + stx tmp+1 + ldy #0 + +; do an OPEN #1,4,0,$filename + +; get length of filename +fnameloop: + lda (tmp),y + beq fndone + iny + bne fnameloop + + ; set IOCB #1 buffer addr, buffer len, etc +fndone: + sty ICBLL+$10 + lda #0 + sta ICBLH+$10 + sta ICAX2+$10 + + ; init these to 0 so we can tell if they change + sta RUNAD + sta RUNAD+1 + sta INITAD + sta INITAD+1 + + ldx #4 + stx ICAX1+$10 + dex + stx ICCOM+$10 ; cmd #3 = OPEN + + ldx #$10 + jsr CIOV ; do the OPEN + bpl readheader + + tya ; CIO returns error code in Y reg + ldx #0 + rts + +fail: + lda #$48 + sta 710 +hang bne hang + +readheader: +; read 2 bytes into local buffer + jsr read2bytes + bpl ok + cpy #136 ; EOF + bne fail + beq close_file ; if at EOF, close the file + +; if they're $ffff, try again +ok: + lda tmp + tax + and tmp+1 + cmp #$ff + beq readheader + +; store those 2 bytes in loadaddr + lda tmp+1 + sta loadaddr+1 + stx loadaddr + +; read 2 more bytes into local buffer (end addr) + jsr read2bytes + bmi fail +; subtract loadaddr from end addr, add 1, to get length +; store length into IOCB + lda loadaddr + sta ICBAL+$10 + lda loadaddr+1 + sta ICBAH+$10 + + sec + lda tmp + sbc loadaddr + sta ICBLL+$10 + lda tmp+1 + sbc loadaddr+1 + sta ICBLH+$10 + inc ICBLL+$10 + bne noinc + inc ICBLH+$10 +noinc: + jsr read_segment + bmi fail + +; if INITAD modified, JSR there + lda INITAD + ora INITAD+1 + beq readheader + + jsr do_init + + lda #0 + sta INITAD + sta INITAD+1 + beq readheader ; branch always + +do_init + jmp (INITAD) + +close_file: + jsr fclose + +; JSR through RUNAD if it's not zero + lda RUNAD + ora RUNAD+1 + beq norun + + jsr do_run + jmp (DOSVEC) ; does not return + +; If there was no run address, we were probably loading an R: driver, so +; our caller is safe to return to +norun + lda #0 ; return 0 + tax + rts + +read2bytes: + lda #tmp + sta ICBAL+$10 + lda #2 + sta ICBLL+$10 + lda #0 + sta ICBAH+$10 + sta ICBLH+$10 +read_segment: + lda #C_GETCHR + sta ICCOM+$10 + ldx #$10 + jmp CIOV + +do_run + jmp (RUNAD) + +fclose + lda #C_CLOSE + sta ICCOM+$10 + ldx #$10 + jmp CIOV + +endmain + +; word RUNAD +; word RUNAD+1 +; word main diff --git a/src/aexec.h b/src/aexec.h new file mode 100644 index 0000000..41cc9fd --- /dev/null +++ b/src/aexec.h @@ -0,0 +1,7 @@ +#ifndef AEXEC_H +#define AEXEC_H + +extern int __fastcall__ (*atari_exec_p)(char *); +#define atari_exec(x) ((*atari_exec_p)(x)) + +#endif diff --git a/src/aextest.dasm b/src/aextest.dasm new file mode 100644 index 0000000..da4522b --- /dev/null +++ b/src/aextest.dasm @@ -0,0 +1,52 @@ + + processor 6502 + include equates.inc + +init_routine = $2E00 + + org init_routine-6 + word $FFFF + word init_routine + word end_init_routine-1 + + org init_routine + + lda #0 + sta COLOR2 + + lda RTCLOK+2 +iloop: + cmp RTCLOK+2 + beq iloop + + rts + +end_init_routine: + + word INITAD + word INITAD+1 + word init_routine + +main_routine = $2F00 + rorg main_routine-6 + word main_routine + word end_main_routine-1 + + rorg main_routine + + lda #$0F + sta COLOR2 + + lda RTCLOK+2 +mloop: + cmp RTCLOK+2 + beq mloop + + rts + +end_main_routine: + + word RUNAD + word RUNAD+1 + word main_routine + diff --git a/src/aextest2.dasm b/src/aextest2.dasm new file mode 100644 index 0000000..fa897c6 --- /dev/null +++ b/src/aextest2.dasm @@ -0,0 +1,27 @@ + + processor 6502 + include equates.inc + +main = $6000 + + org main-6 + word $FFFF + word main + word end_main-1 + + org main + + lda #filename + jsr $0600 + lda #$08 + sta COLOR2 + rts + +filename: byte "D:AEXTEST.XEX", $00 + +end_main: + + word RUNAD + word RUNAD+1 + word main diff --git a/src/atari850.ser b/src/atari850.ser new file mode 100644 index 0000000..57eee3f Binary files /dev/null and b/src/atari850.ser differ diff --git a/src/atariserver.sh b/src/atariserver.sh new file mode 100755 index 0000000..5a1d838 --- /dev/null +++ b/src/atariserver.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# Configurable stuff: + +# Name of the disk image (default: command line arg, or fujichat.atr) +ATR_IMAGE=${1-fujichat.atr} + +TTY=/dev/ttyS0 # serial port to use + +# No delay: +#DELAY="true" + +# 1 second: +#DELAY="sleep 1" + +# 1/4 second (may not work on old Linux installs): +DELAY="usleep 250000" + +# End of config section, start of code: + +ifconfig $SLIP_IFACE down 2&>/dev/null +killall $SLATTACH 2&>/dev/null +fuser -k $TTY 2&>/dev/null # make sure nobody's using the port... +$DELAY +fuser -k -9 $TTY 2&>/dev/null # Just in case... +$DELAY +modprobe atarisio port=$TTY +$DELAY +atariserver $ATR_IMAGE +#atariserver autorun.sys # fails when run from MyPicoDOS, why? +$DELAY +rmmod atarisio +$DELAY diff --git a/src/atariserver_slip.sh b/src/atariserver_slip.sh new file mode 100755 index 0000000..42b37cd --- /dev/null +++ b/src/atariserver_slip.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +# This script is for use with the uIP test programs and AtariSIO. +# Before running this, run "make disk" to create the disk image. +# This script needs to be run with root privileges (e.g. with sudo) + +# Configurable stuff: + +ATR_IMAGE=${1-fujichat.atr} + +#ATR_IMAGE=fujitest.atr # Name of the disk image +TTY=/dev/ttyS0 # serial port to use +BAUD=4800 # must match compiled-in value in rs232dev.c +SLATTACH=a8_slattach # slattach binary (possibly patched) +SLIP_IFACE=sl0 # probably no need to change this +LOCAL_IP=192.168.0.1 # SLIP IP address for Linux host +REMOTE_IP=192.168.0.2 # SLIP IP address for Atari host +IP_FORWARD=yes # Route packets for the Atari? +IP_MASQUERADE=yes # NAT for the Atari? +MASQ_IFACE=ra0 # if NATing, our main (LAM or internet) interface +DUMP_PACKETS=yes # Run tcpdump on sl0 interface? + +# DELAY is needed on some (most?) systems because e.g. atariserver tries +# to run before the atarisio module is fully initialized. Choose one: + +# No delay: +#DELAY="true" + +# 1 second: +#DELAY="sleep 1" + +# 1/4 second (may not work on old Linux installs): +DELAY="usleep 250000" + +# End of config section, start of code: + +ifconfig $SLIP_IFACE down 2&>/dev/null +killall $SLATTACH 2&>/dev/null +fuser -k $TTY 2&>/dev/null # make sure nobody's using the port... +$DELAY +fuser -k -9 $TTY 2&>/dev/null # Just in case... +$DELAY +modprobe atarisio port=$TTY +$DELAY +atariserver $ATR_IMAGE +#atariserver autorun.sys # fails when run from MyPicoDOS, why? +$DELAY +rmmod atarisio +$DELAY +echo "Starting SLIP on $SLIP_IFACE, local $LOCAL_IP, remote $REMOTE_IP" +$SLATTACH -L -p slip -s $BAUD $TTY & +$DELAY +ifconfig $SLIP_IFACE $LOCAL_IP mtu 576 +ifconfig $SLIP_IFACE $LOCAL_IP pointopoint $REMOTE_IP + +if [ "$IP_MASQUERADE" = "yes" ]; then + echo "IP Masquerading enabled" + iptables -F + iptables -t nat -F + iptables -t nat -A POSTROUTING -o $MASQ_IFACE -j MASQUERADE +fi + +if [ "$IP_FORWARD" = "yes" ]; then + echo "IP Forwarding enabled" + echo "1" > /proc/sys/net/ipv4/ip_forward +fi + +if [ "$DUMP_PACKETS" = "yes" ]; then + tcpdump -i $SLIP_IFACE -X -n -vvv -s 0 +fi diff --git a/src/atariserver_slirp.sh b/src/atariserver_slirp.sh new file mode 100755 index 0000000..c6ba620 --- /dev/null +++ b/src/atariserver_slirp.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# Configurable stuff: + +# Name of the disk image (default: command line arg, or fujichat.atr) +ATR_IMAGE=${1-fujichat.atr} + +TTY=/dev/ttyS0 # serial port to use +BAUD=4800 # must match FujiChat conf + +# This setting is only needed if you're using an AtariMax (Steve Tucker) +# auto-sensing SIO2PC as your serial device. +TUCKER_SIO2PC_HACK="yes" + +# DELAY is needed on some (most?) systems because e.g. atariserver tries +# to run before the atarisio module is fully initialized. Choose one: + +# No delay: +#DELAY="true" + +# 1 second: +#DELAY="sleep 1" + +# 1/4 second (may not work on old Linux installs): +DELAY="usleep 250000" + +# End of config section, start of code: + +ifconfig $SLIP_IFACE down 2&>/dev/null +killall $SLATTACH 2&>/dev/null +fuser -k $TTY 2&>/dev/null # make sure nobody's using the port... +$DELAY +fuser -k -9 $TTY 2&>/dev/null # Just in case... +$DELAY +modprobe atarisio port=$TTY +$DELAY +atariserver $ATR_IMAGE +#atariserver autorun.sys # fails when run from MyPicoDOS, why? +$DELAY +rmmod atarisio +$DELAY + +slirp "tty $TTY" "mru 576" "mtu 576" "baudrate $BAUD" & + +if [ "$TUCKER_SIO2PC_HACK" = "yes" ]; then + sleep 1 + ./clear_rts +fi diff --git a/src/bobvert.com b/src/bobvert.com new file mode 100644 index 0000000..b5aeccc Binary files /dev/null and b/src/bobvert.com differ diff --git a/src/clear_rts b/src/clear_rts new file mode 100755 index 0000000..e855ca0 Binary files /dev/null and b/src/clear_rts differ diff --git a/src/clear_rts.c b/src/clear_rts.c new file mode 100644 index 0000000..52da3f5 --- /dev/null +++ b/src/clear_rts.c @@ -0,0 +1,42 @@ +/* Compile with: + gcc -o toggle_rts toggle_rts.c + + Change PORT if necessary. + */ +#define PORT "/dev/ttyS0" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int main() { + int fd, status; + + fd = open(PORT, O_RDWR); + if(fd < 0) { + perror(PORT); + return 1; + } + + // fprintf(stderr, "ioctl(fd, TIOCMGET, &status);\n"); + ioctl(fd, TIOCMGET, &status); + /* + if(status & TIOCM_RTS) { + fprintf(stderr, "RTS set\n"); + } else { + fprintf(stderr, "RTS clear\n"); + } + */ + status &= ~TIOCM_RTS; + ioctl(fd, TIOCMSET, &status); + // fprintf(stderr, "ioctl(fd, TIOCMSET, &status);\n"); + fprintf(stderr, "RTS forced off (Tucker SIO2PC)\n"); + return 0; +} diff --git a/src/clock-arch.c b/src/clock-arch.c new file mode 100644 index 0000000..8cff850 --- /dev/null +++ b/src/clock-arch.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: clock-arch.c,v 1.2 2006/06/12 08:00:31 adam Exp $ + */ + +/** + * \file + * Implementation of architecture-specific clock functionality + * \author + * Adam Dunkels + */ + +#include "clock-arch.h" + +/*---------------------------------------------------------------------------*/ +clock_time_t +clock_time(void) +{ + return clock(); +} +/*---------------------------------------------------------------------------*/ diff --git a/src/clock-arch.h b/src/clock-arch.h new file mode 100644 index 0000000..8ea4edc --- /dev/null +++ b/src/clock-arch.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: clock-arch.h,v 1.2 2006/06/12 08:00:31 adam Exp $ + */ + +#ifndef __CLOCK_ARCH_H__ +#define __CLOCK_ARCH_H__ + +#include +typedef int clock_time_t; +#define CLOCK_CONF_SECOND (_clocks_per_sec()) + +#endif /* __CLOCK_ARCH_H__ */ diff --git a/src/col64/autorun.sys b/src/col64/autorun.sys new file mode 100644 index 0000000..956e404 Binary files /dev/null and b/src/col64/autorun.sys differ diff --git a/src/col64/col64.bin b/src/col64/col64.bin new file mode 100644 index 0000000..956e404 Binary files /dev/null and b/src/col64/col64.bin differ diff --git a/src/col64/col64.dasm b/src/col64/col64.dasm new file mode 100644 index 0000000..aca1259 --- /dev/null +++ b/src/col64/col64.dasm @@ -0,0 +1,1194 @@ + +; ---------------------------------------------------------------------------- +; 64x32 software text driver +; Uses 4x5 font in 5x6 character cells +; Based on disassembled COL80 driver + +; This driver is missing quite a few things a full E: driver should have: + +; - Does not work with BASIC or any other cart! Though if START_ADDRESS_1 +; is changed to $7Cxx, a BASIC-able version could be assembled + +; - No support for cursor controls, insert/delete, or even clear screen +; (instead the control-codes are printed as normal characters, if they're +; above 31 decimal). This is a feature: our intended application is an +; IRC client, where ASCII codes 125 and 126 represent } and ~ chars, +; not clear-screen and backspace. + +; - Backspace key is supported during get-byte, but printing a backspace +; with put-byte prints a tilde instead. Again, a feature. + +; - No support for low ASCII at all: any attempt to input or print a character +; in the range 0-31 decimal is just ignored (this includes the arrow keys). +; This is done to keep the font size at 96 characters, so it'll fit in a +; page. Also IRC doesn't use low-ASCII. + +; - Does not attempt to survive a warmstart + +; - Will fail disastrously if an application sets COLCRS/ROWCRS to any +; out-of-range values + +; - Only displays the cursor during get-byte operations + +; On the other hand, this driver is tiny (font is 240 bytes, code 718, not +; counting 100 bytes of throwaway init code in the tape buffer), and plays +; nice with cc65's stdio support (though NOT conio, don't even go there) + +; Theory of operation: + +; This is an Atari OS-compliant device driver. On load, the init routine +; replaces the E: entry in HATABS with a pointer to our vector table, +; col64_vector_tab. + +; We implement the CIO commands OPEN, CLOSE, GETBYTE, and PUTBYTE. The +; GET-STATUS and SPECIAL commands are not implemented, and the CLOSE +; command simply returns success (it doesn't need to do anything else). + +; When a channel is OPENed to our new E: device, the col64_open routine +; calls part of the OS's S: handler to switch to GRAPHICS 8 (320x192 mono) +; mode. + +; When the CIO PUT-BYTES or PUT-RECORD calls are made on our channel, CIO +; calls our PUTBYTE routine (col64_putbyte) as needed to write (print) +; characters to the screen. col64_putbyte keeps track of the current +; cursor position (using COLCRS and ROWCRS), and either renders a glyph +; at the current location, or (when the EOL character $9B is printed) +; moves the cursor to the beginning of the next line, scrolling the +; display RAM if necessary. + +; When the CIO GET-BYTES or GET-RECORD calls are made on our channel, CIO +; calls our GETBYTE routine (col64_getbyte). This routine maintains its +; own buffer of user-input characters. When first called (or any call when +; the buffer is empty), col64_getbyte reads a complete line of input using +; the OS's K: handler, echoing typed characters to the screen using our +; own col64_putbyte. Only the backspace key is supported for editing. Once +; the user presses Return, the first byte in the buffer is returned to +; the caller. On subsequent calls, characters are returned from the buffer +; until the buffer is empty. At this point, the next call to col64_getbyte +; will result in a new line of input being read. + +; col64_putbyte calls render_glyph to draw a character in display RAM. +; The font consists of 96 characters (low ASCII not supported), each 4 pixels +; wide and 5 tall [*]. These are rendered into 5x6 character cells, with the +; extra pixels being left blank to provide padding between characters. +; Since 5 pixel wide cells don't line up evenly on display RAM byte +; boundaries, render_glyph has to shift each 4-pixel line of glyph +; data the appropriate number of times, and combine the result with the +; rest of each screen byte (that portion that's outside of the 5-pixel +; cell we're currently writing to). Surprisingly, this is accomplished +; slightly faster than the standard OS E: driver prints a single character. +; (unfortunately, scrolling the screen is *much* slower than the OS E: +; driver's scrolling...) + +; [*] ...except the lowercase q j p q y, which have true descenders. The +; glyphs for these are still 4x5, but the 6th row of pixels for all 5 +; get stored together in the last glyph in the set (ASCII code $7F, +; which should be considered an unprintable character). + + processor 6502 ; DASM-specific + +; ---------------------------------------------------------------------------- + include equates.inc + +; "backdoor" vectors into the S: and K: ROM drivers. These are addres-minus-1, +; called by PHA/PHA/RTS. +s_dev_open_lo = $E410 ; (not named in OS sources) +s_dev_open_hi = $E411 ; "" +k_dev_get_lo = $E424 ; "" +k_dev_get_hi = $E425 ; "" + +; ---------------------------------------------------------------------------- +; Constants + +LAST_ROW = $1F ; last valid cursor row on screen, 31 decimal (we count from 0) +EOL = $9B ; Atari ASCII end-of-line (aka the Return key) +INVERTED_MASK = $F8 ; stored in inverse_mask when rendering in inverse video + +; ---------------------------------------------------------------------------- +; Defaults + +DEFAULT_TEXT_COLOR = $00 +DEFAULT_BG_COLOR = $C8 +DEFAULT_RMARGN = $3F + +; ---------------------------------------------------------------------------- +; ZP storage +; Reuse some of the E:/S: devices' storage +; These all get recalculated on col64_putbyte entry, +; so it's probably OK to mix with GR.8 PLOT/DRAWTO stuff + + seg.u "data" + org $A0 ; (used to be $90 aka OLDROW) +mask_lo ds 1 ; Holds the 16-bit mask, used by render_glyph +mask_hi ds 1 +screen_ptr_lo ds 1 ; Pointer to display RAM: render_glyph and scroll_screen +screen_ptr_hi ds 1 ; both use this. +font_index ds 1 ; index into font: TMPCHR * 5 +shift_amount ds 1 ; How many times to right-shift during render_glyph + + ;org $63 ; aka LOGCOL +glyph_data_lo ds 1 ; render_glyph stores (possibly shifted) glyph data +glyph_data_hi ds 1 ; here. Also a 2nd display RAM pointer in scroll_screen +lo_nybble_flag ds 1 ; non-zero if glyph data in top 4 bits of font + + ;org $68 ; aka SAVADR +inverse_mask ds 1 ; 0 for normal video, INVERTED_MASK for inverse +line_buffer_index ds 1 ; used by col64_getbyte +descender ds 1 ; offset-1 of true descender byte, into font_data + +; We also use several other ZP locations, normally used by the OS E: driver: +; COLCRS ROWCRS TMPCHR BUFCNT RMARGN SAVMSC are used for the same purpose as +; the OS uses them for. + +; ---------------------------------------------------------------------------- +; Non-ZP storage (cassette buffer for now) + + org CASBUF +line_buffer ds $80 + + seg "code" +; ---------------------------------------------------------------------------- +; XEX segment header + +;START_ADDRESS_1 = $9C78 +START_ADDRESS_1 = $9C00 ; should end at $A036; subtract 2K to use with BASIC + org START_ADDRESS_1-6 + + word $FFFF + word START_ADDRESS_1 + word END_ADDR_1 + +; ---------------------------------------------------------------------------- +; Font data should be aligned on a page boundary +; (for speed; still works unaligned). Each 5 bytes stores 2 glyphs +; side-by-side. When rendering into 5x6 cells, the bottom line and +; the left column are set to all 0 (or all 1 for inverse video) for padding, +; so the glyphs can take up the entire 4x5 space. +; Only character codes 32 through 127 are supported; this is 96 +; characters. At 2 glyphs per 5 bytes, that's 96/2*5=240 bytes, +; which means the whole font fits into one page and can be +; accessed with X or Y indexed mode rather than (indirect),Y. + +font_data: + ;include font4x5.inc + include col64_ext.inc + +DESCENDERS = $EB ; g j p q y descender bytes, offset from font_data + +; ---------------------------------------------------------------------------- +; Mask tables, used by setup_mask. Indexed by (COLCRS % 8), since they +; would repeat every 8 bytes anyway. Each mask is 16 bits, and contains +; a 1 for each pixel in screen RAM that we *don't* want to change when +; writing pixels (because they're not part of the current character cell), +; but see below... + +mask_lo_tab: + byte $07, $F8, $C1, $FE, $F0, $83, $FC, $E0 + +; In mask_hi_tab, $00 is never a valid mask, while $FF means "don't touch any +; bits in 2nd byte". As a minor optimization, $00 appears in the table in +; place of $FF. This allows us to just test the Z flag after loading the mask +; hi byte, instead of needing to compare against $FF. +; (Actually, on further thought, the $FF's could have been left in, and the +; test could have been made on the N flag: any hi mask with bit 7 set won't have +; any other bits clear. *Shrug*) + +mask_hi_tab: + byte $00, $3F, $00, $0F, $7F, $00, $1F, $00 + +; ---------------------------------------------------------------------------- +; Indexed by COLCRS%8, how many bits to shift the font data right +; The mask_*_tab stuff above could be calculated at runtime from this, +; the tables are only there for speed. + +shift_amount_tab: + byte $00, $05, $02, $07, $04, $01, $06, $03 + +; ---------------------------------------------------------------------------- +; Line address tables, used by setup_screen_ptr. Indexed by ROWCRS. Used by +; setup_screen_ptr + +line_addr_tab_lo: + byte $00, $f0, $e0, $d0, $c0, $b0, $a0, $90 + byte $80, $70, $60, $50, $40, $30, $20, $10 + byte $00, $f0, $e0, $d0, $c0, $b0, $a0, $90 + byte $80, $70, $60, $50, $40, $30, $20, $10 + +line_addr_tab_hi: + byte $00, $00, $01, $02, $03, $04, $05, $06 + byte $07, $08, $09, $0a, $0b, $0c, $0d, $0e + byte $0f, $0f, $10, $11, $12, $13, $14, $15 + byte $16, $17, $18, $19, $1a, $1b, $1c, $1d + +; ---------------------------------------------------------------------------- +; Byte offset within scanline, indexed by COLCRS & $1F value +; Used by setup_screen_ptr. + +column_byte_tab: + byte $00, $00, $01, $01, $02, $03, $03, $04 + byte $05, $05, $06, $06, $07, $08, $08, $09 + byte $0A, $0A, $0B, $0B, $0C, $0D, $0D, $0E + byte $0F, $0F, $10, $10, $11, $12, $12, $13 + +; Used to be indexed by COLCRS, rest of the table was: + ;byte $14, $14, $15, $15, $16, $17, $17, $18 + ;byte $19, $19, $1A, $1A, $1B, $1C, $1C, $1D + ;byte $1E, $1E, $1F, $1F, $20, $21, $21, $22 + ;byte $23, $23, $24, $24, $25, $26, $26, $27 + +; ---------------------------------------------------------------------------- +; Handler table (HATABS will point to this). +; See the HATABS and EDITRV entries in Mapping the Atari for details. + +col64_vector_tab: + word col64_open-1 ; OPEN vector + word col64_close-1 ; CLOSE vector + word col64_getbyte-1 ; GET BYTE vector + word col64_putbyte-1 ; PUT BYTE vector + word col64_close-1 ; GET STATUS vector + word col64_close-1 ; SPECIAL vector + ;jmp col64_init ; Jump to initialization code (JMP LSB/MSB) + ; (Note: the OS really only ever calls the JMP init + ; routines for handlers in ROM, this could be empty) + +; ---------------------------------------------------------------------------- +; Assembly version of GRAPHICS 8+16 command. + +init_graphics_8: + lda #$08 ; graphics mode 8 + sta ICAX2Z + lda #$0C ; R/W access + sta ICAX1Z + jsr open_s_dev + + ; Set default colors + lda #DEFAULT_BG_COLOR + sta COLOR2 + sta COLOR4 + lda #DEFAULT_TEXT_COLOR + sta COLOR1 + + ; Protect ourselves from the OS + lda #START_ADDRESS_1 + sta MEMTOP+1 + rts + +; ---------------------------------------------------------------------------- +; Call the OPEN vector for the S: device, using the ROM vector table +; at $E410. The table stores address-minus-one of each routine, which is +; meant to actually be called via the RTS instruction (standard 6502 +; technique, but confusing the first time you encounter it) + +open_s_dev: + lda s_dev_open_hi + pha + lda s_dev_open_lo + pha + rts + +; ---------------------------------------------------------------------------- +; Callback for the internal get-one-byte, used by the OS to implement the +; CIO GET RECORD and GET BYTES commands. This routine takes no arguments, +; and returns the read byte in the accumulator. + +; Internally, COL64 maintains a line buffer. Each time col64_getbyte is +; called, it returns the next character in the buffer. If the buffer's +; empty (or if the last call returned the last character), a new line +; of input is read from the user (and the first character is returned). +; This is not exactly how the OS E: device works: it reads keystrokes but +; doesn't buffer them, until Return is hit; then it reads from screen +; memory, at the current cursor line (and the line(s) before/after, +; depending on its map of logical => physical lines). We can't do that +; because we don't store character codes in screen memory... although +; we *could* support insert/delete character, delete-line, and left/right +; arrows. We don't, to save driver code size... + +; This code was borrowed from COL80, then big chunks of it were diked out +; and/or optimized. + +col64_getbyte: + lda BUFCNT + beq get_line ; See if there are bytes left in the buffer + +get_next_byte: ; Yes: return next byte from the buffer + ldx line_buffer_index + lda line_buffer,x + dec BUFCNT + inc line_buffer_index + jmp return_success + +; Buffer is empty. +; Get a line of input from the user, terminated by the Return key. +get_line: + lda #$00 + sta BUFCNT + sta line_buffer_index + +show_cursor: + jsr print_inv_space + jsr get_keystroke + +; code meant to deal with BREAK key, left out 'cause FujiChat disables BREAK +; cpy #$01 +; beq keystroke_ok +; ldy #0 +; sty line_buffer_index +; sty BUFCNT + +keystroke_ok: + cmp #$20 + bcc show_cursor ; ignore low ASCII + cmp #EOL + beq return_key_hit + +check_backs_key: + cmp #$7E + beq backs_key_hit + +;check_clear_key: ; don't bother, don't need + ; (if we did want this, it should check delete-line instead!) + ;;cmp #$7D + ;;beq clear_key_hit + +normal_key_hit: + ldx BUFCNT + bmi show_cursor + +buffer_character: + sta line_buffer,x + jsr col64_putbyte + inc BUFCNT + bne show_cursor + +return_key_hit: + jsr print_space + lda #EOL + ldx BUFCNT + sta line_buffer,x + inc BUFCNT + jsr col64_putbyte + bne get_next_byte ; col64_putbyte always clears Z flag! + +;;clear_key_hit: +; jsr clear_screen ; if we implemented it... +;; lda #$00 +;; sta line_buffer_index +;; sta BUFCNT +;; beq get_line + +backs_key_hit: + jsr print_space + lda BUFCNT + beq backs_key_done + dec COLCRS + lda COLCRS + clc + adc #$01 + cmp LMARGN + bne backs_same_line + lda RMARGN + sta COLCRS + dec ROWCRS + +backs_same_line: + dec BUFCNT + +backs_key_done: + jmp show_cursor + +; ---------------------------------------------------------------------------- +; Print a space or inverse space character at the current cursor position. +; Does not update the cursor position. + +print_inv_space: + lda #INVERTED_MASK + byte $2C + +print_space: + lda #$00 + sta inverse_mask + lda #$00 + sta TMPCHR + jmp render_glyph + +; ---------------------------------------------------------------------------- +; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine +; (call by pushing address-minus-one then doing an RTS) + +get_keystroke: + lda k_dev_get_hi + pha + lda k_dev_get_lo + pha + ;rts ; fall through to return_success + + +; ---------------------------------------------------------------------------- +; Unimplemented CIO callbacks here. Also various other routines jump here +; to return success to the caller. + +col64_close: +return_success: + ldy #$01 + rts + +; ---------------------------------------------------------------------------- +; CIO OPEN command callback + +col64_open: + jsr init_graphics_8 + lda #$00 + sta ROWCRS + sta COLCRS + sta BUFCNT + sta LMARGN + lda #DEFAULT_RMARGN + sta RMARGN + rts + +; ---------------------------------------------------------------------------- +; CIO PUT BYTE command callback +; The byte to put is passed to us in the accumulator. + +col64_putbyte: + ; EOL (decimal 155)? + cmp #EOL +;;; bne check_clear + bne regular_char + lda RMARGN + sta COLCRS + jmp skip_write + +;;;check_clear: +;;; ; save memory by not including clear_screen +;;; ; (also, this lets us print the } character) +;;; ; Clear (decimal 125)? +;;; cmp #$7D +;;; bne regular_char +;;; jmp clear_screen +;;; .endif +;;; + +; See if this is an inverse video char (code >= 128) +regular_char: + tax + bpl not_inverse + lda #INVERTED_MASK + .byte $2C ; aka BIT abs, skip the LDA +not_inverse: + lda #$00 + sta inverse_mask + + txa + and #$7F + sec + sbc #$20 ; subtract $20 because we only handle codes $20 to $7F + bcs not_low_ascii + jmp return_success ; ignore any chr codes $00-$1F or $80-$9F + +not_low_ascii: + sta TMPCHR + + lda DINDEX ; OS stores current graphics mode here + cmp #$08 + beq graphics_ok + ; If we're not in GRAPHICS 8 mode, reinitialize ourselves + jsr col64_open + +graphics_ok: + jsr render_glyph + +skip_write: + ; Move the cursor 1 space to the right. This will + ; advance us to the next line if we're at the margin, + ; and scroll the screen if needed + jsr advance_cursor + +; Could implement SSFLAG logic here +;check_ssflag: + ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla + ; any time the user presses ctrl-1 + ;lda SSFLAG + ;bne check_ssflag + jmp return_success + +; ---------------------------------------------------------------------------- +; Call the routines that actually print the character. +; render_glyph prints the character in TMPCHR at the current +; COLCRS and ROWCRS, and does NOT advance the cursor. +; TMPCHR should already have bit 7 stripped; render_glyph will +; use inverse_mask, so the caller should have set that up as well. + +; Note: The 4 subroutines were only ever called from render_glyph, +; so to save a tiny bit of time and space, they're now inline code. + +render_glyph: + ;jsr setup_mask + ;jsr setup_screen_ptr + ;jsr setup_font_index + ;jmp write_font_data + +; ---------------------------------------------------------------------------- +; mask is used to avoid overwriting pixels outside the character cell +; we're currently writing. Since 5 pixel wide cells don't align on byte +; boundaries in screen RAM, we have to read/modify/write 2 bytes, and +; the mask also has to be 2 bytes wide. +; Also we set up shift_amount here. + +setup_mask: + lda COLCRS + and #$07 + tax + lda mask_lo_tab,x + sta mask_lo + lda mask_hi_tab,x + sta mask_hi + lda shift_amount_tab,x + sta shift_amount + ;rts + + +; ---------------------------------------------------------------------------- +; Make (screen_ptr_lo) point to the first byte of screen RAM on the top line +; of the current char cell. Assumes COLCRS/ROWCRS are never out of range! +setup_screen_ptr: + ; first the row... table lookup quicker than mult by 240 + ldx ROWCRS ; +3 = 3 + clc ; +2 = 5 + lda SAVMSC ; +3 = 8 + adc line_addr_tab_lo,x ; +4 = 12 + sta screen_ptr_lo ; +3 = 15 + lda SAVMSC+1 ; +3 = 18 + adc line_addr_tab_hi,x ; +4 = 22 + sta screen_ptr_hi ; +3 = 25 + + ; now do the column. column_byte_tab is only a half-table, so do lookup + ; on bits 0-4 of COLCRS, then add 20 decimal if bit 5 of COLCRS was set. + lda COLCRS + tay + and #$1F + tax + lda column_byte_tab,x + cpy #$20 + bcc ssp_noadd + adc #$13 ; +1 because C set = 20 dec + +ssp_noadd: + clc + adc screen_ptr_lo + sta screen_ptr_lo + lda #0 + adc screen_ptr_hi + sta screen_ptr_hi + + ;rts + +; ---------------------------------------------------------------------------- +; Set up font_index to point to the font_data bitmap for the character in +; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the +; bitmap is in the upper or lower 4 bits of the bytes pointed to. + +; Calculation is: +; lo_nybble_flag = (TMPCHR & 1) ? $FF : $00; +; font_index = (TMPCHR >> 1) * 5; + +setup_font_index: + lda #$00 + sta lo_nybble_flag + lda TMPCHR + lsr ; a = (TMPCHR >> 1) + tay ; y = a + bcc font_hi_nybble + dec lo_nybble_flag ; = $FF + +font_hi_nybble: + clc + asl ; a *= 2 + asl ; a *= 2 + sta font_index + tya + adc font_index + sta font_index + + ; rts + + +; ---------------------------------------------------------------------------- +; True descender support: we've got a hard-coded list of 5 characters +; (g j p q y) that have them. All the descender graphics are stored in the +; bottom nybble of the last glyph in the font, which means we can only have +; 5 characters that have descenders. +; TODO: tighten up this code some (faster/smaller) + + lda TMPCHR + ldx #$FF + + cmp #'g-$20 + bne chk_j + ldx #DESCENDERS-1 +chk_j: + cmp #'j-$20 + bne chk_p + ldx #DESCENDERS +chk_p: + cmp #'p-$20 + bne chk_q + ldx #DESCENDERS+1 +chk_q: + cmp #'q-$20 + bne chk_y + ldx #DESCENDERS+2 +chk_y: + cmp #'y-$20 + bne not_y + ldx #DESCENDERS+3 + +not_y: + stx descender + +; ---------------------------------------------------------------------------- +; When write_font_data is called, all this stuff must be set up: +; - font_index is the 1-byte index into font_data where the current glyph is +; - lo_nybble_flag is 0 for high nybble of glyph data, $FF for low +; - mask_lo/hi is our 16-bit pixel mask (1's are "leave original data") +; - shift_amount is # of times to shift glyph data right +; - screen_ptr_lo/hi points to the 1st byte on the top line +; - inverse_mask is 0 for normal or INVERTED_MASK for inverse +; - descender is the offset *minus one* of the byte holding the bottom 4 +; pixels in the 4x6 character. Most of the time this will be $FF, +; AKA the the offset from font_data of the first byte of the space glyph +; (minus one), which has 0000 in its top nybble. The rest of the time, +; the descenders are taken from the bottom nybble of the last character +; glyph (which would be the unprintable code $7F). The logic that does +; the descenders is hard-coded to use the top nybble for $FF and the +; bottom nybble for anything else. + +; Loop 5 times, each time thru the loop: +; - extract 4-bit glyph data, store in glyph_data_lo +; - apply inverse_mask +; - shift right shift_amount times +; ...write data... +; - add 40 to 16-bit screen_ptr_lo/hi (to get to next line) +; ...then one more loop with font_index and lo_nybble_flag set +; to a byte in the space glyph, to handle the bottom row (which +; is always 0 for normal or all 1's for inverse) + +write_font_data: + ldx #$05 ; outer loop counter, aye + +wfont_line_loop: + lda #$00 + sta glyph_data_hi + + ldy font_index + lda font_data,y ; note: entire font must fit in one page! + + bit lo_nybble_flag + beq use_hi_nybble + + asl ; the pixels we want are in the low nybble of the font data byte. + asl ; shift them up to the top nybble + asl + asl + +use_hi_nybble: ; 4-bit glyph data now in hi nybble + and #$F0 + eor inverse_mask + sta glyph_data_lo + + ldy shift_amount + beq wfont_no_shift + +wfont_shift_loop: ; right-shift 16-bit glyph data shift_amount times + lsr glyph_data_lo + ror glyph_data_hi + dey + bne wfont_shift_loop + +wfont_no_shift: ; Y always zero when we get here + lda mask_lo + and (screen_ptr_lo),y + ora glyph_data_lo + sta (screen_ptr_lo),y + + lda mask_hi + beq wfont_skip_hi ; don't bother with 2nd screen byte if we don't need to + iny + and (screen_ptr_lo),y + ora glyph_data_hi + sta (screen_ptr_lo),y + +wfont_skip_hi: + dex + bmi wfont_done + bne wfont_not_bottom + + ;stx font_index + ;stx lo_nybble_flag + +; X always 0 here: for last line, use the descender (if there's no +; descender for this char, that's $FF. font_index will get inc'ed, +; meaning non-decender chars use the first byte of the space glyph +; as their "descender") + lda descender + sta font_index + cmp #$FF + beq wfont_not_bottom + sta lo_nybble_flag + +wfont_not_bottom: + lda #$28 ; add 40 bytes to point to next line of screen RAM + clc + adc screen_ptr_lo + sta screen_ptr_lo + bcc wfont_noinc + inc screen_ptr_hi + +wfont_noinc: + inc font_index + bne wfont_line_loop ; branch always + +wfont_done: + rts + +; ---------------------------------------------------------------------------- +; Not the fastest scroller in the west... TODO: make faster :) + +; lda_operand points to line N (minus one byte) +; sta_operand points to line N+1 (minus one byte) +; Y ranges 240 to 1 in the loop, hence the -1 byte +; CAUTION: Self-modifying code! Proceed with caution. + +; This version gives us overall driver speed almost 20% faster +; than the original scroll_screen (last commented-out one below) +; Also just scrolling 250 times is slightly faster than COL80 +; (1505 jiffies; setting CRITIC saves 48 jiffies) +; (makes it 17% the speed of the OS E: driver, where COL80 is 15%) +; Note that E80 is slightly over twice as fast at this as the OS! + +; Note about performance where scrolling is *not* concerned: +; Printing 914 non-control characters on a freshly-cleared screen: +; OS E: - 172 jiffies (subtract 12 = 160 jiffies if cursor disabled) +; E80 - 168 jiffies (about same as OS E:) +; COL80 - 116 jiffies (yes, it's fastest!) +; CON64 from SDX 4.41 - 227 jiffies first time I tried, crashed next time! +; COL64 - 142 jiffies (still faster than OS E:) + +scroll_screen: +; lda SDMCTL +; pha +; lda #0 +; sta SDMCTL + +; lda CRITIC +; pha +; lda #1 +; sta CRITIC + + lda SAVMSC + sec + sbc #1 + sta lda_operand + lda SAVMSC+1 + sbc #0 + sta lda_operand+1 + ldx #LAST_ROW + +scroll_line_loop: + ldy #$F0 + + lda lda_operand+1 + sta sta_operand+1 + lda lda_operand + sta sta_operand + clc + adc #$F0 + sta lda_operand + bcc ss_noinc + inc lda_operand+1 +ss_noinc: + +scroll_byte_loop: +lda_operand = *+1 + lda 0,y +sta_operand = *+1 + sta 0,y + dey + bne scroll_byte_loop + dex + bne scroll_line_loop + +scroll_blank: + lda lda_operand + sta sta2_operand + lda lda_operand+1 + sta sta2_operand+1 + lda #0 + ldy #$F0 +sblank_loop: +sta2_operand = *+1 + sta 0,y + dey + bne sblank_loop + +; pla +; sta SDMCTL +; pla +; sta CRITIC + rts + +;; This version is faster and fully functional +;; (overall driver speed is 10% faster than with the +;; one below) +; glyph_data_lo points to line N (minus one byte) +; screen_ptr_lo points to line N+1 (minus one byte) +; Y ranges 240 to 1 in the loop, hence the -1 byte + +;;scroll_screen: +;; lda SAVMSC +;; sec +;; sbc #1 +;; sta screen_ptr_lo +;; lda SAVMSC+1 +;; sbc #0 +;; sta screen_ptr_hi +;; ldx #LAST_ROW +;; +;;scroll_line_loop: +;; ldy #$F0 +;; +;; lda screen_ptr_hi +;; sta glyph_data_hi +;; lda screen_ptr_lo +;; sta glyph_data_lo +;; clc +;; adc #$F0 +;; sta screen_ptr_lo +;; bcc ss_noinc +;; inc screen_ptr_hi +;;ss_noinc: +;; +;;scroll_byte_loop: +;; lda (screen_ptr_lo),y +;; sta (glyph_data_lo),y +;; dey +;; bne scroll_byte_loop +;; dex +;; bne scroll_line_loop +;; +;;scroll_blank: +;; lda #0 +;; ldy #$F0 +;;sblank_loop: +;; sta (screen_ptr_lo),y +;; dey +;; bne sblank_loop +;; +;; rts + +; Clock cycle timings: +; 1792080 CPU cycles per second (or is it 1789773?) +; 29868 per jiffy on NTSC (1/60 sec) +; DL = 174 bytes @ 1 cycle each +; Screen RAM = 7680 bytes @ 1 ea +; Refresh = 262 * 9 = 2358 +; so ANTIC steals 10212 (34.2%) cycles, leaves 19656 (65.8%) +; Of that time, the OS steals some doing VBLANK processing. +; It may be that I can set CRITIC here and get a little of +; that back (depends on what, if anything, that does to +; the RS232 driver and/or custom keybuffer stuff in FujiChat). + +; Now if I could actually do a 100% unrolled scroller, simply +; LDA blah:STA blah-1 7680 times, with NMI/VBI/ANTIC disabled, +; that would be 4+4=8 cycles times 7680 = 61440, or 3.12 frames +; (or 0.052 sec, call it 1/20 sec). Obviously can't do it that way. + +; Did some tests of overall performance (not just scrolling: print +; 24 lines of 35 chars, then 24 newlines, repeat in a loop 10x) +; Turning off ANTIC DMA seems to save 25% time. Setting CRITIC only +; saves 3% or so. Disabling IRQs/NMIs entirely is probably not an +; option. + +;; old (slower, but working) version: +;; scroll_screen: +;; lda #0 ; +2 = 2 +;; sta COLCRS ; +3 = 5 +;; sta ROWCRS ; +3 = 8 +;; jsr setup_screen_ptr ; +6 = 14, +54 = 68 +;; +;; scroll_line_loop: +;; lda screen_ptr_lo ; +3 = 3 +;; sta glyph_data_lo ; +3 = 6 +;; lda screen_ptr_hi ; +3 = 12 +;; sta glyph_data_hi ; +3 = 15 +;; ldx ROWCRS ; +3 = 18 +;; cpx #LAST_ROW ; +2 = 20 +;; beq scroll_blank ; +2 = 22 (+1 more last time thru) +;; inx ; +2 = 24 +;; stx ROWCRS ; +3 = 27 +;; jsr setup_screen_ptr ; +6+54 = 87 +;; ldy #0 ; +2 = 89 +;; ; times 31 is 2759, +1 = 2760 +;; +;; scroll_byte_loop: +;; lda (screen_ptr_lo),y ; +5 = 5 +;; sta (glyph_data_lo),y ; +6 = 11 +;; iny ; +2 = 13 +;; cpy #$F0 ; +2 = 15 +;; bne scroll_byte_loop ; +3 = 18 (-1 last time thru) +;; ; ...times 31 times 240 - 1 = 133919 (!) +;; beq scroll_line_loop ; +3*31-1 (92) +;; +;; scroll_blank: +;; jsr setup_screen_ptr ; +6+54 = 60 +;; ldy #0 ; +2 = 62 +;; tya ; +2 = 64 +;; sblank_loop: +;; sta (screen_ptr_lo),y ; +6 = 6 +;; iny ; +2 = 8 +;; cpy #$F0 ; +2 = 10 +;; bne sblank_loop ; +3 = 13 (-1 last time) +;; ; times 240, minus 1 = 3119 +;; +;; rts ; +6 +;; +;; Total routine time is 68 + 2760 + 133919 + 92 + 64 + 3119 + 6 = 140028 +;; Divide by free cyc/frame: 140028/19656 = 7.12 frames, or 0.11 sec, +;; not counting VBLANK overhead. 95% of the time is of course in the +;; inner loop. Every cycle saved in the inner loop is worth about +;; 5% of the runtime! So switching from incrementing to decrementing +;; Y will save 10% of the time (from not having the CPY). Using self- +;; modifying code for the lda/sta saves 2 more cycles (10% more), but +;; adds a small bit of overhead in the outer loop. +;; The scroll_blank loop is only 2.2% of the total time. Every cycle +;; shaved off its loop is worth only 1/3 of a percent of the total +;; time (switching to dey is worth 2/3 of 1%). +;; Replace jsr setup_screen_ptr in scroll_line_loop with loading from +;; the tables directly will save approx. 35 cycles per outer loop, +;; or only about 0.8%. +;; So total savings is 20% + 0.6% + 0.8% = 21.4%, meaning real time +;; drops to approx 0.085 sec, or approx 5.5 NTSC frames (another way +;; to look at it: 11.75 scrolled lines/sec instead of the original 9) +;; Yet another way: 2 1/3 seconds to scroll the whole screen, vs +;; the original 3 1/2. Still abysmal. + +;; One possibility would be to borrow a page from the ACE-80 book and +;; update LMSes within the DL. This would bloat the display list by +;; 64 bytes (not so bad). We'd basically treat screen RAM as a circular +;; buffer of 32 lines. Every scroll, update the LMS operands to point +;; to the next line-buffer, and whichever buffer is the last visible +;; line needs to be blanked. Got to see how much code this will add +;; (possibly the routine that does this might not be longer than the +;; scroll_screen I've been using). ACE-80 (or anyway E80) uses way +;; more screen RAM than it looks like it needs, plus DLIs. + +; ---------------------------------------------------------------------------- +; Move the cursor one space to the right (to the next line if at the margin, +; and scroll screen if on the last row) + +advance_cursor: + inc COLCRS + lda RMARGN + cmp COLCRS + bcs same_line + lda LMARGN + sta COLCRS + lda ROWCRS + cmp #LAST_ROW + bcc no_scroll + jsr scroll_screen + ; Move to last row after scrolling + lda #LAST_ROW-1 + sta ROWCRS + +no_scroll: + inc ROWCRS + +same_line: + rts + +END_ADDR_1 = *-1 + + +; ---------------------------------------------------------------------------- +; Initialization. If we don't want the handler to survive a warmstart, we +; can load this bit into e.g. the cassette buffer (throw away after running) + +START_ADDRESS_2 = CASBUF + +; XEX segment header for throwaway init code + rorg START_ADDRESS_2-4 + word START_ADDRESS_2 + word END_ADDR_2 + +col64_init: + ldy #$00 + +next_hatab_slot: + lda HATABS,y + beq register_x_handler + iny + iny + iny + cpy #$20 + bcc next_hatab_slot + jmp return_success + +register_x_handler: + lda #$58 + sta HATABS,y + lda #col64_vector_tab + iny + sta HATABS,y + jmp return_success + +main_entry_point: + jsr col64_init + lda #$0C + sta ICCOM + ldx #$00 + jsr CIOV + lda #$58 + sta font_index + lda #$03 + sta ICCOM + lda #font_index + sta ICBAL + lda #$00 + sta ICBAH + ldx #$00 + jsr CIOV + ldy #$07 + lda #col64_vector_tab + iny + sta HATABS,y +no_e_handler: + lda #START_ADDRESS_1 + sta MEMTOP+1 + jmp return_success + +END_ADDR_2 = *-1 + +; XEX segment (run address) + word INITAD + word INITAD+1 + word main_entry_point + +; That's all, folks... + +; Rest of file is me rambling & meandering, ignore or not as you choose + +; Possible improvements, some of which may apply to this driver only, +; some of which may apply to a (to be written) 40-column renderer. +; Redb3ard has designed really nice 8x8 normal, bold, italic fonts, +; including a bunch of Unicode normal characters... the 40-column +; driver would include UTF-8 support. Of course there's not enough +; RAM for an IRC client, TCP/IP stack, screen/DL memory, driver, +; UTF-8 tables, and 3 or 4 fonts... will have to wait until after +; the 1.0 FujiChat release (my roadmap for 1.0 is that everything +; needs to work on a 48K unmodded 800; 2.0 will have new features +; that may only work on an XL or even require 130XE banks, though +; it will still be as functional as 1.0, on an 800). + +; True descenders and 5-bit-wide characters. + +; For descenders, could simply leave the top row of pixels blank on +; the screen, and draw the 5 rows of character in the bottom 5 of +; the 6-scanline block. They'd possibly touch the character on the +; next line... + +; 5-bit-wide characters should be used sparingly: only M W m w T +; and maybe Y V v # need them. The "extra" bit could go on the left, +; and just be a copy of the rightmost bit, since these characters +; are symmetrical... but these would often touch the character on +; the left. Capital letters, it's less of a big deal in normal English +; text, since a capital letter should be preceded by a space (or at +; least punctuation), and it won't touch the character on the right +; unless it's another 5-bit-wide one (few words in English are going +; to have that problem; maybe the name AMY in all caps). Unfortunately +; I can't think of a good way to encode the bits of information that +; say a character needs the extra pixel (or a descender either) other +; than a hard-coded set of compares against specific char codes, or +; else a loop over a table of them. Either way there's a loss of +; performance: most characters will fail all the compares... +; It'd be possible to do a 5x5 font, or even 5x6, but 5 bits wide +; means we can't pack the pixel data 2 rows per byte (so the +; font won't fit in a page any more, plus we have to use (zp),y +; or something to access it...) + +; Multiple font support. Since it's an IRC-specific driver, could just +; have _putbyte directly interpret the IRC protocol formatting codes, +; render e.g. bold as inverse, italic as underline if I implement it, +; or else do up a separate italic font (if it's possible to make one +; look good in 4x5). _putbyte could at least strip out the codes it +; can't render (e.g. color). + +; I've thought of doing underline (either a separate mode, or instead +; of inverse video), but a lot of the glyphs will look like crap with +; the underline, because there's no room for spacing: the underline +; will touch the bottom pixels of most characters (and overwrite the +; descenders if we add true descender support...) + +; Obviously, making it a fully-functional E: replacement would be nice. +; I'm not doing this because I'm only wanting to use the driver for +; text-only cc65 programs (specifically FujiChat), though possibly +; I'll come back to col64 and do a proper version later. + +; Also nice: user-adjustable number of rows. Most peoples' monitors can +; display something above 200 scanlines (particularly if they're in PAL +; countries). As-is, we're using 192 scanlines to get 32 rows (of 6 lines +; each). Most people could easily display 34 rows (204 scanlines), and +; not a few could display 35 (210), particularly if the blanking +; instructions at the start of the display list are user-adjustable too +; (to move the picture up or down). Memory usage for video RAM would +; grow by 240 byte per row of characters, and of course we'd need code +; to set up the custom display list (which would be longer than a +; normal one for GR.8). Probably would put a limit of 36 or 40 rows +; since the various tables are fixed-size... + +; If there were RAM enough for it, or if we decide to use XE extra +; banks (or XL/XE under-OS RAM), could have _putbyte also store +; every output character in a buffer, for FujiChat to use as +; scrollback/log buffer (or any other program to use as it sees +; fit, of course). + +; User-loadable font isn't a bad idea: the init code can look for a +; file D:COL64.FNT and load it into font_data if found. + +; Could implement standard ASCII backspace/tab/linefeed/CR/etc codes, +; using low ASCII codes. This would be suitable for a telnet or terminal +; client (not needed for IRC) + +; I really would like to do auto-relocation. Program could load itself +; wherever, and relocate itself (using a table of offsets, for absolute +; addresses within the program) to either MEMLO or MEMTOP. This would +; mean more init code only. + +; It'd be nice to speed up scrolling. One dumb trick would be to use +; self-modifying code: instead of (zp),y addressing, use abs,y +; in the inner loop, and the outer loop modifies the operands in +; the inner. Would mean the code can't be burned to ROM, but who +; was planning to do that anyway? Also simply moving more than one +; chunk per outer-loop iteration would be a small speedup, and so +; would moving 256 bytes per, instead of 240. +; Since the inner loop does lda (zp),y [5+cyc] and sta (zp),y [6cyc] +; 7440 times, replacing them with lda abs,y [4+cyc] and sta abs,y +; [5cyc] should save 7440*2 = almost 15K cycles. +; which may not be noticeable... Unrolling the loop is even less of a +; gain: the outer loop only runs 32 times. Could set CRITIC during the +; move (not sure that helps much). No matter how you slice it, +; moving 8K on a 6502 is *slow*. + +; One slightly cool idea would be to do a proper OPEN of channel #6 +; to S:, like the BASIC GR. command does, instead of the "shortcut" +; using ZIOCB and calling the S: open routine directly. Doing this +; would allow PLOT, DRAWTO, and XIO 18 (fill). diff --git a/src/col64/col64_ext.inc b/src/col64/col64_ext.inc new file mode 100644 index 0000000..81e7660 --- /dev/null +++ b/src/col64/col64_ext.inc @@ -0,0 +1,48 @@ + byte $04, $04, $04, $00, $04 ; [0] 32,33 ,! + byte $AA, $AF, $0A, $0F, $0A ; [5] 34,35 ",# + byte $70, $A9, $62, $54, $E9 ; [10] 36,37 $,% + byte $42, $A2, $44, $A0, $D0 ; [15] 38,39 &,' + byte $24, $42, $42, $42, $24 ; [20] 40,41 (,) + byte $A4, $44, $EE, $44, $A4 ; [25] 42,43 *,+ + byte $00, $00, $0F, $20, $40 ; [30] 44,45 ,,- + byte $02, $02, $04, $08, $48 ; [35] 46,47 .,/ + byte $64, $9C, $B4, $D4, $6E ; [40] 48,49 0,1 + byte $6E, $91, $26, $41, $FE ; [45] 50,51 2,3 + byte $2F, $68, $AE, $F1, $2E ; [50] 52,53 4,5 + byte $7F, $81, $E2, $94, $64 ; [55] 54,55 6,7 + byte $66, $99, $67, $91, $6E ; [60] 56,57 8,9 + byte $00, $42, $00, $02, $44 ; [65] 58,59 :,; + byte $20, $4F, $80, $4F, $20 ; [70] 60,61 <,= + byte $87, $49, $22, $40, $82 ; [75] 62,63 >,? + byte $66, $B9, $BF, $89, $69 ; [80] 64,65 @,A + byte $E6, $99, $E8, $99, $E6 ; [85] 66,67 B,C + byte $EF, $98, $9E, $98, $EF ; [90] 68,69 D,E + byte $F7, $88, $EB, $89, $86 ; [95] 70,71 F,G + byte $9E, $94, $F4, $94, $9E ; [100] 72,73 H,I + byte $39, $1A, $1C, $9A, $69 ; [105] 74,75 J,K + byte $8A, $8F, $8D, $89, $F9 ; [110] 76,77 L,M + byte $96, $D9, $B9, $99, $96 ; [115] 78,79 N,O + byte $E6, $99, $E9, $8A, $85 ; [120] 80,81 P,Q + byte $E7, $98, $E6, $A1, $9E ; [125] 82,83 R,S + byte $F9, $49, $49, $49, $46 ; [130] 84,85 T,U + byte $99, $99, $9D, $AF, $4A ; [135] 86,87 V,W + byte $99, $99, $66, $92, $94 ; [140] 88,89 X,Y + byte $F6, $24, $44, $84, $F6 ; [145] 90,91 Z,[ + byte $86, $82, $42, $22, $26 ; [150] 92,93 \,] + byte $40, $A0, $00, $00, $0F ; [155] 94,95 ^,_ + byte $40, $47, $29, $0B, $05 ; [160] 96,97 `,a + byte $80, $87, $E8, $98, $E7 ; [165] 98,99 b,c + byte $10, $16, $79, $9E, $77 ; [170] 100,101 d,e + byte $60, $47, $E9, $47, $41 ; [175] 102,103 f,g + byte $84, $80, $EC, $94, $9E ; [180] 104,105 h,i + byte $28, $0A, $6C, $2A, $29 ; [185] 106,107 j,k + byte $C0, $4A, $4F, $4D, $E9 ; [190] 108,109 l,m + byte $00, $E6, $99, $99, $96 ; [195] 110,111 n,o + byte $00, $E7, $99, $E7, $81 ; [200] 112,113 p,q + byte $00, $A7, $DC, $83, $8E ; [205] 114,115 r,s + byte $40, $E9, $49, $49, $26 ; [210] 116,117 t,u + byte $00, $99, $9D, $AF, $4A ; [215] 118,119 v,w + byte $00, $99, $69, $66, $92 ; [220] 120,121 x,y + byte $06, $F4, $28, $44, $F6 ; [225] 122,123 z,{ + byte $4C, $44, $42, $44, $4C ; [230] 124,125 |,} + byte $06, $5C, $A8, $01, $0C ; [235] 126,127 ~, diff --git a/src/col64/cruft/col64.dasm b/src/col64/cruft/col64.dasm new file mode 100644 index 0000000..aca1259 --- /dev/null +++ b/src/col64/cruft/col64.dasm @@ -0,0 +1,1194 @@ + +; ---------------------------------------------------------------------------- +; 64x32 software text driver +; Uses 4x5 font in 5x6 character cells +; Based on disassembled COL80 driver + +; This driver is missing quite a few things a full E: driver should have: + +; - Does not work with BASIC or any other cart! Though if START_ADDRESS_1 +; is changed to $7Cxx, a BASIC-able version could be assembled + +; - No support for cursor controls, insert/delete, or even clear screen +; (instead the control-codes are printed as normal characters, if they're +; above 31 decimal). This is a feature: our intended application is an +; IRC client, where ASCII codes 125 and 126 represent } and ~ chars, +; not clear-screen and backspace. + +; - Backspace key is supported during get-byte, but printing a backspace +; with put-byte prints a tilde instead. Again, a feature. + +; - No support for low ASCII at all: any attempt to input or print a character +; in the range 0-31 decimal is just ignored (this includes the arrow keys). +; This is done to keep the font size at 96 characters, so it'll fit in a +; page. Also IRC doesn't use low-ASCII. + +; - Does not attempt to survive a warmstart + +; - Will fail disastrously if an application sets COLCRS/ROWCRS to any +; out-of-range values + +; - Only displays the cursor during get-byte operations + +; On the other hand, this driver is tiny (font is 240 bytes, code 718, not +; counting 100 bytes of throwaway init code in the tape buffer), and plays +; nice with cc65's stdio support (though NOT conio, don't even go there) + +; Theory of operation: + +; This is an Atari OS-compliant device driver. On load, the init routine +; replaces the E: entry in HATABS with a pointer to our vector table, +; col64_vector_tab. + +; We implement the CIO commands OPEN, CLOSE, GETBYTE, and PUTBYTE. The +; GET-STATUS and SPECIAL commands are not implemented, and the CLOSE +; command simply returns success (it doesn't need to do anything else). + +; When a channel is OPENed to our new E: device, the col64_open routine +; calls part of the OS's S: handler to switch to GRAPHICS 8 (320x192 mono) +; mode. + +; When the CIO PUT-BYTES or PUT-RECORD calls are made on our channel, CIO +; calls our PUTBYTE routine (col64_putbyte) as needed to write (print) +; characters to the screen. col64_putbyte keeps track of the current +; cursor position (using COLCRS and ROWCRS), and either renders a glyph +; at the current location, or (when the EOL character $9B is printed) +; moves the cursor to the beginning of the next line, scrolling the +; display RAM if necessary. + +; When the CIO GET-BYTES or GET-RECORD calls are made on our channel, CIO +; calls our GETBYTE routine (col64_getbyte). This routine maintains its +; own buffer of user-input characters. When first called (or any call when +; the buffer is empty), col64_getbyte reads a complete line of input using +; the OS's K: handler, echoing typed characters to the screen using our +; own col64_putbyte. Only the backspace key is supported for editing. Once +; the user presses Return, the first byte in the buffer is returned to +; the caller. On subsequent calls, characters are returned from the buffer +; until the buffer is empty. At this point, the next call to col64_getbyte +; will result in a new line of input being read. + +; col64_putbyte calls render_glyph to draw a character in display RAM. +; The font consists of 96 characters (low ASCII not supported), each 4 pixels +; wide and 5 tall [*]. These are rendered into 5x6 character cells, with the +; extra pixels being left blank to provide padding between characters. +; Since 5 pixel wide cells don't line up evenly on display RAM byte +; boundaries, render_glyph has to shift each 4-pixel line of glyph +; data the appropriate number of times, and combine the result with the +; rest of each screen byte (that portion that's outside of the 5-pixel +; cell we're currently writing to). Surprisingly, this is accomplished +; slightly faster than the standard OS E: driver prints a single character. +; (unfortunately, scrolling the screen is *much* slower than the OS E: +; driver's scrolling...) + +; [*] ...except the lowercase q j p q y, which have true descenders. The +; glyphs for these are still 4x5, but the 6th row of pixels for all 5 +; get stored together in the last glyph in the set (ASCII code $7F, +; which should be considered an unprintable character). + + processor 6502 ; DASM-specific + +; ---------------------------------------------------------------------------- + include equates.inc + +; "backdoor" vectors into the S: and K: ROM drivers. These are addres-minus-1, +; called by PHA/PHA/RTS. +s_dev_open_lo = $E410 ; (not named in OS sources) +s_dev_open_hi = $E411 ; "" +k_dev_get_lo = $E424 ; "" +k_dev_get_hi = $E425 ; "" + +; ---------------------------------------------------------------------------- +; Constants + +LAST_ROW = $1F ; last valid cursor row on screen, 31 decimal (we count from 0) +EOL = $9B ; Atari ASCII end-of-line (aka the Return key) +INVERTED_MASK = $F8 ; stored in inverse_mask when rendering in inverse video + +; ---------------------------------------------------------------------------- +; Defaults + +DEFAULT_TEXT_COLOR = $00 +DEFAULT_BG_COLOR = $C8 +DEFAULT_RMARGN = $3F + +; ---------------------------------------------------------------------------- +; ZP storage +; Reuse some of the E:/S: devices' storage +; These all get recalculated on col64_putbyte entry, +; so it's probably OK to mix with GR.8 PLOT/DRAWTO stuff + + seg.u "data" + org $A0 ; (used to be $90 aka OLDROW) +mask_lo ds 1 ; Holds the 16-bit mask, used by render_glyph +mask_hi ds 1 +screen_ptr_lo ds 1 ; Pointer to display RAM: render_glyph and scroll_screen +screen_ptr_hi ds 1 ; both use this. +font_index ds 1 ; index into font: TMPCHR * 5 +shift_amount ds 1 ; How many times to right-shift during render_glyph + + ;org $63 ; aka LOGCOL +glyph_data_lo ds 1 ; render_glyph stores (possibly shifted) glyph data +glyph_data_hi ds 1 ; here. Also a 2nd display RAM pointer in scroll_screen +lo_nybble_flag ds 1 ; non-zero if glyph data in top 4 bits of font + + ;org $68 ; aka SAVADR +inverse_mask ds 1 ; 0 for normal video, INVERTED_MASK for inverse +line_buffer_index ds 1 ; used by col64_getbyte +descender ds 1 ; offset-1 of true descender byte, into font_data + +; We also use several other ZP locations, normally used by the OS E: driver: +; COLCRS ROWCRS TMPCHR BUFCNT RMARGN SAVMSC are used for the same purpose as +; the OS uses them for. + +; ---------------------------------------------------------------------------- +; Non-ZP storage (cassette buffer for now) + + org CASBUF +line_buffer ds $80 + + seg "code" +; ---------------------------------------------------------------------------- +; XEX segment header + +;START_ADDRESS_1 = $9C78 +START_ADDRESS_1 = $9C00 ; should end at $A036; subtract 2K to use with BASIC + org START_ADDRESS_1-6 + + word $FFFF + word START_ADDRESS_1 + word END_ADDR_1 + +; ---------------------------------------------------------------------------- +; Font data should be aligned on a page boundary +; (for speed; still works unaligned). Each 5 bytes stores 2 glyphs +; side-by-side. When rendering into 5x6 cells, the bottom line and +; the left column are set to all 0 (or all 1 for inverse video) for padding, +; so the glyphs can take up the entire 4x5 space. +; Only character codes 32 through 127 are supported; this is 96 +; characters. At 2 glyphs per 5 bytes, that's 96/2*5=240 bytes, +; which means the whole font fits into one page and can be +; accessed with X or Y indexed mode rather than (indirect),Y. + +font_data: + ;include font4x5.inc + include col64_ext.inc + +DESCENDERS = $EB ; g j p q y descender bytes, offset from font_data + +; ---------------------------------------------------------------------------- +; Mask tables, used by setup_mask. Indexed by (COLCRS % 8), since they +; would repeat every 8 bytes anyway. Each mask is 16 bits, and contains +; a 1 for each pixel in screen RAM that we *don't* want to change when +; writing pixels (because they're not part of the current character cell), +; but see below... + +mask_lo_tab: + byte $07, $F8, $C1, $FE, $F0, $83, $FC, $E0 + +; In mask_hi_tab, $00 is never a valid mask, while $FF means "don't touch any +; bits in 2nd byte". As a minor optimization, $00 appears in the table in +; place of $FF. This allows us to just test the Z flag after loading the mask +; hi byte, instead of needing to compare against $FF. +; (Actually, on further thought, the $FF's could have been left in, and the +; test could have been made on the N flag: any hi mask with bit 7 set won't have +; any other bits clear. *Shrug*) + +mask_hi_tab: + byte $00, $3F, $00, $0F, $7F, $00, $1F, $00 + +; ---------------------------------------------------------------------------- +; Indexed by COLCRS%8, how many bits to shift the font data right +; The mask_*_tab stuff above could be calculated at runtime from this, +; the tables are only there for speed. + +shift_amount_tab: + byte $00, $05, $02, $07, $04, $01, $06, $03 + +; ---------------------------------------------------------------------------- +; Line address tables, used by setup_screen_ptr. Indexed by ROWCRS. Used by +; setup_screen_ptr + +line_addr_tab_lo: + byte $00, $f0, $e0, $d0, $c0, $b0, $a0, $90 + byte $80, $70, $60, $50, $40, $30, $20, $10 + byte $00, $f0, $e0, $d0, $c0, $b0, $a0, $90 + byte $80, $70, $60, $50, $40, $30, $20, $10 + +line_addr_tab_hi: + byte $00, $00, $01, $02, $03, $04, $05, $06 + byte $07, $08, $09, $0a, $0b, $0c, $0d, $0e + byte $0f, $0f, $10, $11, $12, $13, $14, $15 + byte $16, $17, $18, $19, $1a, $1b, $1c, $1d + +; ---------------------------------------------------------------------------- +; Byte offset within scanline, indexed by COLCRS & $1F value +; Used by setup_screen_ptr. + +column_byte_tab: + byte $00, $00, $01, $01, $02, $03, $03, $04 + byte $05, $05, $06, $06, $07, $08, $08, $09 + byte $0A, $0A, $0B, $0B, $0C, $0D, $0D, $0E + byte $0F, $0F, $10, $10, $11, $12, $12, $13 + +; Used to be indexed by COLCRS, rest of the table was: + ;byte $14, $14, $15, $15, $16, $17, $17, $18 + ;byte $19, $19, $1A, $1A, $1B, $1C, $1C, $1D + ;byte $1E, $1E, $1F, $1F, $20, $21, $21, $22 + ;byte $23, $23, $24, $24, $25, $26, $26, $27 + +; ---------------------------------------------------------------------------- +; Handler table (HATABS will point to this). +; See the HATABS and EDITRV entries in Mapping the Atari for details. + +col64_vector_tab: + word col64_open-1 ; OPEN vector + word col64_close-1 ; CLOSE vector + word col64_getbyte-1 ; GET BYTE vector + word col64_putbyte-1 ; PUT BYTE vector + word col64_close-1 ; GET STATUS vector + word col64_close-1 ; SPECIAL vector + ;jmp col64_init ; Jump to initialization code (JMP LSB/MSB) + ; (Note: the OS really only ever calls the JMP init + ; routines for handlers in ROM, this could be empty) + +; ---------------------------------------------------------------------------- +; Assembly version of GRAPHICS 8+16 command. + +init_graphics_8: + lda #$08 ; graphics mode 8 + sta ICAX2Z + lda #$0C ; R/W access + sta ICAX1Z + jsr open_s_dev + + ; Set default colors + lda #DEFAULT_BG_COLOR + sta COLOR2 + sta COLOR4 + lda #DEFAULT_TEXT_COLOR + sta COLOR1 + + ; Protect ourselves from the OS + lda #START_ADDRESS_1 + sta MEMTOP+1 + rts + +; ---------------------------------------------------------------------------- +; Call the OPEN vector for the S: device, using the ROM vector table +; at $E410. The table stores address-minus-one of each routine, which is +; meant to actually be called via the RTS instruction (standard 6502 +; technique, but confusing the first time you encounter it) + +open_s_dev: + lda s_dev_open_hi + pha + lda s_dev_open_lo + pha + rts + +; ---------------------------------------------------------------------------- +; Callback for the internal get-one-byte, used by the OS to implement the +; CIO GET RECORD and GET BYTES commands. This routine takes no arguments, +; and returns the read byte in the accumulator. + +; Internally, COL64 maintains a line buffer. Each time col64_getbyte is +; called, it returns the next character in the buffer. If the buffer's +; empty (or if the last call returned the last character), a new line +; of input is read from the user (and the first character is returned). +; This is not exactly how the OS E: device works: it reads keystrokes but +; doesn't buffer them, until Return is hit; then it reads from screen +; memory, at the current cursor line (and the line(s) before/after, +; depending on its map of logical => physical lines). We can't do that +; because we don't store character codes in screen memory... although +; we *could* support insert/delete character, delete-line, and left/right +; arrows. We don't, to save driver code size... + +; This code was borrowed from COL80, then big chunks of it were diked out +; and/or optimized. + +col64_getbyte: + lda BUFCNT + beq get_line ; See if there are bytes left in the buffer + +get_next_byte: ; Yes: return next byte from the buffer + ldx line_buffer_index + lda line_buffer,x + dec BUFCNT + inc line_buffer_index + jmp return_success + +; Buffer is empty. +; Get a line of input from the user, terminated by the Return key. +get_line: + lda #$00 + sta BUFCNT + sta line_buffer_index + +show_cursor: + jsr print_inv_space + jsr get_keystroke + +; code meant to deal with BREAK key, left out 'cause FujiChat disables BREAK +; cpy #$01 +; beq keystroke_ok +; ldy #0 +; sty line_buffer_index +; sty BUFCNT + +keystroke_ok: + cmp #$20 + bcc show_cursor ; ignore low ASCII + cmp #EOL + beq return_key_hit + +check_backs_key: + cmp #$7E + beq backs_key_hit + +;check_clear_key: ; don't bother, don't need + ; (if we did want this, it should check delete-line instead!) + ;;cmp #$7D + ;;beq clear_key_hit + +normal_key_hit: + ldx BUFCNT + bmi show_cursor + +buffer_character: + sta line_buffer,x + jsr col64_putbyte + inc BUFCNT + bne show_cursor + +return_key_hit: + jsr print_space + lda #EOL + ldx BUFCNT + sta line_buffer,x + inc BUFCNT + jsr col64_putbyte + bne get_next_byte ; col64_putbyte always clears Z flag! + +;;clear_key_hit: +; jsr clear_screen ; if we implemented it... +;; lda #$00 +;; sta line_buffer_index +;; sta BUFCNT +;; beq get_line + +backs_key_hit: + jsr print_space + lda BUFCNT + beq backs_key_done + dec COLCRS + lda COLCRS + clc + adc #$01 + cmp LMARGN + bne backs_same_line + lda RMARGN + sta COLCRS + dec ROWCRS + +backs_same_line: + dec BUFCNT + +backs_key_done: + jmp show_cursor + +; ---------------------------------------------------------------------------- +; Print a space or inverse space character at the current cursor position. +; Does not update the cursor position. + +print_inv_space: + lda #INVERTED_MASK + byte $2C + +print_space: + lda #$00 + sta inverse_mask + lda #$00 + sta TMPCHR + jmp render_glyph + +; ---------------------------------------------------------------------------- +; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine +; (call by pushing address-minus-one then doing an RTS) + +get_keystroke: + lda k_dev_get_hi + pha + lda k_dev_get_lo + pha + ;rts ; fall through to return_success + + +; ---------------------------------------------------------------------------- +; Unimplemented CIO callbacks here. Also various other routines jump here +; to return success to the caller. + +col64_close: +return_success: + ldy #$01 + rts + +; ---------------------------------------------------------------------------- +; CIO OPEN command callback + +col64_open: + jsr init_graphics_8 + lda #$00 + sta ROWCRS + sta COLCRS + sta BUFCNT + sta LMARGN + lda #DEFAULT_RMARGN + sta RMARGN + rts + +; ---------------------------------------------------------------------------- +; CIO PUT BYTE command callback +; The byte to put is passed to us in the accumulator. + +col64_putbyte: + ; EOL (decimal 155)? + cmp #EOL +;;; bne check_clear + bne regular_char + lda RMARGN + sta COLCRS + jmp skip_write + +;;;check_clear: +;;; ; save memory by not including clear_screen +;;; ; (also, this lets us print the } character) +;;; ; Clear (decimal 125)? +;;; cmp #$7D +;;; bne regular_char +;;; jmp clear_screen +;;; .endif +;;; + +; See if this is an inverse video char (code >= 128) +regular_char: + tax + bpl not_inverse + lda #INVERTED_MASK + .byte $2C ; aka BIT abs, skip the LDA +not_inverse: + lda #$00 + sta inverse_mask + + txa + and #$7F + sec + sbc #$20 ; subtract $20 because we only handle codes $20 to $7F + bcs not_low_ascii + jmp return_success ; ignore any chr codes $00-$1F or $80-$9F + +not_low_ascii: + sta TMPCHR + + lda DINDEX ; OS stores current graphics mode here + cmp #$08 + beq graphics_ok + ; If we're not in GRAPHICS 8 mode, reinitialize ourselves + jsr col64_open + +graphics_ok: + jsr render_glyph + +skip_write: + ; Move the cursor 1 space to the right. This will + ; advance us to the next line if we're at the margin, + ; and scroll the screen if needed + jsr advance_cursor + +; Could implement SSFLAG logic here +;check_ssflag: + ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla + ; any time the user presses ctrl-1 + ;lda SSFLAG + ;bne check_ssflag + jmp return_success + +; ---------------------------------------------------------------------------- +; Call the routines that actually print the character. +; render_glyph prints the character in TMPCHR at the current +; COLCRS and ROWCRS, and does NOT advance the cursor. +; TMPCHR should already have bit 7 stripped; render_glyph will +; use inverse_mask, so the caller should have set that up as well. + +; Note: The 4 subroutines were only ever called from render_glyph, +; so to save a tiny bit of time and space, they're now inline code. + +render_glyph: + ;jsr setup_mask + ;jsr setup_screen_ptr + ;jsr setup_font_index + ;jmp write_font_data + +; ---------------------------------------------------------------------------- +; mask is used to avoid overwriting pixels outside the character cell +; we're currently writing. Since 5 pixel wide cells don't align on byte +; boundaries in screen RAM, we have to read/modify/write 2 bytes, and +; the mask also has to be 2 bytes wide. +; Also we set up shift_amount here. + +setup_mask: + lda COLCRS + and #$07 + tax + lda mask_lo_tab,x + sta mask_lo + lda mask_hi_tab,x + sta mask_hi + lda shift_amount_tab,x + sta shift_amount + ;rts + + +; ---------------------------------------------------------------------------- +; Make (screen_ptr_lo) point to the first byte of screen RAM on the top line +; of the current char cell. Assumes COLCRS/ROWCRS are never out of range! +setup_screen_ptr: + ; first the row... table lookup quicker than mult by 240 + ldx ROWCRS ; +3 = 3 + clc ; +2 = 5 + lda SAVMSC ; +3 = 8 + adc line_addr_tab_lo,x ; +4 = 12 + sta screen_ptr_lo ; +3 = 15 + lda SAVMSC+1 ; +3 = 18 + adc line_addr_tab_hi,x ; +4 = 22 + sta screen_ptr_hi ; +3 = 25 + + ; now do the column. column_byte_tab is only a half-table, so do lookup + ; on bits 0-4 of COLCRS, then add 20 decimal if bit 5 of COLCRS was set. + lda COLCRS + tay + and #$1F + tax + lda column_byte_tab,x + cpy #$20 + bcc ssp_noadd + adc #$13 ; +1 because C set = 20 dec + +ssp_noadd: + clc + adc screen_ptr_lo + sta screen_ptr_lo + lda #0 + adc screen_ptr_hi + sta screen_ptr_hi + + ;rts + +; ---------------------------------------------------------------------------- +; Set up font_index to point to the font_data bitmap for the character in +; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the +; bitmap is in the upper or lower 4 bits of the bytes pointed to. + +; Calculation is: +; lo_nybble_flag = (TMPCHR & 1) ? $FF : $00; +; font_index = (TMPCHR >> 1) * 5; + +setup_font_index: + lda #$00 + sta lo_nybble_flag + lda TMPCHR + lsr ; a = (TMPCHR >> 1) + tay ; y = a + bcc font_hi_nybble + dec lo_nybble_flag ; = $FF + +font_hi_nybble: + clc + asl ; a *= 2 + asl ; a *= 2 + sta font_index + tya + adc font_index + sta font_index + + ; rts + + +; ---------------------------------------------------------------------------- +; True descender support: we've got a hard-coded list of 5 characters +; (g j p q y) that have them. All the descender graphics are stored in the +; bottom nybble of the last glyph in the font, which means we can only have +; 5 characters that have descenders. +; TODO: tighten up this code some (faster/smaller) + + lda TMPCHR + ldx #$FF + + cmp #'g-$20 + bne chk_j + ldx #DESCENDERS-1 +chk_j: + cmp #'j-$20 + bne chk_p + ldx #DESCENDERS +chk_p: + cmp #'p-$20 + bne chk_q + ldx #DESCENDERS+1 +chk_q: + cmp #'q-$20 + bne chk_y + ldx #DESCENDERS+2 +chk_y: + cmp #'y-$20 + bne not_y + ldx #DESCENDERS+3 + +not_y: + stx descender + +; ---------------------------------------------------------------------------- +; When write_font_data is called, all this stuff must be set up: +; - font_index is the 1-byte index into font_data where the current glyph is +; - lo_nybble_flag is 0 for high nybble of glyph data, $FF for low +; - mask_lo/hi is our 16-bit pixel mask (1's are "leave original data") +; - shift_amount is # of times to shift glyph data right +; - screen_ptr_lo/hi points to the 1st byte on the top line +; - inverse_mask is 0 for normal or INVERTED_MASK for inverse +; - descender is the offset *minus one* of the byte holding the bottom 4 +; pixels in the 4x6 character. Most of the time this will be $FF, +; AKA the the offset from font_data of the first byte of the space glyph +; (minus one), which has 0000 in its top nybble. The rest of the time, +; the descenders are taken from the bottom nybble of the last character +; glyph (which would be the unprintable code $7F). The logic that does +; the descenders is hard-coded to use the top nybble for $FF and the +; bottom nybble for anything else. + +; Loop 5 times, each time thru the loop: +; - extract 4-bit glyph data, store in glyph_data_lo +; - apply inverse_mask +; - shift right shift_amount times +; ...write data... +; - add 40 to 16-bit screen_ptr_lo/hi (to get to next line) +; ...then one more loop with font_index and lo_nybble_flag set +; to a byte in the space glyph, to handle the bottom row (which +; is always 0 for normal or all 1's for inverse) + +write_font_data: + ldx #$05 ; outer loop counter, aye + +wfont_line_loop: + lda #$00 + sta glyph_data_hi + + ldy font_index + lda font_data,y ; note: entire font must fit in one page! + + bit lo_nybble_flag + beq use_hi_nybble + + asl ; the pixels we want are in the low nybble of the font data byte. + asl ; shift them up to the top nybble + asl + asl + +use_hi_nybble: ; 4-bit glyph data now in hi nybble + and #$F0 + eor inverse_mask + sta glyph_data_lo + + ldy shift_amount + beq wfont_no_shift + +wfont_shift_loop: ; right-shift 16-bit glyph data shift_amount times + lsr glyph_data_lo + ror glyph_data_hi + dey + bne wfont_shift_loop + +wfont_no_shift: ; Y always zero when we get here + lda mask_lo + and (screen_ptr_lo),y + ora glyph_data_lo + sta (screen_ptr_lo),y + + lda mask_hi + beq wfont_skip_hi ; don't bother with 2nd screen byte if we don't need to + iny + and (screen_ptr_lo),y + ora glyph_data_hi + sta (screen_ptr_lo),y + +wfont_skip_hi: + dex + bmi wfont_done + bne wfont_not_bottom + + ;stx font_index + ;stx lo_nybble_flag + +; X always 0 here: for last line, use the descender (if there's no +; descender for this char, that's $FF. font_index will get inc'ed, +; meaning non-decender chars use the first byte of the space glyph +; as their "descender") + lda descender + sta font_index + cmp #$FF + beq wfont_not_bottom + sta lo_nybble_flag + +wfont_not_bottom: + lda #$28 ; add 40 bytes to point to next line of screen RAM + clc + adc screen_ptr_lo + sta screen_ptr_lo + bcc wfont_noinc + inc screen_ptr_hi + +wfont_noinc: + inc font_index + bne wfont_line_loop ; branch always + +wfont_done: + rts + +; ---------------------------------------------------------------------------- +; Not the fastest scroller in the west... TODO: make faster :) + +; lda_operand points to line N (minus one byte) +; sta_operand points to line N+1 (minus one byte) +; Y ranges 240 to 1 in the loop, hence the -1 byte +; CAUTION: Self-modifying code! Proceed with caution. + +; This version gives us overall driver speed almost 20% faster +; than the original scroll_screen (last commented-out one below) +; Also just scrolling 250 times is slightly faster than COL80 +; (1505 jiffies; setting CRITIC saves 48 jiffies) +; (makes it 17% the speed of the OS E: driver, where COL80 is 15%) +; Note that E80 is slightly over twice as fast at this as the OS! + +; Note about performance where scrolling is *not* concerned: +; Printing 914 non-control characters on a freshly-cleared screen: +; OS E: - 172 jiffies (subtract 12 = 160 jiffies if cursor disabled) +; E80 - 168 jiffies (about same as OS E:) +; COL80 - 116 jiffies (yes, it's fastest!) +; CON64 from SDX 4.41 - 227 jiffies first time I tried, crashed next time! +; COL64 - 142 jiffies (still faster than OS E:) + +scroll_screen: +; lda SDMCTL +; pha +; lda #0 +; sta SDMCTL + +; lda CRITIC +; pha +; lda #1 +; sta CRITIC + + lda SAVMSC + sec + sbc #1 + sta lda_operand + lda SAVMSC+1 + sbc #0 + sta lda_operand+1 + ldx #LAST_ROW + +scroll_line_loop: + ldy #$F0 + + lda lda_operand+1 + sta sta_operand+1 + lda lda_operand + sta sta_operand + clc + adc #$F0 + sta lda_operand + bcc ss_noinc + inc lda_operand+1 +ss_noinc: + +scroll_byte_loop: +lda_operand = *+1 + lda 0,y +sta_operand = *+1 + sta 0,y + dey + bne scroll_byte_loop + dex + bne scroll_line_loop + +scroll_blank: + lda lda_operand + sta sta2_operand + lda lda_operand+1 + sta sta2_operand+1 + lda #0 + ldy #$F0 +sblank_loop: +sta2_operand = *+1 + sta 0,y + dey + bne sblank_loop + +; pla +; sta SDMCTL +; pla +; sta CRITIC + rts + +;; This version is faster and fully functional +;; (overall driver speed is 10% faster than with the +;; one below) +; glyph_data_lo points to line N (minus one byte) +; screen_ptr_lo points to line N+1 (minus one byte) +; Y ranges 240 to 1 in the loop, hence the -1 byte + +;;scroll_screen: +;; lda SAVMSC +;; sec +;; sbc #1 +;; sta screen_ptr_lo +;; lda SAVMSC+1 +;; sbc #0 +;; sta screen_ptr_hi +;; ldx #LAST_ROW +;; +;;scroll_line_loop: +;; ldy #$F0 +;; +;; lda screen_ptr_hi +;; sta glyph_data_hi +;; lda screen_ptr_lo +;; sta glyph_data_lo +;; clc +;; adc #$F0 +;; sta screen_ptr_lo +;; bcc ss_noinc +;; inc screen_ptr_hi +;;ss_noinc: +;; +;;scroll_byte_loop: +;; lda (screen_ptr_lo),y +;; sta (glyph_data_lo),y +;; dey +;; bne scroll_byte_loop +;; dex +;; bne scroll_line_loop +;; +;;scroll_blank: +;; lda #0 +;; ldy #$F0 +;;sblank_loop: +;; sta (screen_ptr_lo),y +;; dey +;; bne sblank_loop +;; +;; rts + +; Clock cycle timings: +; 1792080 CPU cycles per second (or is it 1789773?) +; 29868 per jiffy on NTSC (1/60 sec) +; DL = 174 bytes @ 1 cycle each +; Screen RAM = 7680 bytes @ 1 ea +; Refresh = 262 * 9 = 2358 +; so ANTIC steals 10212 (34.2%) cycles, leaves 19656 (65.8%) +; Of that time, the OS steals some doing VBLANK processing. +; It may be that I can set CRITIC here and get a little of +; that back (depends on what, if anything, that does to +; the RS232 driver and/or custom keybuffer stuff in FujiChat). + +; Now if I could actually do a 100% unrolled scroller, simply +; LDA blah:STA blah-1 7680 times, with NMI/VBI/ANTIC disabled, +; that would be 4+4=8 cycles times 7680 = 61440, or 3.12 frames +; (or 0.052 sec, call it 1/20 sec). Obviously can't do it that way. + +; Did some tests of overall performance (not just scrolling: print +; 24 lines of 35 chars, then 24 newlines, repeat in a loop 10x) +; Turning off ANTIC DMA seems to save 25% time. Setting CRITIC only +; saves 3% or so. Disabling IRQs/NMIs entirely is probably not an +; option. + +;; old (slower, but working) version: +;; scroll_screen: +;; lda #0 ; +2 = 2 +;; sta COLCRS ; +3 = 5 +;; sta ROWCRS ; +3 = 8 +;; jsr setup_screen_ptr ; +6 = 14, +54 = 68 +;; +;; scroll_line_loop: +;; lda screen_ptr_lo ; +3 = 3 +;; sta glyph_data_lo ; +3 = 6 +;; lda screen_ptr_hi ; +3 = 12 +;; sta glyph_data_hi ; +3 = 15 +;; ldx ROWCRS ; +3 = 18 +;; cpx #LAST_ROW ; +2 = 20 +;; beq scroll_blank ; +2 = 22 (+1 more last time thru) +;; inx ; +2 = 24 +;; stx ROWCRS ; +3 = 27 +;; jsr setup_screen_ptr ; +6+54 = 87 +;; ldy #0 ; +2 = 89 +;; ; times 31 is 2759, +1 = 2760 +;; +;; scroll_byte_loop: +;; lda (screen_ptr_lo),y ; +5 = 5 +;; sta (glyph_data_lo),y ; +6 = 11 +;; iny ; +2 = 13 +;; cpy #$F0 ; +2 = 15 +;; bne scroll_byte_loop ; +3 = 18 (-1 last time thru) +;; ; ...times 31 times 240 - 1 = 133919 (!) +;; beq scroll_line_loop ; +3*31-1 (92) +;; +;; scroll_blank: +;; jsr setup_screen_ptr ; +6+54 = 60 +;; ldy #0 ; +2 = 62 +;; tya ; +2 = 64 +;; sblank_loop: +;; sta (screen_ptr_lo),y ; +6 = 6 +;; iny ; +2 = 8 +;; cpy #$F0 ; +2 = 10 +;; bne sblank_loop ; +3 = 13 (-1 last time) +;; ; times 240, minus 1 = 3119 +;; +;; rts ; +6 +;; +;; Total routine time is 68 + 2760 + 133919 + 92 + 64 + 3119 + 6 = 140028 +;; Divide by free cyc/frame: 140028/19656 = 7.12 frames, or 0.11 sec, +;; not counting VBLANK overhead. 95% of the time is of course in the +;; inner loop. Every cycle saved in the inner loop is worth about +;; 5% of the runtime! So switching from incrementing to decrementing +;; Y will save 10% of the time (from not having the CPY). Using self- +;; modifying code for the lda/sta saves 2 more cycles (10% more), but +;; adds a small bit of overhead in the outer loop. +;; The scroll_blank loop is only 2.2% of the total time. Every cycle +;; shaved off its loop is worth only 1/3 of a percent of the total +;; time (switching to dey is worth 2/3 of 1%). +;; Replace jsr setup_screen_ptr in scroll_line_loop with loading from +;; the tables directly will save approx. 35 cycles per outer loop, +;; or only about 0.8%. +;; So total savings is 20% + 0.6% + 0.8% = 21.4%, meaning real time +;; drops to approx 0.085 sec, or approx 5.5 NTSC frames (another way +;; to look at it: 11.75 scrolled lines/sec instead of the original 9) +;; Yet another way: 2 1/3 seconds to scroll the whole screen, vs +;; the original 3 1/2. Still abysmal. + +;; One possibility would be to borrow a page from the ACE-80 book and +;; update LMSes within the DL. This would bloat the display list by +;; 64 bytes (not so bad). We'd basically treat screen RAM as a circular +;; buffer of 32 lines. Every scroll, update the LMS operands to point +;; to the next line-buffer, and whichever buffer is the last visible +;; line needs to be blanked. Got to see how much code this will add +;; (possibly the routine that does this might not be longer than the +;; scroll_screen I've been using). ACE-80 (or anyway E80) uses way +;; more screen RAM than it looks like it needs, plus DLIs. + +; ---------------------------------------------------------------------------- +; Move the cursor one space to the right (to the next line if at the margin, +; and scroll screen if on the last row) + +advance_cursor: + inc COLCRS + lda RMARGN + cmp COLCRS + bcs same_line + lda LMARGN + sta COLCRS + lda ROWCRS + cmp #LAST_ROW + bcc no_scroll + jsr scroll_screen + ; Move to last row after scrolling + lda #LAST_ROW-1 + sta ROWCRS + +no_scroll: + inc ROWCRS + +same_line: + rts + +END_ADDR_1 = *-1 + + +; ---------------------------------------------------------------------------- +; Initialization. If we don't want the handler to survive a warmstart, we +; can load this bit into e.g. the cassette buffer (throw away after running) + +START_ADDRESS_2 = CASBUF + +; XEX segment header for throwaway init code + rorg START_ADDRESS_2-4 + word START_ADDRESS_2 + word END_ADDR_2 + +col64_init: + ldy #$00 + +next_hatab_slot: + lda HATABS,y + beq register_x_handler + iny + iny + iny + cpy #$20 + bcc next_hatab_slot + jmp return_success + +register_x_handler: + lda #$58 + sta HATABS,y + lda #col64_vector_tab + iny + sta HATABS,y + jmp return_success + +main_entry_point: + jsr col64_init + lda #$0C + sta ICCOM + ldx #$00 + jsr CIOV + lda #$58 + sta font_index + lda #$03 + sta ICCOM + lda #font_index + sta ICBAL + lda #$00 + sta ICBAH + ldx #$00 + jsr CIOV + ldy #$07 + lda #col64_vector_tab + iny + sta HATABS,y +no_e_handler: + lda #START_ADDRESS_1 + sta MEMTOP+1 + jmp return_success + +END_ADDR_2 = *-1 + +; XEX segment (run address) + word INITAD + word INITAD+1 + word main_entry_point + +; That's all, folks... + +; Rest of file is me rambling & meandering, ignore or not as you choose + +; Possible improvements, some of which may apply to this driver only, +; some of which may apply to a (to be written) 40-column renderer. +; Redb3ard has designed really nice 8x8 normal, bold, italic fonts, +; including a bunch of Unicode normal characters... the 40-column +; driver would include UTF-8 support. Of course there's not enough +; RAM for an IRC client, TCP/IP stack, screen/DL memory, driver, +; UTF-8 tables, and 3 or 4 fonts... will have to wait until after +; the 1.0 FujiChat release (my roadmap for 1.0 is that everything +; needs to work on a 48K unmodded 800; 2.0 will have new features +; that may only work on an XL or even require 130XE banks, though +; it will still be as functional as 1.0, on an 800). + +; True descenders and 5-bit-wide characters. + +; For descenders, could simply leave the top row of pixels blank on +; the screen, and draw the 5 rows of character in the bottom 5 of +; the 6-scanline block. They'd possibly touch the character on the +; next line... + +; 5-bit-wide characters should be used sparingly: only M W m w T +; and maybe Y V v # need them. The "extra" bit could go on the left, +; and just be a copy of the rightmost bit, since these characters +; are symmetrical... but these would often touch the character on +; the left. Capital letters, it's less of a big deal in normal English +; text, since a capital letter should be preceded by a space (or at +; least punctuation), and it won't touch the character on the right +; unless it's another 5-bit-wide one (few words in English are going +; to have that problem; maybe the name AMY in all caps). Unfortunately +; I can't think of a good way to encode the bits of information that +; say a character needs the extra pixel (or a descender either) other +; than a hard-coded set of compares against specific char codes, or +; else a loop over a table of them. Either way there's a loss of +; performance: most characters will fail all the compares... +; It'd be possible to do a 5x5 font, or even 5x6, but 5 bits wide +; means we can't pack the pixel data 2 rows per byte (so the +; font won't fit in a page any more, plus we have to use (zp),y +; or something to access it...) + +; Multiple font support. Since it's an IRC-specific driver, could just +; have _putbyte directly interpret the IRC protocol formatting codes, +; render e.g. bold as inverse, italic as underline if I implement it, +; or else do up a separate italic font (if it's possible to make one +; look good in 4x5). _putbyte could at least strip out the codes it +; can't render (e.g. color). + +; I've thought of doing underline (either a separate mode, or instead +; of inverse video), but a lot of the glyphs will look like crap with +; the underline, because there's no room for spacing: the underline +; will touch the bottom pixels of most characters (and overwrite the +; descenders if we add true descender support...) + +; Obviously, making it a fully-functional E: replacement would be nice. +; I'm not doing this because I'm only wanting to use the driver for +; text-only cc65 programs (specifically FujiChat), though possibly +; I'll come back to col64 and do a proper version later. + +; Also nice: user-adjustable number of rows. Most peoples' monitors can +; display something above 200 scanlines (particularly if they're in PAL +; countries). As-is, we're using 192 scanlines to get 32 rows (of 6 lines +; each). Most people could easily display 34 rows (204 scanlines), and +; not a few could display 35 (210), particularly if the blanking +; instructions at the start of the display list are user-adjustable too +; (to move the picture up or down). Memory usage for video RAM would +; grow by 240 byte per row of characters, and of course we'd need code +; to set up the custom display list (which would be longer than a +; normal one for GR.8). Probably would put a limit of 36 or 40 rows +; since the various tables are fixed-size... + +; If there were RAM enough for it, or if we decide to use XE extra +; banks (or XL/XE under-OS RAM), could have _putbyte also store +; every output character in a buffer, for FujiChat to use as +; scrollback/log buffer (or any other program to use as it sees +; fit, of course). + +; User-loadable font isn't a bad idea: the init code can look for a +; file D:COL64.FNT and load it into font_data if found. + +; Could implement standard ASCII backspace/tab/linefeed/CR/etc codes, +; using low ASCII codes. This would be suitable for a telnet or terminal +; client (not needed for IRC) + +; I really would like to do auto-relocation. Program could load itself +; wherever, and relocate itself (using a table of offsets, for absolute +; addresses within the program) to either MEMLO or MEMTOP. This would +; mean more init code only. + +; It'd be nice to speed up scrolling. One dumb trick would be to use +; self-modifying code: instead of (zp),y addressing, use abs,y +; in the inner loop, and the outer loop modifies the operands in +; the inner. Would mean the code can't be burned to ROM, but who +; was planning to do that anyway? Also simply moving more than one +; chunk per outer-loop iteration would be a small speedup, and so +; would moving 256 bytes per, instead of 240. +; Since the inner loop does lda (zp),y [5+cyc] and sta (zp),y [6cyc] +; 7440 times, replacing them with lda abs,y [4+cyc] and sta abs,y +; [5cyc] should save 7440*2 = almost 15K cycles. +; which may not be noticeable... Unrolling the loop is even less of a +; gain: the outer loop only runs 32 times. Could set CRITIC during the +; move (not sure that helps much). No matter how you slice it, +; moving 8K on a 6502 is *slow*. + +; One slightly cool idea would be to do a proper OPEN of channel #6 +; to S:, like the BASIC GR. command does, instead of the "shortcut" +; using ZIOCB and calling the S: open routine directly. Doing this +; would allow PLOT, DRAWTO, and XIO 18 (fill). diff --git a/src/col64/cruft/col64.dasm.works b/src/col64/cruft/col64.dasm.works new file mode 100644 index 0000000..1e02921 --- /dev/null +++ b/src/col64/cruft/col64.dasm.works @@ -0,0 +1,731 @@ + +; ---------------------------------------------------------------------------- +; 64x32 software text driver +; Uses 4x5 font in 5x6 character cells +; Based on disassembled COL80 driver + +; This driver is missing quite a few things a full E: driver should have: + +; - No support for cursor controls, insert/delete, or even clear screen +; (instead the control-codes are printed as normal characters, if they're +; above 31 decimal) + +; - No support for low ASCII at all: any attempt to input or print a character +; in the range 0-31 decimal is just ignored (this includes the arrow keys) + +; - Does not attempt to survive a warmstart + +; - Will fail disastrously if an application sets COLCRS/ROWCRS to any +; out-of-range values + +; - Only displays the cursor during get-byte operations + +; - Backspace key is supported during get-byte, but printing a backspace +; with put-byte prints a tilde instead + +; On the other hand, this driver is tiny, and plays nice with cc65's stdio +; support (though NOT conio!) + + processor 6502 ; DASM-specific + +; ---------------------------------------------------------------------------- + include equates.inc +s_dev_open_lo = $E410 ; (not named in OS sources) +s_dev_open_hi = $E411 ; "" +k_dev_get_lo = $E424 ; "" +k_dev_get_hi = $E425 ; "" + +; ---------------------------------------------------------------------------- +; Constants + +LAST_ROW = $1F +EOL = $9B +INVERTED_MASK = $F8 + +; ---------------------------------------------------------------------------- +; Defaults + +DEFAULT_TEXT_COLOR = $00 +DEFAULT_BG_COLOR = $08 +;DEFAULT_LMARGN = $00 ; not used +DEFAULT_RMARGN = $3F + +; ---------------------------------------------------------------------------- +; ZP storage +; Reuse some of the E:/S: devices' storage +; These all get recalculated on col64_putbyte entry, +; so it's OK to mix with GR.8 PLOT/DRAWTO stuff + + seg.u "data" + org $5A ; aka OLDROW +mask_lo ds 1 +mask_hi ds 1 +screen_ptr_lo ds 1 +screen_ptr_hi ds 1 +font_index ds 1 +shift_amount ds 1 +line_count ds 1 +glyph_data_lo ds 1 +glyph_data_hi ds 1 + +; ---------------------------------------------------------------------------- +; Non-ZP storage (cassette buffer for now) + + org CASBUF +lo_nybble_flag ds 1 +inverse_mask ds 1 +line_buffer_index ds 1 +line_buffer ds $80 + + seg "code" +; ---------------------------------------------------------------------------- +; XEX segment header +START_ADDRESS_1 = $9A00 + org START_ADDRESS_1-6 + + word $FFFF + word START_ADDRESS_1 + word END_ADDR_1 + +; ---------------------------------------------------------------------------- +; Font data should be aligned on a page boundary +; (for speed; still works unaligned). Each 5 bytes stores 2 glyphs +; side-by-side. When rendering into 5x6 cells, the bottom line and +; the left column are set to all 0, so the glyphs can take up the +; entire 4x5 space. +; Only character codes 32 through 127 are supported; this is 96 +; characters. At 2 glyphs per 5 bytes, that's 96/2*5=240 bytes, +; which means the whole font fits into one page and can be +; accessed with X or Y indexed mode rather than (indirect),Y. + +font_data: + include font4x5.inc + +; ---------------------------------------------------------------------------- +; Mask tables, used by setup_mask. Indexed by (COLCRS % 8), since they +; would repeat every 8 bytes anyway. + +mask_lo_tab: + byte $07, $F8, $C1, $FE, $F0, $83, $FC, $E0 + +; In mask_hi_tab, $00 is never a valid mask, while $FF means "don't touch any +; bits in 2nd byte". As a minor optimization, $00 appears in the table in +; place of $FF. This allows us to just test the Z flag after loading the mask +; hi byte, instead of needing to compare against $FF. + +mask_hi_tab: + byte $00, $3F, $00, $0F, $7F, $00, $1F, $00 + +; ---------------------------------------------------------------------------- +; Indexed by COLCRS%8, how many bits to shift the font data right +; The mask_*_tab stuff above could be calculated at runtime from this, +; the tables are only there for speed. +shift_amount_tab: + byte $00, $05, $02, $07, $04, $01, $06, $03 + +; ---------------------------------------------------------------------------- +; Line address tables, used by setup_screen_ptr. + +line_addr_tab_hi: + byte $00, $00, $01, $02, $03, $04, $05, $06 + byte $07, $08, $09, $0a, $0b, $0c, $0d, $0e + byte $0f, $0f, $10, $11, $12, $13, $14, $15 + byte $16, $17, $18, $19, $1a, $1b, $1c, $1d + +line_addr_tab_lo: + byte $00, $f0, $e0, $d0, $c0, $b0, $a0, $90 + byte $80, $70, $60, $50, $40, $30, $20, $10 + byte $00, $f0, $e0, $d0, $c0, $b0, $a0, $90 + byte $80, $70, $60, $50, $40, $30, $20, $10 + +; ---------------------------------------------------------------------------- +; Byte offset within scanline, indexed by COLCRS value +; Used by setup_screen_ptr + +column_byte_tab: + byte $00, $00, $01, $01, $02, $03, $03, $04 + byte $05, $05, $06, $06, $07, $08, $08, $09 + byte $0A, $0A, $0B, $0B, $0C, $0D, $0D, $0E + byte $0F, $0F, $10, $10, $11, $12, $12, $13 + byte $14, $14, $15, $15, $16, $17, $17, $18 + byte $19, $19, $1A, $1A, $1B, $1C, $1C, $1D + byte $1E, $1E, $1F, $1F, $20, $21, $21, $22 + byte $23, $23, $24, $24, $25, $26, $26, $27 + +; ---------------------------------------------------------------------------- +; Handler table (HATABS will point to this). +; See the HATABS and EDITRV entries in Mapping the Atari for details. + +col64_vector_tab: + word col64_open-1 ; OPEN vector + word col64_close-1 ; CLOSE vector + word col64_getbyte-1 ; GET BYTE vector + word col64_putbyte-1 ; PUT BYTE vector + word col64_close-1 ; GET STATUS vector + word col64_close-1 ; SPECIAL vector + jmp col64_init ; Jump to initialization code (JMP LSB/MSB) + +; ---------------------------------------------------------------------------- +; Assembly version of GRAPHICS 8+16 command. + +init_graphics_8: + lda #$08 ; graphics mode 8 + sta ICAX2Z + lda #$0C ; R/W access + sta ICAX1Z + jsr open_s_dev + + ; Set default colors + lda #DEFAULT_BG_COLOR + sta COLOR2 + sta COLOR4 + lda #DEFAULT_TEXT_COLOR + sta COLOR1 + + ; Protect ourselves from the OS + lda #START_ADDRESS_1 + sta MEMTOP+1 + rts + +; ---------------------------------------------------------------------------- +; Call the OPEN vector for the S: device, using the ROM vector table +; at $E410. The table stores address-minus-one of each routine, which is +; meant to actually be called via the RTS instruction (standard 6502 +; technique, but confusing the first time you encounter it) + +open_s_dev: + lda s_dev_open_hi + pha + lda s_dev_open_lo + pha + rts + +; ---------------------------------------------------------------------------- +; Callback for the internal get-one-byte, used by the OS to implement the +; CIO GET RECORD and GET BYTES commands. This routine takes no arguments, +; and returns the read byte in the accumulator. + +; Internally, COL64 maintains a line buffer. Each time col64_getbyte is +; called, it returns the next character in the buffer. If the buffer's +; empty (or if the last call returned the last character), a new line +; of input is read from the user (and the first character is returned). +; This is exactly how the OS E: device works. + +col64_getbyte: + lda BUFCNT + beq get_line + +get_next_byte: + ldx line_buffer_index + lda line_buffer,x + dec BUFCNT + inc line_buffer_index + jmp return_success + +; ---------------------------------------------------------------------------- +; Get a line of input from the user, terminated by the Return key. + +get_line: + lda #$00 + sta BUFCNT + sta line_buffer_index + +show_cursor: + lda #$00 + sta TMPCHR + lda #INVERTED_MASK + sta inverse_mask + jsr render_glyph + jsr get_keystroke + cpy #$01 + beq keystroke_ok + dey ; yes, we really care about 1-byte optimizations + sty line_buffer_index + sty BUFCNT + +keystroke_ok: + cmp #$20 + bcc show_cursor ; ignore low ASCII + cmp #EOL + bne check_backs_key + jmp return_key_hit + +check_backs_key: + cmp #$7E + bne check_clear_key + jmp backs_key_hit + +check_clear_key: + cmp #$7D + bne normal_key_hit + jmp clear_key_hit + +normal_key_hit: + ldx BUFCNT + bpl buffer_character +; jmp beep ; if we implemented it... + jmp show_cursor + +buffer_character: + sta line_buffer,x + jsr col64_putbyte + inc BUFCNT + jmp show_cursor + +return_key_hit: + jsr print_space + lda #EOL + ldx BUFCNT + sta line_buffer,x + inc BUFCNT + jsr col64_putbyte + jmp get_next_byte + +clear_key_hit: +; jsr clear_screen ; if we implemented it... + lda #$00 + sta line_buffer_index + sta BUFCNT + jmp get_line + +backs_key_hit: + jsr print_space + lda BUFCNT + beq backs_key_done + dec COLCRS + lda COLCRS + clc + adc #$01 + cmp LMARGN + bne backs_same_line + lda RMARGN + sta COLCRS + dec ROWCRS + +backs_same_line: + dec BUFCNT + +backs_key_done: + jmp show_cursor + +; ---------------------------------------------------------------------------- +; Print a space character at the current cursor position. Does not +; update the cursor position. +print_space: + lda #$00 + sta inverse_mask + + sta TMPCHR + jsr render_glyph + rts + +; ---------------------------------------------------------------------------- +; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine +; (call by pushing address-minus-one then doing an RTS) + +get_keystroke: + lda k_dev_get_hi + pha + lda k_dev_get_lo + pha + rts + + +; ---------------------------------------------------------------------------- +; Unimplemented CIO callbacks here. Also various other routines jump here +; to return success to the caller. + +col64_close: +return_success: + ldy #$01 + rts + +; ---------------------------------------------------------------------------- +; CIO OPEN command callback + +col64_open: + jsr init_graphics_8 + lda #$00 + sta ROWCRS + sta COLCRS + sta BUFCNT + sta LMARGN + lda #DEFAULT_RMARGN + sta RMARGN + rts + +; ---------------------------------------------------------------------------- +; CIO PUT BYTE command callback +; The byte to put is passed to us in the accumulator. + +col64_putbyte: + ; EOL (decimal 155)? + cmp #EOL +;;; bne check_clear + bne regular_char + lda RMARGN + sta COLCRS + jmp skip_write + +;;;check_clear: +;;; ; save memory by not including clear_screen +;;; ; (also, this lets us print the } character) +;;; ; Clear (decimal 125)? +;;; cmp #$7D +;;; bne regular_char +;;; jmp clear_screen +;;; .endif +;;; + +; See if this is an inverse video char (code >= 128) +regular_char: + tax + bpl not_inverse + lda #INVERTED_MASK + sta inverse_mask + bne skip_ninv + +not_inverse: + lda #$00 + sta inverse_mask + +skip_ninv: + txa + and #$7F + sec + sbc #$20 + bcs not_low_ascii + jmp return_success + +not_low_ascii: + sta TMPCHR + + lda DINDEX ; OS stores current graphics mode here + cmp #$08 + beq graphics_ok + ; If we're not in GRAPHICS 8 mode, reinitialize ourselves + jsr col64_open + +graphics_ok: + jsr render_glyph + +skip_write: + ; Move the cursor 1 space to the right. This will + ; advance us to the next line if we're at the margin, + ; and scroll the screen if needed + jsr advance_cursor + +; Could implement SSFLAG logic here +;check_ssflag: + ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla + ; any time the user presses ctrl-1 + ;lda SSFLAG + ;bne check_ssflag + jmp return_success + +; ---------------------------------------------------------------------------- +; Call the routines that actually print the character. +; render_glyph prints the character in TMPCHR at the current +; COLCRS and ROWCRS, and does NOT advance the cursor. +; TMPCHR should already have bit 7 stripped; render_glyph will +; use inverse_mask, so the caller should have set that up as well. +render_glyph: + jsr setup_mask + jsr setup_screen_ptr + jsr setup_font_index + jmp write_font_data + +; ---------------------------------------------------------------------------- +; mask is used to avoid overwriting pixels outside the character cell +; we're currently writing. Since 5 pixel wide cells don't align on byte +; boundaries in screen RAM, we have to read/modify/write 2 bytes, and +; the mask also has to be 2 bytes wide. +; Also we set up shift_amount here. + +setup_mask: + lda COLCRS + and #$07 + tax + lda mask_lo_tab,x + sta mask_lo + lda mask_hi_tab,x + sta mask_hi + lda shift_amount_tab,x + sta shift_amount + rts + + +; ---------------------------------------------------------------------------- +; Make (screen_ptr_lo) point to the first byte of screen RAM on the top scanline +; of the current char cell. Assumes COLCRS/ROWCRS are never out of range! +setup_screen_ptr: + ; first the row... table lookup quicker than mult by 240 + ldx ROWCRS + clc + lda SAVMSC + adc line_addr_tab_lo,x + sta screen_ptr_lo + lda SAVMSC+1 + adc line_addr_tab_hi,x + sta screen_ptr_hi + + ; now do the column + ldx COLCRS + lda screen_ptr_lo + clc + adc column_byte_tab,x + sta screen_ptr_lo + lda #0 + adc screen_ptr_hi + sta screen_ptr_hi + + rts + +; ---------------------------------------------------------------------------- +; Set up font_index to point to the font_data bitmap for the character in +; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the +; bitmap is in the upper or lower 4 bits of the bytes pointed to. + +; Calculation is: +; lo_nybble_flag = (TMPCHR & 1) ? $FF : $00; +; font_index = (TMPCHR >> 1) * 5; + +setup_font_index: + lda #$00 + sta lo_nybble_flag + lda TMPCHR + lsr ; a = (TMPCHR >> 1) + tay ; y = a + bcc font_hi_nybble + dec lo_nybble_flag ; = $FF + +font_hi_nybble: + clc + asl ; a *= 2 + asl ; a *= 2 + sta font_index + tya + adc font_index + sta font_index + + rts + + +; ---------------------------------------------------------------------------- +; When write_font_data is called: +; - font_index is the 1-byte index into font_data where the current glyph is +; - lo_nybble_flag is 0 for high nybble of glyph data, $FF for low +; - mask_lo/hi is our 16-bit pixel mask (1's are "leave original data") +; - shift_amount is # of times to shift glyph data right +; - screen_ptr_lo/hi points to the 1st byte on the top line + +; Loop 5 times, each time thru the loop: +; - extract 4-bit glyph data, store in glyph_data_lo +; - shift right shift_amount times +; ...write data... +; - add 40 to 16-bit screen_ptr_lo/hi (to get to next line) + +write_font_data: + lda #$05 + sta line_count + +wfont_line_loop: + lda #$00 + tay + sta glyph_data_hi + + ldx font_index + lda font_data,x + + bit lo_nybble_flag + beq use_hi_nybble + + asl + asl + asl + asl + +use_hi_nybble: ; 4-bit glyph data now in hi nybble + and #$F0 + eor inverse_mask + sta glyph_data_lo + + ldx shift_amount + beq wfont_no_shift + +wfont_shift_loop: + lsr glyph_data_lo + ror glyph_data_hi + dex + bne wfont_shift_loop + +wfont_no_shift: + lda mask_lo + and (screen_ptr_lo),y + ora glyph_data_lo + sta (screen_ptr_lo),y + + lda mask_hi + beq wfont_skip_hi + iny + and (screen_ptr_lo),y + ora glyph_data_hi + sta (screen_ptr_lo),y + +wfont_skip_hi: + dec line_count + bmi wfont_done + bne wfont_not_bottom + + stx font_index ; X always 0: for last line, cheat and use the space glyph + stx lo_nybble_flag + +wfont_not_bottom: + lda #$28 ; 40 bytes to next line + clc + adc screen_ptr_lo + sta screen_ptr_lo + bcc wfont_noinc + inc screen_ptr_hi + +wfont_noinc: + inc font_index + bne wfont_line_loop ; branch always + +wfont_done: + rts + +; ---------------------------------------------------------------------------- +; Not the fastest scroller in the west... TODO: make faster :) + +; glyph_data_lo points to line N +; screen_ptr_lo points to line N+1 +scroll_screen: + lda #0 + sta COLCRS + sta ROWCRS + jsr setup_screen_ptr + +scroll_line_loop: + lda screen_ptr_lo + sta glyph_data_lo + lda screen_ptr_hi + sta glyph_data_hi + ldx ROWCRS + cpx #LAST_ROW + beq scroll_blank + inx + stx ROWCRS + jsr setup_screen_ptr + ldy #0 + +scroll_byte_loop: + lda (screen_ptr_lo),y + sta (glyph_data_lo),y + iny + cpy #$F0 + bne scroll_byte_loop + beq scroll_line_loop + +scroll_blank: + jsr setup_screen_ptr + ldy #0 + tya +sblank_loop: + sta (screen_ptr_lo),y + iny + cpy #$F0 + bne sblank_loop + + rts + +; ---------------------------------------------------------------------------- +; Move the cursor one space to the right (to the next line if at the margin, +; and scroll screen if on the last row) + +advance_cursor: + inc COLCRS + lda RMARGN + cmp COLCRS + bcs same_line + lda LMARGN + sta COLCRS + lda ROWCRS + cmp #LAST_ROW + bcc no_scroll + jsr scroll_screen + ; Move to last row after scrolling + lda #LAST_ROW-1 + sta ROWCRS + +no_scroll: + inc ROWCRS + +same_line: + rts + +; ---------------------------------------------------------------------------- +; Initialization. If we don't want the handler to survive a warmstart, we +; can load this bit into e.g. the cassette buffer (throw away after running) + +col64_init: + ldy #$00 + +next_hatab_slot: + lda HATABS,y + beq register_x_handler + iny + iny + iny + cpy #$20 + bcc next_hatab_slot + jmp return_success + +register_x_handler: + lda #$58 + sta HATABS,y + lda #col64_vector_tab + iny + sta HATABS,y + jmp return_success + +main_entry_point: + jsr col64_init + lda #$0C + sta ICCOM + ldx #$00 + jsr CIOV + lda #$58 + sta font_index + lda #$03 + sta ICCOM + lda #font_index + sta ICBAL + lda #$00 + sta ICBAH + ldx #$00 + jsr CIOV + ldy #$07 + lda #col64_vector_tab + iny + sta HATABS,y +no_e_handler: + lda #START_ADDRESS_1 + sta MEMTOP+1 + jmp return_success + +END_ADDR_1 = *-1 + +; XEX segment (run address) + word INITAD + word INITAD+1 + word main_entry_point diff --git a/src/col64/cruft/col64.sh b/src/col64/cruft/col64.sh new file mode 100644 index 0000000..cc49b07 --- /dev/null +++ b/src/col64/cruft/col64.sh @@ -0,0 +1,6 @@ +dasm col64.dasm -f3 -otest -llist +cp test col64.xex +axe -w test test.atr +cat test hello.xex > test2 +axe -w test2 test.atr +atari800 -atari test.atr diff --git a/src/col64/cruft/col64_ext.inc b/src/col64/cruft/col64_ext.inc new file mode 100644 index 0000000..81e7660 --- /dev/null +++ b/src/col64/cruft/col64_ext.inc @@ -0,0 +1,48 @@ + byte $04, $04, $04, $00, $04 ; [0] 32,33 ,! + byte $AA, $AF, $0A, $0F, $0A ; [5] 34,35 ",# + byte $70, $A9, $62, $54, $E9 ; [10] 36,37 $,% + byte $42, $A2, $44, $A0, $D0 ; [15] 38,39 &,' + byte $24, $42, $42, $42, $24 ; [20] 40,41 (,) + byte $A4, $44, $EE, $44, $A4 ; [25] 42,43 *,+ + byte $00, $00, $0F, $20, $40 ; [30] 44,45 ,,- + byte $02, $02, $04, $08, $48 ; [35] 46,47 .,/ + byte $64, $9C, $B4, $D4, $6E ; [40] 48,49 0,1 + byte $6E, $91, $26, $41, $FE ; [45] 50,51 2,3 + byte $2F, $68, $AE, $F1, $2E ; [50] 52,53 4,5 + byte $7F, $81, $E2, $94, $64 ; [55] 54,55 6,7 + byte $66, $99, $67, $91, $6E ; [60] 56,57 8,9 + byte $00, $42, $00, $02, $44 ; [65] 58,59 :,; + byte $20, $4F, $80, $4F, $20 ; [70] 60,61 <,= + byte $87, $49, $22, $40, $82 ; [75] 62,63 >,? + byte $66, $B9, $BF, $89, $69 ; [80] 64,65 @,A + byte $E6, $99, $E8, $99, $E6 ; [85] 66,67 B,C + byte $EF, $98, $9E, $98, $EF ; [90] 68,69 D,E + byte $F7, $88, $EB, $89, $86 ; [95] 70,71 F,G + byte $9E, $94, $F4, $94, $9E ; [100] 72,73 H,I + byte $39, $1A, $1C, $9A, $69 ; [105] 74,75 J,K + byte $8A, $8F, $8D, $89, $F9 ; [110] 76,77 L,M + byte $96, $D9, $B9, $99, $96 ; [115] 78,79 N,O + byte $E6, $99, $E9, $8A, $85 ; [120] 80,81 P,Q + byte $E7, $98, $E6, $A1, $9E ; [125] 82,83 R,S + byte $F9, $49, $49, $49, $46 ; [130] 84,85 T,U + byte $99, $99, $9D, $AF, $4A ; [135] 86,87 V,W + byte $99, $99, $66, $92, $94 ; [140] 88,89 X,Y + byte $F6, $24, $44, $84, $F6 ; [145] 90,91 Z,[ + byte $86, $82, $42, $22, $26 ; [150] 92,93 \,] + byte $40, $A0, $00, $00, $0F ; [155] 94,95 ^,_ + byte $40, $47, $29, $0B, $05 ; [160] 96,97 `,a + byte $80, $87, $E8, $98, $E7 ; [165] 98,99 b,c + byte $10, $16, $79, $9E, $77 ; [170] 100,101 d,e + byte $60, $47, $E9, $47, $41 ; [175] 102,103 f,g + byte $84, $80, $EC, $94, $9E ; [180] 104,105 h,i + byte $28, $0A, $6C, $2A, $29 ; [185] 106,107 j,k + byte $C0, $4A, $4F, $4D, $E9 ; [190] 108,109 l,m + byte $00, $E6, $99, $99, $96 ; [195] 110,111 n,o + byte $00, $E7, $99, $E7, $81 ; [200] 112,113 p,q + byte $00, $A7, $DC, $83, $8E ; [205] 114,115 r,s + byte $40, $E9, $49, $49, $26 ; [210] 116,117 t,u + byte $00, $99, $9D, $AF, $4A ; [215] 118,119 v,w + byte $00, $99, $69, $66, $92 ; [220] 120,121 x,y + byte $06, $F4, $28, $44, $F6 ; [225] 122,123 z,{ + byte $4C, $44, $42, $44, $4C ; [230] 124,125 |,} + byte $06, $5C, $A8, $01, $0C ; [235] 126,127 ~, diff --git a/src/col64/cruft/col64font.bdf b/src/col64/cruft/col64font.bdf new file mode 100644 index 0000000..b15f724 --- /dev/null +++ b/src/col64/cruft/col64font.bdf @@ -0,0 +1,11993 @@ +STARTFONT 2.1 +COMMENT Contributed by Janne V. Kujala +COMMENT $Id: 4x6.bdf,v 1.5 2002-08-26 18:05:49+01 mgk25 Rel $ +COMMENT Send bug reports to Markus Kuhn +FONT -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1 +SIZE 6 75 75 +FONTBOUNDINGBOX 4 6 0 -1 +STARTPROPERTIES 23 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 6 +POINT_SIZE 60 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 40 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 5 +FONT_DESCENT 1 +DESTINATION 1 +COPYRIGHT "Public domain font. Share and enjoy." +CAP_HEIGHT 5 +X_HEIGHT 4 +DEFAULT_CHAR 0 +_GBDFED_INFO "Edited with gbdfed 1.4." +ENDPROPERTIES +CHARS 920 +STARTCHAR char0 +ENCODING 0 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR space +ENCODING 32 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +00 +40 +00 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +A0 +F0 +A0 +00 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +60 +50 +E0 +00 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +20 +40 +90 +00 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +A0 +D0 +00 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +40 +00 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +A0 +00 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +B0 +D0 +60 +00 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +10 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +F0 +20 +00 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +10 +E0 +00 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +E0 +90 +60 +00 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +10 +20 +40 +40 +00 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +60 +90 +60 +00 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +70 +10 +E0 +00 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +00 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +00 +20 +40 +00 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +80 +40 +20 +00 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +20 +40 +80 +00 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +20 +00 +20 +00 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +B0 +B0 +80 +60 +00 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +80 +90 +60 +00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +90 +90 +E0 +00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +F0 +00 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +B0 +90 +60 +00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +10 +10 +90 +60 +00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +F0 +00 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +D0 +90 +90 +00 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +D0 +B0 +90 +90 +00 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +A0 +50 +00 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +A0 +90 +00 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +90 +90 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +20 +40 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +40 +80 +F0 +00 +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +40 +40 +60 +00 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F0 +00 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +30 +50 +90 +70 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +80 +80 +70 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +70 +90 +70 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +A0 +70 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +70 +10 +60 +00 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +90 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +F0 +D0 +90 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +E0 +80 +00 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +90 +70 +10 +00 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +80 +80 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +C0 +30 +E0 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +80 +40 +60 +00 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +20 +40 +C0 +00 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR char127 +ENCODING 127 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +90 +00 +90 +D0 +00 +ENDCHAR +STARTCHAR space +ENCODING 160 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +40 +40 +00 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +E0 +40 +00 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +40 +A0 +00 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +00 +40 +40 +00 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +D0 +D0 +90 +60 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +00 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 173 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +D0 +60 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +C0 +00 +00 +ENDCHAR +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +40 +80 +00 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +D0 +D0 +50 +50 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +00 +00 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +50 +70 +10 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +10 +20 +30 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +50 +B0 +10 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +80 +60 +00 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +F0 +A0 +B0 +00 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +80 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +50 +D0 +50 +E0 +00 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +E0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +A0 +00 +00 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +E0 +80 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +80 +60 +40 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +40 +00 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR Amacron +ENCODING 256 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR amacron +ENCODING 257 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Abreve +ENCODING 258 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR abreve +ENCODING 259 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Aogonek +ENCODING 260 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR aogonek +ENCODING 261 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +A0 +60 +20 +ENDCHAR +STARTCHAR Cacute +ENCODING 262 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cacute +ENCODING 263 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +80 +60 +00 +ENDCHAR +STARTCHAR Ccircumflex +ENCODING 264 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccircumflex +ENCODING 265 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Cdotaccent +ENCODING 266 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cdotaccent +ENCODING 267 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Ccaron +ENCODING 268 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccaron +ENCODING 269 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Dcaron +ENCODING 270 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcaron +ENCODING 271 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Dcroat +ENCODING 272 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcroat +ENCODING 273 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Emacron +ENCODING 274 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR emacron +ENCODING 275 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Ebreve +ENCODING 276 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ebreve +ENCODING 277 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Edotaccent +ENCODING 278 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR edotaccent +ENCODING 279 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Eogonek +ENCODING 280 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +20 +ENDCHAR +STARTCHAR eogonek +ENCODING 281 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +40 +ENDCHAR +STARTCHAR Ecaron +ENCODING 282 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ecaron +ENCODING 283 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Gcircumflex +ENCODING 284 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gcircumflex +ENCODING 285 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gbreve +ENCODING 286 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gbreve +ENCODING 287 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gdotaccent +ENCODING 288 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gdotaccent +ENCODING 289 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gcommaaccent +ENCODING 290 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR gcommaaccent +ENCODING 291 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Hcircumflex +ENCODING 292 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hcircumflex +ENCODING 293 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Hbar +ENCODING 294 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hbar +ENCODING 295 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Itilde +ENCODING 296 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR itilde +ENCODING 297 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Imacron +ENCODING 298 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR imacron +ENCODING 299 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Ibreve +ENCODING 300 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR ibreve +ENCODING 301 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Iogonek +ENCODING 302 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR iogonek +ENCODING 303 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +20 +ENDCHAR +STARTCHAR Idotaccent +ENCODING 304 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR IJ +ENCODING 306 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +A0 +A0 +20 +60 +ENDCHAR +STARTCHAR ij +ENCODING 307 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Jcircumflex +ENCODING 308 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR jcircumflex +ENCODING 309 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +20 +20 +C0 +ENDCHAR +STARTCHAR Kcommaaccent +ENCODING 310 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kcommaaccent +ENCODING 311 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kgreenlandic +ENCODING 312 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR Lacute +ENCODING 313 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lacute +ENCODING 314 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Lcommaaccent +ENCODING 315 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR lcommaaccent +ENCODING 316 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR Lcaron +ENCODING 317 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +C0 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lcaron +ENCODING 318 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Ldot +ENCODING 319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +A0 +80 +E0 +00 +ENDCHAR +STARTCHAR ldot +ENCODING 320 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +50 +40 +E0 +00 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Nacute +ENCODING 323 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR nacute +ENCODING 324 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Ncommaaccent +ENCODING 325 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +20 +ENDCHAR +STARTCHAR ncommaaccent +ENCODING 326 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +40 +ENDCHAR +STARTCHAR Ncaron +ENCODING 327 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR ncaron +ENCODING 328 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR napostrophe +ENCODING 329 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +00 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Eng +ENCODING 330 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +A0 +20 +40 +ENDCHAR +STARTCHAR eng +ENCODING 331 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Omacron +ENCODING 332 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR omacron +ENCODING 333 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Obreve +ENCODING 334 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR obreve +ENCODING 335 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Ohungarumlaut +ENCODING 336 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR ohungarumlaut +ENCODING 337 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR Racute +ENCODING 340 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR racute +ENCODING 341 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Rcommaaccent +ENCODING 342 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +00 +40 +ENDCHAR +STARTCHAR rcommaaccent +ENCODING 343 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +C0 +80 +80 +20 +ENDCHAR +STARTCHAR Rcaron +ENCODING 344 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR rcaron +ENCODING 345 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Sacute +ENCODING 346 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR sacute +ENCODING 347 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scircumflex +ENCODING 348 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR scircumflex +ENCODING 349 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scedilla +ENCODING 350 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scedilla +ENCODING 351 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +E0 +00 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 354 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +20 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 355 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR Tcaron +ENCODING 356 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tcaron +ENCODING 357 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Tbar +ENCODING 358 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tbar +ENCODING 359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Utilde +ENCODING 360 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR utilde +ENCODING 361 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Umacron +ENCODING 362 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR umacron +ENCODING 363 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Ubreve +ENCODING 364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR ubreve +ENCODING 365 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Uring +ENCODING 366 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uring +ENCODING 367 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uhungarumlaut +ENCODING 368 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uhungarumlaut +ENCODING 369 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uogonek +ENCODING 370 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +20 +ENDCHAR +STARTCHAR uogonek +ENCODING 371 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +60 +40 +ENDCHAR +STARTCHAR Wcircumflex +ENCODING 372 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR wcircumflex +ENCODING 373 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ycircumflex +ENCODING 374 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ycircumflex +ENCODING 375 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +40 +80 +00 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Zacute +ENCODING 377 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zacute +ENCODING 378 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zdotaccent +ENCODING 379 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zdotaccent +ENCODING 380 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR longs +ENCODING 383 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR uni018F +ENCODING 399 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR florin +ENCODING 402 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +40 +80 +ENDCHAR +STARTCHAR Scommaaccent +ENCODING 536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scommaaccent +ENCODING 537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +00 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR uni0259 +ENCODING 601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR circumflex +ENCODING 710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR caron +ENCODING 711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR breve +ENCODING 728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dotaccent +ENCODING 729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ring +ENCODING 730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR ogonek +ENCODING 731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +80 +C0 +ENDCHAR +STARTCHAR tilde +ENCODING 732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR hungarumlaut +ENCODING 733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0374 +ENCODING 884 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0375 +ENCODING 885 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +80 +ENDCHAR +STARTCHAR uni037A +ENCODING 890 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +60 +ENDCHAR +STARTCHAR uni037E +ENCODING 894 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +80 +ENDCHAR +STARTCHAR tonos +ENCODING 900 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dieresistonos +ENCODING 901 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Alphatonos +ENCODING 902 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR anoteleia +ENCODING 903 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR Epsilontonos +ENCODING 904 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +60 +40 +60 +00 +ENDCHAR +STARTCHAR Etatonos +ENCODING 905 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Iotatonos +ENCODING 906 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Omicrontonos +ENCODING 908 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Upsilontonos +ENCODING 910 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR Omegatonos +ENCODING 911 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR iotadieresistonos +ENCODING 912 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +40 +20 +00 +ENDCHAR +STARTCHAR Alpha +ENCODING 913 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Beta +ENCODING 914 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Gamma +ENCODING 915 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR Delta +ENCODING 916 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Epsilon +ENCODING 917 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Zeta +ENCODING 918 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Eta +ENCODING 919 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Theta +ENCODING 920 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR Iota +ENCODING 921 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Kappa +ENCODING 922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Lambda +ENCODING 923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Mu +ENCODING 924 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Nu +ENCODING 925 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR Xi +ENCODING 926 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR Omicron +ENCODING 927 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Pi +ENCODING 928 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Rho +ENCODING 929 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR Sigma +ENCODING 931 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Tau +ENCODING 932 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Upsilon +ENCODING 933 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Phi +ENCODING 934 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR Chi +ENCODING 935 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR Psi +ENCODING 936 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 937 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR Iotadieresis +ENCODING 938 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR Upsilondieresis +ENCODING 939 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR alphatonos +ENCODING 940 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR epsilontonos +ENCODING 941 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR etatonos +ENCODING 942 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR iotatonos +ENCODING 943 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresistonos +ENCODING 944 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR alpha +ENCODING 945 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +A0 +50 +00 +ENDCHAR +STARTCHAR beta +ENCODING 946 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR gamma +ENCODING 947 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR delta +ENCODING 948 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR epsilon +ENCODING 949 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR zeta +ENCODING 950 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +80 +E0 +20 +40 +ENDCHAR +STARTCHAR eta +ENCODING 951 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR theta +ENCODING 952 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR iota +ENCODING 953 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR kappa +ENCODING 954 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR lambda +ENCODING 955 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR mu +ENCODING 956 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR nu +ENCODING 957 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +40 +00 +ENDCHAR +STARTCHAR xi +ENCODING 958 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR omicron +ENCODING 959 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR pi +ENCODING 960 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR rho +ENCODING 961 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR sigma1 +ENCODING 962 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +40 +C0 +00 +ENDCHAR +STARTCHAR sigma +ENCODING 963 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +A0 +40 +00 +ENDCHAR +STARTCHAR tau +ENCODING 964 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilon +ENCODING 965 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR phi +ENCODING 966 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +A0 +40 +40 +ENDCHAR +STARTCHAR chi +ENCODING 967 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +60 +A0 +00 +ENDCHAR +STARTCHAR psi +ENCODING 968 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR omega +ENCODING 969 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR iotadieresis +ENCODING 970 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresis +ENCODING 971 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omicrontonos +ENCODING 972 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR upsilontonos +ENCODING 973 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omegatonos +ENCODING 974 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10023 +ENCODING 1025 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10051 +ENCODING 1026 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10052 +ENCODING 1027 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10053 +ENCODING 1028 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10054 +ENCODING 1029 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10055 +ENCODING 1030 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10056 +ENCODING 1031 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10057 +ENCODING 1032 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10058 +ENCODING 1033 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10059 +ENCODING 1034 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10060 +ENCODING 1035 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10061 +ENCODING 1036 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10062 +ENCODING 1038 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10145 +ENCODING 1039 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10017 +ENCODING 1040 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10018 +ENCODING 1041 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10019 +ENCODING 1042 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10020 +ENCODING 1043 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10021 +ENCODING 1044 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10022 +ENCODING 1045 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10024 +ENCODING 1046 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10025 +ENCODING 1047 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10026 +ENCODING 1048 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +E0 +A0 +20 +00 +ENDCHAR +STARTCHAR afii10027 +ENCODING 1049 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR afii10028 +ENCODING 1050 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10029 +ENCODING 1051 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10030 +ENCODING 1052 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10031 +ENCODING 1053 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10032 +ENCODING 1054 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10033 +ENCODING 1055 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10034 +ENCODING 1056 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10035 +ENCODING 1057 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10036 +ENCODING 1058 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10037 +ENCODING 1059 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +40 +40 +80 +ENDCHAR +STARTCHAR afii10038 +ENCODING 1060 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR afii10039 +ENCODING 1061 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10040 +ENCODING 1062 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii10041 +ENCODING 1063 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +60 +20 +20 +00 +ENDCHAR +STARTCHAR afii10042 +ENCODING 1064 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10043 +ENCODING 1065 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10044 +ENCODING 1066 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10045 +ENCODING 1067 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10046 +ENCODING 1068 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10047 +ENCODING 1069 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10048 +ENCODING 1070 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +D0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10049 +ENCODING 1071 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10065 +ENCODING 1072 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR afii10066 +ENCODING 1073 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10067 +ENCODING 1074 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10068 +ENCODING 1075 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10069 +ENCODING 1076 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10070 +ENCODING 1077 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10072 +ENCODING 1078 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +60 +60 +B0 +00 +ENDCHAR +STARTCHAR afii10073 +ENCODING 1079 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10074 +ENCODING 1080 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10075 +ENCODING 1081 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10076 +ENCODING 1082 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10077 +ENCODING 1083 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10078 +ENCODING 1084 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10079 +ENCODING 1085 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10080 +ENCODING 1086 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10081 +ENCODING 1087 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10082 +ENCODING 1088 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii10083 +ENCODING 1089 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +80 +60 +00 +ENDCHAR +STARTCHAR afii10084 +ENCODING 1090 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10085 +ENCODING 1091 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR afii10086 +ENCODING 1092 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR afii10087 +ENCODING 1093 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii10088 +ENCODING 1094 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +20 +ENDCHAR +STARTCHAR afii10089 +ENCODING 1095 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +00 +ENDCHAR +STARTCHAR afii10090 +ENCODING 1096 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10091 +ENCODING 1097 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10092 +ENCODING 1098 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10093 +ENCODING 1099 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10094 +ENCODING 1100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10095 +ENCODING 1101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10096 +ENCODING 1102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10097 +ENCODING 1103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +60 +A0 +00 +ENDCHAR +STARTCHAR afii10071 +ENCODING 1105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10099 +ENCODING 1106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +20 +ENDCHAR +STARTCHAR afii10100 +ENCODING 1107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10101 +ENCODING 1108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10102 +ENCODING 1109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10103 +ENCODING 1110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10104 +ENCODING 1111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10105 +ENCODING 1112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +20 +20 +20 +C0 +ENDCHAR +STARTCHAR afii10106 +ENCODING 1113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10107 +ENCODING 1114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10108 +ENCODING 1115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10109 +ENCODING 1116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10110 +ENCODING 1118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10193 +ENCODING 1119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10050 +ENCODING 1168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10098 +ENCODING 1169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR uni0492 +ENCODING 1170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR uni0493 +ENCODING 1171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR afii57664 +ENCODING 1488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii57665 +ENCODING 1489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +F0 +00 +ENDCHAR +STARTCHAR afii57666 +ENCODING 1490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii57667 +ENCODING 1491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57668 +ENCODING 1492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57669 +ENCODING 1493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57670 +ENCODING 1494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii57671 +ENCODING 1495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57672 +ENCODING 1496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii57673 +ENCODING 1497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +20 +00 +00 +00 +ENDCHAR +STARTCHAR afii57674 +ENCODING 1498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +20 +ENDCHAR +STARTCHAR afii57675 +ENCODING 1499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +C0 +00 +ENDCHAR +STARTCHAR afii57676 +ENCODING 1500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +20 +40 +00 +ENDCHAR +STARTCHAR afii57677 +ENCODING 1501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57678 +ENCODING 1502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57679 +ENCODING 1503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57680 +ENCODING 1504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR afii57681 +ENCODING 1505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii57682 +ENCODING 1506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +60 +C0 +00 +ENDCHAR +STARTCHAR afii57683 +ENCODING 1507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +20 +20 +ENDCHAR +STARTCHAR afii57684 +ENCODING 1508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57685 +ENCODING 1509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57686 +ENCODING 1510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57687 +ENCODING 1511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57688 +ENCODING 1512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57689 +ENCODING 1513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +D0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57690 +ENCODING 1514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E02 +ENCODING 7682 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E03 +ENCODING 7683 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0A +ENCODING 7690 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0B +ENCODING 7691 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR uni1E1E +ENCODING 7710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E1F +ENCODING 7711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni1E40 +ENCODING 7744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E41 +ENCODING 7745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uni1E56 +ENCODING 7766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E57 +ENCODING 7767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR uni1E60 +ENCODING 7776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E61 +ENCODING 7777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E6A +ENCODING 7786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni1E6B +ENCODING 7787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +20 +ENDCHAR +STARTCHAR Wgrave +ENCODING 7808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wgrave +ENCODING 7809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wacute +ENCODING 7810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wacute +ENCODING 7811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wdieresis +ENCODING 7812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wdieresis +ENCODING 7813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ygrave +ENCODING 7922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ygrave +ENCODING 7923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +60 +20 +40 +ENDCHAR +STARTCHAR uni2010 +ENCODING 8208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR uni2011 +ENCODING 8209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR figuredash +ENCODING 8210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR afii00208 +ENCODING 8213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2016 +ENCODING 8214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR underscoredbl +ENCODING 8215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 'UÂ?-1 +BITMAP +00 +00 +00 +F0 +00 +F0 +ENDCHAR +STARTCHAR quoteleft +ENCODING 8216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +00 +00 +00 +ENDCHAR +STARTCHAR quoteright +ENCODING 8217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR quotesinglbase +ENCODING 8218 +SWIDTH 640 01¥VDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +20 +40 +ENDCHAR +STARTCHAR quotereversed +ENCODING 8219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblleft +ENCODING 8220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblright +ENCODING 8221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblbase +ENCODING1MÀ-2 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +50 +50 +A0 +ENDCHAR +STARTCHAR uni201F +ENCODING 8223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +50 +00 +00 +00 +ENDCHAR +STARTCHAR dagger +ENCODING 8224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR daggerdbl +ENCODING 8225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2023 +ENCODING 8227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +E0 +C0 +00 +00 +ENDCHAR +STARTCHAR onedotenleader +ENCODING 8228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR twodotenleader +ENCODING 8229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +A0 +00 +ENDCHAR +STARTCHAR ellipsis +ENCODING 8230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +B0 +00 +ENDCHAR +STARTCHAR uni2027 +ENCODING 8231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR perthousand +ENCODX;µ?8240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +80 +30 +00 +ENDCHAR +STARTCHAR guilsinglleft +ENCODING 8249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +80 +40 +00 +00 +ENDCHAR +STARTCHAR guilsinglright +ENCODING 8250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +20 +40 +00 +00 +ENDCHAR +STARTCHAR uni203E +ENCODING 8254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR nsuperior +ENCODING 8319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR peseta +ENCODING 8359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +60 +40 +40 +00 +ENDCHAR +SE4 KCHAR Euro +ENCODING 8364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR afii61352 +ENCODING 8470 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +B0 +B0 +A0 +B0 +00 +ENDCHAR +STARTCHAR trademark +ENCODING 8482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +00 +E0 +A0 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 8486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni2127 +ENCODING 8487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR oneeighth +ENCODING 8539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 'UÂ?-1 +BITMAP +80 +80 +B0 +20 +50 +20 +ENDCHAR +STARTCHAR threeeighths +ENCODING 8540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +60 +D0 +20 +ENDCHAR +STARTCHAR fiveeighths +ENCODING 8541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +70 +A0 +50 +20 +ENDCHAR +STARTCHAR seveneighths +ENCODING 8542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +A0 +50 +20 +ENDCHAR +STARTCHAR arrowleft +ENCODING 8592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +F0 +40 +00 +00 +ENDCHAR +STARTCHAR arrowup +ENCODING 8593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR arrowright +ENCODING 8594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +F0 +20 +00 +00 +ENDCHAR +STARTCHAR arrowdown +ENCODING 8595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR arrowboth +ENCODING 8596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +F0 +50 +00 +00 +ENDCHAR +STARTCHAR arrowupdn +ENCODING 8597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR universal +ENCODING 8704 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR uni2201 +ENCODING 8705 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR partialdiff +ENCODING 8706 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR existential +ENCODING 8707 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR uni2204 +ENCODING 8708 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +E0 +60 +E0 +80 +ENDCHAR +STARTCHAR emptyset +ENCODING 8709 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR Delta +ENCODING 8710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR gradient +ENCODING 8711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR element +ENCODING 8712 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +80 +60 +00 +ENDCHAR +STARTCHAR notelement +ENCODING 8713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +E0 +A0 +60 +40 +ENDCHAR +STARTCHAR uni220A +ENCODING 8714 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +C0 +80 +40 +00 +ENDCHAR +STARTCHAR suchthat +ENCODING 8715 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +E0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni220C +ENCODING 8716 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +E0 +60 +C0 +80 +ENDCHAR +STARTCHAR uni220D +ENCODING 8717 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +C0 +40 +80 +00 +ENDCHAR +STARTCHAR uni220E +ENCODING 8718 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +00 +ENDCHAR +STARTCHAR product +ENCODING 8719 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2210 +ENCODING 8720 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR summation +ENCODING 8721 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR minus +ENCODING 8722 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2213 +ENCODING 8723 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni2214 +ENCODING 8724 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR fraction +ENCODING 8725 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR uni2216 +ENCODING 8726 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR asteriskmath +ENCODING 8727 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +70 +E0 +50 +40 +ENDCHAR +STARTCHAR uni2218 +ENCODING 8728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +00 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 8729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR radical +ENCODING 8730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +20 +A0 +60 +00 +ENDCHAR +STARTCHAR uni221B +ENCODING 8731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +50 +D0 +10 +50 +30 +ENDCHAR +STARTCHAR uni221C +ENCODING 8732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +D0 +50 +10 +50 +30 +ENDCHAR +STARTCHAR proportional +ENCODING 8733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +E0 +50 +00 +ENDCHAR +STARTCHAR infinity +ENCODING 8734 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +D0 +B0 +40 +00 +ENDCHAR +STARTCHAR orthogonal +ENCODING 8735 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR angle +ENCODING 8736 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR uni2221 +ENCODING 8737 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +A0 +40 +A0 +F0 +20 +ENDCHAR +STARTCHAR uni2222 +ENCODING 8738 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +A0 +A0 +60 +90 +ENDCHAR +STARTCHAR uni2223 +ENCODING 8739 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni2224 +ENCODING 8740 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +40 +00 +ENDCHAR +STARTCHAR uni2225 +ENCODING 8741 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2226 +ENCODING 8742 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +B0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicaland +ENCODING 8743 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicalor +ENCODING 8744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR intersection +ENCODING 8745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR union +ENCODING 8746 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR integral +ENCODING 8747 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni222C +ENCODING 8748 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +A0 +A0 +80 +ENDCHAR +STARTCHAR uni222D +ENCODING 8749 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +D0 +D0 +D0 +A0 +ENDCHAR +STARTCHAR uni222E +ENCODING 8750 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +E0 +40 +80 +ENDCHAR +STARTCHAR uni222F +ENCODING 8751 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +80 +ENDCHAR +STARTCHAR uni2230 +ENCODING 8752 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +F0 +F0 +D0 +A0 +ENDCHAR +STARTCHAR uni2231 +ENCODING 8753 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +50 +40 +80 +ENDCHAR +STARTCHAR uni2232 +ENCODING 8754 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +C0 +40 +80 +ENDCHAR +STARTCHAR uni2233 +ENCODING 8755 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +E0 +40 +80 +ENDCHAR +STARTCHAR therefore +ENCODING 8756 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2235 +ENCODING 8757 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +40 +00 +ENDCHAR +STARTCHAR uni2236 +ENCODING 8758 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2237 +ENCODING 8759 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2238 +ENCODING 8760 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2239 +ENCODING 8761 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +20 +C0 +20 +00 +ENDCHAR +STARTCHAR uni223A +ENCODING 8762 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni223B +ENCODING 8763 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +50 +A0 +00 +40 +ENDCHAR +STARTCHAR similar +ENCODING 8764 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni223D +ENCODING 8765 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni223E +ENCODING 8766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +D0 +B0 +00 +00 +ENDCHAR +STARTCHAR uni223F +ENCODING 8767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +50 +A0 +20 +00 +ENDCHAR +STARTCHAR uni2240 +ENCODING 8768 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +40 +40 +20 +00 +ENDCHAR +STARTCHAR uni2241 +ENCODING 8769 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +B0 +D0 +40 +80 +ENDCHAR +STARTCHAR uni2242 +ENCODING 8770 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +00 +A0 +50 +00 +ENDCHAR +STARTCHAR uni2243 +ENCODING 8771 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2244 +ENCODING 8772 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +D0 +B0 +40 +F0 +40 +ENDCHAR +STARTCHAR congruent +ENCODING 8773 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni2246 +ENCODING 8774 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR uni2247 +ENCODING 8775 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR approxequal +ENCODING 8776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +50 +A0 +00 +ENDCHAR +STARTCHAR uni2249 +ENCODING 8777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +40 +50 +E0 +80 +ENDCHAR +STARTCHAR uni224A +ENCODING 8778 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +00 +F0 +ENDCHAR +STARTCHAR uni224B +ENCODING 8779 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +40 +B0 +ENDCHAR +STARTCHAR uni224C +ENCODING 8780 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +50 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni224D +ENCODING 8781 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +40 +A0 +00 +ENDCHAR +STARTCHAR uni224E +ENCODING 8782 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +A0 +40 +00 +ENDCHAR +STARTCHAR uni224F +ENCODING 8783 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2250 +ENCODING 8784 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2251 +ENCODING 8785 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +40 +ENDCHAR +STARTCHAR uni2252 +ENCODING 8786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +00 +E0 +00 +20 +ENDCHAR +STARTCHAR uni2253 +ENCODING 8787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +00 +E0 +00 +80 +ENDCHAR +STARTCHAR uni2254 +ENCODING 8788 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +00 +B0 +00 +00 +ENDCHAR +STARTCHAR uni2255 +ENCODING 8789 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +D0 +00 +D0 +00 +00 +ENDCHAR +STARTCHAR uni2256 +ENCODING 8790 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2257 +ENCODING 8791 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2258 +ENCODING 8792 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2259 +ENCODING 8793 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225A +ENCODING 8794 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225B +ENCODING 8795 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225C +ENCODING 8796 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225D +ENCODING 8797 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225E +ENCODING 8798 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225F +ENCODING 8799 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR notequal +ENCODING 8800 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR equivalence +ENCODING 8801 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2262 +ENCODING 8802 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2263 +ENCODING 8803 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR lessequal +ENCODING 8804 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR greaterequal +ENCODING 8805 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2266 +ENCODING 8806 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2267 +ENCODING 8807 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2268 +ENCODING 8808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2269 +ENCODING 8809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni226A +ENCODING 8810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni226B +ENCODING 8811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni226C +ENCODING 8812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni226D +ENCODING 8813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR uni226E +ENCODING 8814 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +60 +80 +00 +ENDCHAR +STARTCHAR uni226F +ENCODING 8815 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +60 +C0 +80 +00 +ENDCHAR +STARTCHAR uni2270 +ENCODING 8816 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2271 +ENCODING 8817 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2272 +ENCODING 8818 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +50 +A0 +ENDCHAR +STARTCHAR uni2273 +ENCODING 8819 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2276 +ENCODING 8822 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +20 +80 +60 +C0 +ENDCHAR +STARTCHAR uni2277 +ENCODING 8823 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +80 +20 +C0 +60 +ENDCHAR +STARTCHAR uni2278 +ENCODING 8824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +60 +C0 +60 +C0 +ENDCHAR +STARTCHAR uni2279 +ENCODING 8825 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +60 +C0 +60 +ENDCHAR +STARTCHAR uni227A +ENCODING 8826 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +C0 +20 +00 +00 +ENDCHAR +STARTCHAR uni227B +ENCODING 8827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +60 +80 +00 +00 +ENDCHAR +STARTCHAR uni227C +ENCODING 8828 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227D +ENCODING 8829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +80 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227E +ENCODING 8830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni227F +ENCODING 8831 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2280 +ENCODING 8832 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2281 +ENCODING 8833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR propersubset +ENCODING 8834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +60 +00 +00 +ENDCHAR +STARTCHAR propersuperset +ENCODING 8835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +C0 +00 +00 +ENDCHAR +STARTCHAR notsubset +ENCODING 8836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2285 +ENCODING 8837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR reflexsubset +ENCODING 8838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR reflexsuperset +ENCODING 8839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2288 +ENCODING 8840 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2289 +ENCODING 8841 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +40 +ENDCHAR +STARTCHAR uni228A +ENCODING 8842 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni228B +ENCODING 8843 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +40 +E0 +80 +ENDCHAR +STARTCHAR revlogicalnot +ENCODING 8976 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +80 +00 +00 +ENDCHAR +STARTCHAR integraltp +ENCODING 8992 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR integralbt +ENCODING 8993 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +20 +20 +40 +ENDCHAR +STARTCHAR uni23BA +ENCODING 9146 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BB +ENCODING 9147 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BC +ENCODING 9148 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni23BD +ENCODING 9149 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2409 +ENCODING 9225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +70 +20 +20 +ENDCHAR +STARTCHAR uni240A +ENCODING 9226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +60 +40 +40 +ENDCHAR +STARTCHAR uni240B +ENCODING 9227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +70 +20 +20 +ENDCHAR +STARTCHAR uni240C +ENCODING 9228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +80 +60 +60 +40 +ENDCHAR +STARTCHAR uni240D +ENCODING 9229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +E0 +50 +60 +50 +ENDCHAR +STARTCHAR uni2423 +ENCODING 9251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +90 +F0 +ENDCHAR +STARTCHAR uni2424 +ENCODING 9252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +B0 +90 +20 +20 +30 +ENDCHAR +STARTCHAR SF100000 +ENCODING 9472 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2501 +ENCODING 9473 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +00 +00 +ENDCHAR +STARTCHAR SF110000 +ENCODING 9474 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni2503 +ENCODING 9475 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR uni2504 +ENCODING 9476 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2505 +ENCODING 9477 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni2506 +ENCODING 9478 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2507 +ENCODING 9479 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR uni2508 +ENCODING 9480 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2509 +ENCODING 9481 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni250A +ENCODING 9482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni250B +ENCODING 9483 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR SF010000 +ENCODING 9484 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +40 +40 +ENDCHAR +STARTCHAR uni250D +ENCODING 9485 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni250E +ENCODING 9486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR uni250F +ENCODING 9487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF030000 +ENCODING 9488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2511 +ENCODING 9489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2512 +ENCODING 9490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2513 +ENCODING 9491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF020000 +ENCODING 9492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +00 +00 +ENDCHAR +STARTCHAR uni2515 +ENCODING 9493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni2516 +ENCODING 9494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR uni2517 +ENCODING 9495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +00 +00 +ENDCHAR +STARTCHAR SF040000 +ENCODING 9496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2519 +ENCODING 9497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni251A +ENCODING 9498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR uni251B +ENCODING 9499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +00 +00 +ENDCHAR +STARTCHAR SF080000 +ENCODING 9500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +40 +40 +ENDCHAR +STARTCHAR uni251D +ENCODING 9501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni251E +ENCODING 9502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +40 +40 +ENDCHAR +STARTCHAR uni251F +ENCODING 9503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +60 +60 +ENDCHAR +STARTCHAR uni2520 +ENCODING 9504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR uni2521 +ENCODING 9505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni2522 +ENCODING 9506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +60 +60 +ENDCHAR +STARTCHAR uni2523 +ENCODING 9507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF090000 +ENCODING 9508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2525 +ENCODING 9509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2526 +ENCODING 9510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +40 +40 +ENDCHAR +STARTCHAR uni2527 +ENCODING 9511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2528 +ENCODING 9512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2529 +ENCODING 9513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +40 +40 +ENDCHAR +STARTCHAR uni252A +ENCODING 9514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR uni252B +ENCODING 9515 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF060000 +ENCODING 9516 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252D +ENCODING 9517 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252E +ENCODING 9518 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252F +ENCODING 9519 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2530 +ENCODING 9520 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2531 +ENCODING 9521 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2532 +ENCODING 9522 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2533 +ENCODING 9523 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR SF070000 +ENCODING 9524 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2535 +ENCODING 9525 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2536 +ENCODING 9526 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2537 +ENCODING 9527 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2538 +ENCODING 9528 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2539 +ENCODING 9529 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253A +ENCODING 9530 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253B +ENCODING 9531 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR SF050000 +ENCODING 9532 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253D +ENCODING 9533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253E +ENCODING 9534 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253F +ENCODING 9535 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2540 +ENCODING 9536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2541 +ENCODING 9537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2542 +ENCODING 9538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2543 +ENCODING 9539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2544 +ENCODING 9540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2545 +ENCODING 9541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2546 +ENCODING 9542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2547 +ENCODING 9543 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2548 +ENCODING 9544 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2549 +ENCODING 9545 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254A +ENCODING 9546 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254B +ENCODING 9547 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254C +ENCODING 9548 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254D +ENCODING 9549 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254E +ENCODING 9550 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +00 +40 +40 +ENDCHAR +STARTCHAR uni254F +ENCODING 9551 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +60 +00 +60 +60 +ENDCHAR +STARTCHAR SF430000 +ENCODING 9552 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF240000 +ENCODING 9553 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR SF510000 +ENCODING 9554 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF520000 +ENCODING 9555 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR SF390000 +ENCODING 9556 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF220000 +ENCODING 9557 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF210000 +ENCODING 9558 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR SF250000 +ENCODING 9559 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF500000 +ENCODING 9560 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF490000 +ENCODING 9561 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR SF380000 +ENCODING 9562 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF280000 +ENCODING 9563 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +00 +ENDCHAR +STARTCHAR SF270000 +ENCODING 9564 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR SF260000 +ENCODING 9565 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR SF360000 +ENCODING 9566 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF370000 +ENCODING 9567 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR SF420000 +ENCODING 9568 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF190000 +ENCODING 9569 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF200000 +ENCODING 9570 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR SF230000 +ENCODING 9571 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF470000 +ENCODING 9572 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +40 +ENDCHAR +STARTCHAR SF480000 +ENCODING 9573 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR SF410000 +ENCODING 9574 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR SF450000 +ENCODING 9575 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF460000 +ENCODING 9576 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR SF400000 +ENCODING 9577 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF540000 +ENCODING 9578 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +40 +F0 +40 +ENDCHAR +STARTCHAR SF530000 +ENCODING 9579 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR SF440000 +ENCODING 9580 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR uni256D +ENCODING 9581 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +30 +40 +40 +ENDCHAR +STARTCHAR uni256E +ENCODING 9582 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +80 +40 +40 +ENDCHAR +STARTCHAR uni256F +ENCODING 9583 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +80 +00 +00 +ENDCHAR +STARTCHAR uni2570 +ENCODING 9584 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +30 +00 +00 +ENDCHAR +STARTCHAR uni2571 +ENCODING 9585 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +20 +40 +40 +80 +ENDCHAR +STARTCHAR uni2572 +ENCODING 9586 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +20 +20 +10 +ENDCHAR +STARTCHAR uni2573 +ENCODING 9587 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +60 +90 +90 +ENDCHAR +STARTCHAR uni2574 +ENCODING 9588 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2575 +ENCODING 9589 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR uni2576 +ENCODING 9590 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +00 +00 +ENDCHAR +STARTCHAR uni2577 +ENCODING 9591 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +40 +40 +ENDCHAR +STARTCHAR uni2578 +ENCODING 9592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2579 +ENCODING 9593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR uni257A +ENCODING 9594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni257B +ENCODING 9595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +60 +60 +ENDCHAR +STARTCHAR uni257C +ENCODING 9596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +30 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257D +ENCODING 9597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +60 +60 +60 +ENDCHAR +STARTCHAR uni257E +ENCODING 9598 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257F +ENCODING 9599 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +40 +40 +ENDCHAR +STARTCHAR upblock +ENCODING 9600 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +00 +00 +00 +ENDCHAR +STARTCHAR uni2581 +ENCODING 9601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2582 +ENCODING 9602 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F8 +ENDCHAR +STARTCHAR uni2583 +ENCODING 9603 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F8 +F8 +ENDCHAR +STARTCHAR dnblock +ENCODING 9604 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2585 +ENCODING 9605 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2586 +ENCODING 9606 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2587 +ENCODING 9607 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR block +ENCODING 9608 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2589 +ENCODING 9609 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +F0 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR uni258A +ENCODING 9610 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR uni258B +ENCODING 9611 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR lfblock +ENCODING 9612 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258D +ENCODING 9613 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258E +ENCODING 9614 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni258F +ENCODING 9615 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR rtblock +ENCODING 9616 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR ltshade +ENCODING 9617 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +80 +20 +80 +20 +ENDCHAR +STARTCHAR shade +ENCODING 9618 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A8 +50 +A8 +50 +A8 +50 +ENDCHAR +STARTCHAR dkshade +ENCODING 9619 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B8 +E8 +B8 +E8 +B8 +E8 +ENDCHAR +STARTCHAR uni2594 +ENCODING 9620 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni2595 +ENCODING 9621 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR filledbox +ENCODING 9632 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR H22073 +ENCODING 9633 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uni25C6 +ENCODING 9670 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR spade +ENCODING 9824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR club +ENCODING 9827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +E0 +00 +ENDCHAR +STARTCHAR heart +ENCODING 9829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR diamond +ENCODING 9830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2669 +ENCODING 9833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnote +ENCODING 9834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnotedbl +ENCODING 9835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +50 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266C +ENCODING 9836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +70 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266D +ENCODING 9837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni266E +ENCODING 9838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +A0 +E0 +20 +00 +ENDCHAR +STARTCHAR uni266F +ENCODING 9839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uniFFFD +ENCODING 65533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +90 +D0 +F0 +D0 +F0 +ENDCHAR +ENDFONT diff --git a/src/col64/cruft/col64font.hex b/src/col64/cruft/col64font.hex new file mode 100644 index 0000000..6b88e9b --- /dev/null +++ b/src/col64/cruft/col64font.hex @@ -0,0 +1,920 @@ +0000:A000A000A000 +0020:000000000000 +0021:404040004000 +0022:A0A000000000 +0023:A0F0A0F0A000 +0024:70A06050E000 +0025:009020409000 +0026:40A040A0D000 +0027:202040000000 +0028:204040402000 +0029:402020204000 +002A:A040E040A000 +002B:4040E0404000 +002C:000000204000 +002D:0000F0000000 +002E:000000004000 +002F:202040808000 +0030:6090B0D06000 +0031:40C04040E000 +0032:60902040F000 +0033:E0106010E000 +0034:2060A0F02000 +0035:F080E010E000 +0036:7080E0906000 +0037:F01020404000 +0038:609060906000 +0039:60907010E000 +003A:004000004000 +003B:002000204000 +003C:204080402000 +003D:00F000F00000 +003E:804020408000 +003F:709020002000 +0040:60B0B0806000 +0041:6090F0909000 +0042:E090E090E000 +0043:609080906000 +0044:E0909090E000 +0045:F080E080F000 +0046:F080E0808000 +0047:7080B0906000 +0048:9090F0909000 +0049:E0404040E000 +004A:301010906000 +004B:90A0C0A09000 +004C:80808080F000 +004D:A0F0D0909000 +004E:90D0B0909000 +004F:609090906000 +0050:E090E0808000 +0051:609090A05000 +0052:E090E0A09000 +0053:70806010E000 +0054:F04040404000 +0055:909090906000 +0056:909090A04000 +0057:9090D0F0A000 +0058:909060909000 +0059:909060204000 +005A:F0204080F000 +005B:604040406000 +005C:808040202000 +005D:602020206000 +005E:40A000000000 +005F:00000000F000 +0060:404020000000 +0061:003050907000 +0062:8080E090E000 +0063:007080807000 +0064:101070907000 +0065:006090A07000 +0066:6040E0404000 +0067:709070106000 +0068:8080E0909000 +0069:4000C040E000 +006A:20006020C000 +006B:80A0C0A09000 +006C:C0404040E000 +006D:00A0F0D09000 +006E:00E090909000 +006F:006090906000 +0070:00E090E08000 +0071:007090701000 +0072:00A0D0808000 +0073:0070C030E000 +0074:40E040402000 +0075:009090906000 +0076:009090A04000 +0077:0090D0F0A000 +0078:009060609000 +0079:00906020C000 +007A:00F02040F000 +007B:604080406000 +007C:404040404000 +007D:C0402040C000 +007E:0050A0000000 +007F:B0900090D000 +00A0:000000000000 +00A1:400040404000 +00A2:40E080E04000 +00A3:20406040A000 +00A4:009060609000 +00A5:A040E0404000 +00A6:404000404000 +00A7:60C0A06020C0 +00A8:A00000000000 +00A9:6090D0D09060 +00AA:60A06000E000 +00AB:0050A0500000 +00AC:0000E0200000 +00AD:0000E0000000 +00AE:60F0D0600000 +00AF:E00000000000 +00B0:40A040000000 +00B1:40E04000E000 +00B2:C04080C00000 +00B3:C04080408000 +00B4:204000000000 +00B5:00A0A0A0C080 +00B6:70D0D0505000 +00B7:000040000000 +00B8:000000204000 +00B9:40C040400000 +00BA:40A04000E000 +00BB:00A050A00000 +00BC:808080507010 +00BD:8080B0102030 +00BE:C0408050B010 +00BF:400040806000 +00C0:8040A0E0A000 +00C1:2040A0E0A000 +00C2:C040A0E0A000 +00C3:60C0A0E0A000 +00C4:A040A0E0A000 +00C5:4040A0E0A000 +00C6:70A0F0A0B000 +00C7:40A080A04080 +00C8:80E0C080E000 +00C9:20E0C080E000 +00CA:60E0C080E000 +00CB:A0E0C080E000 +00CC:80E04040E000 +00CD:20E04040E000 +00CE:40E04040E000 +00CF:A0404040E000 +00D0:E050D050E000 +00D1:50A0E0E0A000 +00D2:8040A0A04000 +00D3:2040A0A04000 +00D4:4040A0A04000 +00D5:70E0A0A04000 +00D6:A040A0A04000 +00D7:00A040A00000 +00D8:60A0E0A0C000 +00D9:8040A0A0E000 +00DA:2040A0A0E000 +00DB:4000A0A0E000 +00DC:A000A0A0E000 +00DD:2000A0404000 +00DE:80C0A0C08000 +00DF:40A0C0A0E080 +00E0:804060A06000 +00E1:204060A06000 +00E2:600060A06000 +00E3:50A060A06000 +00E4:A00060A06000 +00E5:400060A06000 +00E6:0070B0A07000 +00E7:0040A0806040 +00E8:8040A0C06000 +00E9:2040A0C06000 +00EA:C040A0C06000 +00EB:A040A0C06000 +00EC:80404040E000 +00ED:20C04040E000 +00EE:40A04040E000 +00EF:A000C040E000 +00F0:A04060A04000 +00F1:50A0C0A0A000 +00F2:804040A04000 +00F3:204040A04000 +00F4:400040A04000 +00F5:E00040A04000 +00F6:A00040A04000 +00F7:4000E0004000 +00F8:0060A0A0C000 +00F9:8040A0A06000 +00FA:2040A0A06000 +00FB:4000A0A06000 +00FC:A000A0A06000 +00FD:2040A0E020C0 +00FE:8080C0A0C080 +00FF:A000A0E020C0 +0100:E040A0E0A000 +0101:E00060A06000 +0102:A040A0E0A000 +0103:A04060A06000 +0104:0040A0E0A020 +0105:000060A06020 +0106:60A080A04000 +0107:2040A0806000 +0108:E0A080A04000 +0109:600060806000 +010A:40E080A04000 +010B:400060806000 +010C:E0A080A04000 +010D:A04060806000 +010E:E0C0A0A0C000 +010F:302060A06000 +0110:C0A0E0A0C000 +0111:602060A06000 +0112:E0E0C080E000 +0113:E040A0C06000 +0114:A0E0C080E000 +0115:A040A0C06000 +0116:40E0C080E000 +0117:4040A0C06000 +0118:E080C080E020 +0119:0040A0C06040 +011A:A0E0C080E000 +011B:A040A0C06000 +011C:606080A06000 +011D:6060A06020C0 +011E:A06080A06000 +011F:A040A06020C0 +0120:406080A06000 +0121:4060A06020C0 +0122:6080A0A04040 +0123:4060A06020C0 +0124:6000A0E0A000 +0125:40A0C0A0A000 +0126:A0E0A0E0A000 +0127:80C0C0A0A000 +0128:50A04040E000 +0129:50A0C040E000 +012A:E000E040E000 +012B:E000C040E000 +012C:A040E040E000 +012D:A040C040E000 +012E:E0404040E020 +012F:4000C040E020 +0130:4000E040E000 +0131:0000C040E000 +0132:80A0A0A02060 +0133:A000A0A02040 +0134:60A020A04000 +0135:40A0002020C0 +0136:A0A0C0A02040 +0137:80A0C0A02040 +0138:00A0A0C0A000 +0139:40808080E000 +013A:20C04040E000 +013B:80808080E020 +013C:C0404040E020 +013D:A0C08080E000 +013E:D0404040E000 +013F:8080A080E000 +0140:C0405040E000 +0141:80A0C080E000 +0142:C060C040E000 +0143:20A0E0A08000 +0144:2040C0A0A000 +0145:20A0E0A08020 +0146:00C0A0A00040 +0147:20A0E0A08000 +0148:A040C0A0A000 +0149:8000C0A0A000 +014A:A0E0E0A02040 +014B:00C0A0A02040 +014C:E040A0A04000 +014D:E00040A04000 +014E:A040A0A04000 +014F:A04040A04000 +0150:A040A0A04000 +0151:A0A040A04000 +0152:50A0B0A07000 +0153:0070B0A07000 +0154:20C0A0C0A000 +0155:2000A0C08000 +0156:C0A0C0A00040 +0157:00A0C0808020 +0158:60C0A0C0A000 +0159:6000A0C08000 +015A:2060C020C000 +015B:2060C020C000 +015C:6060C020C000 +015D:6060C020C000 +015E:60804020C040 +015F:0060C020E040 +0160:6060C020E000 +0161:6060C020C000 +0162:E04040402040 +0163:40E040402040 +0164:A040E0404000 +0165:A040E0402000 +0166:E040E0404000 +0167:E040E0402000 +0168:D020A0A0E000 +0169:50A000A06000 +016A:E000A0A0E000 +016B:E000A0A06000 +016C:A040A0A0E000 +016D:A04000A06000 +016E:4000A0A0E000 +016F:4000A0A06000 +0170:A000A0A0E000 +0171:A000A0A06000 +0172:00A0A0A04020 +0173:00A0A0A06040 +0174:40A0A0E0A000 +0175:4000A0E0E000 +0176:6000A0404000 +0177:4000A0408000 +0178:A000A0404000 +0179:40E04080E000 +017A:40E04080E000 +017B:40E04080E000 +017C:40E04080E000 +017D:A0E04080E000 +017E:A0E04080E000 +017F:2040C0404000 +018F:00C060A04000 +0192:2040E0404080 +0218:60804020C040 +0219:0060C020E040 +021A:E04040400040 +021B:40E040402040 +0259:00C060A04000 +02C6:40A000000000 +02C7:A04000000000 +02C9:E00000000000 +02D8:906000000000 +02D9:400000000000 +02DA:40A040000000 +02DB:0000004080C0 +02DC:50A000000000 +02DD:A0A000000000 +0374:204000000000 +0375:000000004080 +037A:000000004060 +037E:004000004080 +0384:204000000000 +0385:B04000000000 +0386:C0A0E0A0A000 +0387:000040000000 +0388:E0C060406000 +0389:A020E0A0A000 +038A:E0C04040E000 +038C:C0A0A0A04000 +038E:A0A0C0404000 +038F:C0A0A040A000 +0390:B04000402000 +0391:40A0E0A0A000 +0392:C0A0C0A0C000 +0393:E08080808000 +0394:4040A0A0E000 +0395:E080C080E000 +0396:E0204080E000 +0397:A0A0E0A0A000 +0398:40A0E0A04000 +0399:E0404040E000 +039A:A0A0C0A0A000 +039B:4040A0A0A000 +039C:A0E0A0A0A000 +039D:20A0E0A08000 +039E:E0004000E000 +039F:40A0A0A04000 +03A0:E0A0A0A0A000 +03A1:C0A0C0808000 +03A3:E0804080E000 +03A4:E04040404000 +03A5:A0A040404000 +03A6:40E0A0E04000 +03A7:A0A040A0A000 +03A8:A0E0E0404000 +03A9:40A0A040A000 +03AA:A000E040E000 +03AB:A000A0404000 +03AC:408060A06000 +03AD:20C040806000 +03AE:2040C0A02040 +03AF:200040402000 +03B0:B040A0A0C000 +03B1:0050A0A05000 +03B2:40A0C0A0C000 +03B3:00A060404000 +03B4:608040A04000 +03B5:00E0C0806000 +03B6:E04080E02040 +03B7:00C0A0A02040 +03B8:40A0E0A04000 +03B9:004040402000 +03BA:00A0A0C0A000 +03BB:C02060A0A000 +03BC:00A0A0A0C080 +03BD:00A0A0604000 +03BE:60A040806000 +03BF:0040A0A04000 +03C0:00E0A0A0A000 +03C1:0040A0A0C080 +03C2:00608040C000 +03C3:0060C0A04000 +03C4:00E040402000 +03C5:0080A0A0C000 +03C6:0040E0A04040 +03C7:00A04060A000 +03C8:00A0E0E04000 +03C9:00A0A0E0E000 +03CA:A00040402000 +03CB:A000A0A0C000 +03CC:204040A04000 +03CD:2000A0A0C000 +03CE:2000A0E0E000 +0401:A0E0C080E000 +0402:E080C0A0A000 +0403:20E080808000 +0404:6080C0806000 +0405:60804020C000 +0406:E0404040E000 +0407:A0E04040E000 +0408:202020A04000 +0409:E060A0B0B000 +040A:A0A0E0B0B000 +040B:C080C0A0A000 +040C:2080A0C0A000 +040E:A04000A04080 +040F:A0A0A0A0E040 +0410:40A0E0A0A000 +0411:E080C0A0C000 +0412:C0A0C0A0C000 +0413:E08080808000 +0414:E060A0A0E0A0 +0415:E080C080E000 +0416:A0E040E0A000 +0417:C0204020C000 +0418:80A0E0A02000 +0419:6080A0E0A020 +041A:A0A0C0A0A000 +041B:60A0A0A0A000 +041C:A0E0A0A0A000 +041D:A0A0E0A0A000 +041E:40A0A0A04000 +041F:E0A0A0A0A000 +0420:C0A0C0808000 +0421:40A080A04000 +0422:E04040404000 +0423:A0A0A0404080 +0424:40E0A0E04000 +0425:A0A040A0A000 +0426:A0A0A0A0E000 +0427:A0A060202000 +0428:A0A0E0E0E000 +0429:A0A0E0E0F010 +042A:C04060506000 +042B:9090D0B0D000 +042C:8080C0A0C000 +042D:C0206020C000 +042E:A0D0D0D0A000 +042F:60A060A0A000 +0430:0060A0A06000 +0431:6080E0A04000 +0432:00E0C0A0C000 +0433:00E080808000 +0434:0060A0A0E0A0 +0435:0040A0C06000 +0436:00B06060B000 +0437:00E04020C000 +0438:00A0E0E0A000 +0439:A040A0E0A000 +043A:00A0A0C0A000 +043B:0060A0A0A000 +043C:00A0E0A0A000 +043D:00A0E0A0A000 +043E:0040A0A04000 +043F:00E0A0A0A000 +0440:00C0A0C08080 +0441:006080806000 +0442:00E040404000 +0443:00A0A06020C0 +0444:4040A0A04040 +0445:00A04040A000 +0446:00A0A0A0E020 +0447:00A0A0602000 +0448:00A0E0E0E000 +0449:00A0E0E0F010 +044A:00C060506000 +044B:0090D0B0D000 +044C:0080C0A0C000 +044D:00C06020C000 +044E:00A0D0D0A000 +044F:0060A060A000 +0451:A040A0C06000 +0452:80C080C0A020 +0453:2040E0808000 +0454:0060C0806000 +0455:0060C020C000 +0456:4000C040E000 +0457:A000C040E000 +0458:2000202020C0 +0459:0060A0B0B000 +045A:00A0E0B0B000 +045B:80C080C0A000 +045C:2080A0C0A000 +045E:A04000A04080 +045F:00A0A0A0E040 +0490:20E080808000 +0491:0020E0808000 +0492:6040E0404000 +0493:006040E04000 +05D0:00A060C0A000 +05D1:00E02020F000 +05D2:80404040A000 +05D3:00E020202000 +05D4:80E020A0A000 +05D5:402020202000 +05D6:806040404000 +05D7:00E0A0A0A000 +05D8:A0A0A0A0C000 +05D9:C02020000000 +05DA:00E020202020 +05DB:00E02020C000 +05DC:80E020204000 +05DD:8060A0A0E000 +05DE:8060A0A0A000 +05DF:806020202000 +05E0:402020206000 +05E1:8060A0A04000 +05E2:A0A0A060C000 +05E3:00E0A0202020 +05E4:00E0A020E000 +05E5:00A0A0C08080 +05E6:00A04020E000 +05E7:00E020C08080 +05E8:00C020202000 +05E9:00F0D0A0E000 +05EA:8060A0A0A000 +1E02:40E0C0A0C000 +1E03:A080C0A0C000 +1E0A:40C0A0A0C000 +1E0B:A02060A06000 +1E1E:40E080C08000 +1E1F:802040E04000 +1E40:4000E0A0A000 +1E41:4000A0E0A000 +1E56:40C0A0C08000 +1E57:4000C0A0C080 +1E60:40E0C020C000 +1E61:4060C020C000 +1E6A:40E040404000 +1E6B:400040E04020 +1E80:8020A0E0E000 +1E81:8040A0A0E000 +1E82:2080A0E0E000 +1E83:2040A0A0E000 +1E84:A000A0E0E000 +1E85:A000A0E0E000 +1EF2:8020A0404000 +1EF3:8040A0602040 +2010:000060000000 +2011:000060000000 +2012:0000E0000000 +2013:0000E0000000 +2014:0000F0000000 +2015:0000F0000000 +2016:A0A0A0A0A0A0 +2017:000000F000F0 +2018:204060000000 +2019:602040000000 +201A:000000602040 +201B:604020000000 +201C:50A0A0000000 +201D:5050A0000000 +201E:0000005050A0 +201F:A0A050000000 +2020:40E040404000 +2021:40E040E04000 +2022:0040E0400000 +2023:00C0E0C00000 +2024:000000004000 +2025:00000000A000 +2026:00000000B000 +2027:000040000000 +2030:802040803000 +2039:004080400000 +203A:004020400000 +203E:F80000000000 +207F:00C0A0A00000 +20A7:60F060404000 +20AC:2040E0402000 +2116:C0B0B0A0B000 +2122:E04000E0A000 +2126:40A0A040A000 +2127:A040A0A04000 +215B:8080B0205020 +215C:C040B060D020 +215D:C08070A05020 +215E:C040B0A05020 +2190:0040F0400000 +2191:0040E0404000 +2192:0020F0200000 +2193:004040E04000 +2194:0050F0500000 +2195:40E040E04000 +2200:A0A0E0A04000 +2201:40A080A04000 +2202:C02060A04000 +2203:E020E020E000 +2204:F020E060E080 +2205:2060A0A0C080 +2206:4040A0A0E000 +2207:E0A0A0404000 +2208:6080E0806000 +2209:70A0E0A06040 +220A:4080C0804000 +220B:C020E020C000 +220C:D020E060C080 +220D:8040C0408000 +220E:C0C0C0C0C000 +220F:E0A0A0A0A000 +2210:A0A0A0A0E000 +2211:E0804080E000 +2212:0000E0000000 +2213:E00040E04000 +2214:400040E04000 +2215:202040808000 +2216:808040202000 +2217:20A070E05040 +2218:0040A0400000 +2219:0040E0400000 +221A:302020A06000 +221B:D050D0105030 +221C:D0D050105030 +221D:000050E05000 +221E:0020D0B04000 +221F:00008080E000 +2220:00204080E000 +2221:10A040A0F020 +2222:9060A0A06090 +2223:404040404000 +2224:406040C04000 +2225:A0A0A0A0A000 +2226:A0B0E0A0A000 +2227:004040A0A000 +2228:00A0A0404000 +2229:0040A0A0A000 +222A:00A0A0A04000 +222B:204040404080 +222C:50A0A0A0A080 +222D:50D0D0D0D0A0 +222E:2040E0E04080 +222F:50A0E0E0A080 +2230:50D0F0F0D0A0 +2231:2040E0504080 +2232:2040E0C04080 +2233:2040C0E04080 +2234:00004000A000 +2235:0000A0004000 +2236:000040004000 +2237:0000A000A000 +2238:004000E00000 +2239:000020C02000 +223A:A000E000A000 +223B:200050A00040 +223C:000050A00000 +223D:0000A0500000 +223E:0000D0B00000 +223F:004050A02000 +2240:402040402000 +2241:1020B0D04080 +2242:00E000A05000 +2243:0050A000E000 +2244:20D0B040F040 +2245:50A000E000E0 +2246:50A020F040F0 +2247:70A020F040F0 +2248:50A00050A000 +2249:70A04050E080 +224A:40B040B000F0 +224B:40B040B040B0 +224C:A05000E000E0 +224D:A0400040A000 +224E:40A000A04000 +224F:40A000E00000 +2250:4000E000E000 +2251:40E000E00040 +2252:80E000E00020 +2253:20E000E00080 +2254:00B000B00000 +2255:00D000D00000 +2256:00E040E00000 +2257:40E000E00000 +2258:40E000E00000 +2259:40E000E00000 +225A:A0E000E00000 +225B:40E000E00000 +225C:40E000E00000 +225D:4000E000E000 +225E:4000E000E000 +225F:4000E000E000 +2260:20E040E08000 +2261:E000E000E000 +2262:E020E040E080 +2263:E000E000E000 +2264:2040E000E000 +2265:8040E000E000 +2266:2040E000E000 +2267:8040E000E000 +2268:002040E00000 +2269:008040E00000 +226A:0050A0500000 +226B:00A050A00000 +226C:A040A040A000 +226D:20E040E08000 +226E:2060C0608000 +226F:20C060C08000 +2270:2040E040E080 +2271:A060E040E080 +2272:2040E00050A0 +2273:8040E000A050 +2276:60C0208060C0 +2277:C0608020C060 +2278:60C060C060C0 +2279:C060C060C060 +227A:0020C0200000 +227B:008060800000 +227C:20C02000E000 +227D:80608000E000 +227E:20C02000A050 +227F:20C02000A050 +2280:4060C0604000 +2281:40C060C04000 +2282:006080600000 +2283:00C020C00000 +2284:4060C0604000 +2285:40C060C04000 +2286:60806000E000 +2287:C020C000E000 +2288:60A06040E080 +2289:C060C040E040 +228A:60806040E080 +228B:C020C040E080 +2310:0000E0800000 +2320:204040404040 +2321:202020202040 +23BA:F00000000000 +23BB:00F000000000 +23BC:000000F00000 +23BD:0000000000F0 +2409:A0E0A0702020 +240A:8080E0604040 +240B:A0A040702020 +240C:C0C080606040 +240D:E080E0506050 +2423:0000000090F0 +2424:D0B090202030 +2500:000000F00000 +2501:0000F8F80000 +2502:404040404040 +2503:606060606060 +2504:000000A00000 +2505:0000A8A80000 +2506:400040004000 +2507:600060006000 +2508:000000A00000 +2509:0000A8A80000 +250A:400040004000 +250B:600060006000 +250C:000000704040 +250D:000070704040 +250E:000000706060 +250F:000070706060 +2510:000000C04040 +2511:0000C0C04040 +2512:000000E06060 +2513:0000E0E06060 +2514:404040700000 +2515:404070700000 +2516:606060700000 +2517:606070700000 +2518:404040C00000 +2519:4040C0C00000 +251A:606060E00000 +251B:6060E0E00000 +251C:404040704040 +251D:404070704040 +251E:606060704040 +251F:404040706060 +2520:606060706060 +2521:606070704040 +2522:404070706060 +2523:606070706060 +2524:404040C04040 +2525:4040C0C04040 +2526:606060E04040 +2527:404040E06060 +2528:606060E06060 +2529:6060E0E04040 +252A:4040E0E06060 +252B:6060E0E06060 +252C:000000F04040 +252D:0000C0F04040 +252E:000070F04040 +252F:0000F0F04040 +2530:000000F06060 +2531:0000E0F06060 +2532:000070F06060 +2533:0000F0F06060 +2534:404040F00000 +2535:4040C0F00000 +2536:404070F00000 +2537:4040F0F00000 +2538:606060F00000 +2539:6060E0F00000 +253A:606070F00000 +253B:6060F0F00000 +253C:404040F04040 +253D:4040C0F04040 +253E:404070F04040 +253F:4040F0F04040 +2540:606060F04040 +2541:404040F06060 +2542:606060F06060 +2543:6060E0F04040 +2544:606070F04040 +2545:4040E0F06060 +2546:404070F06060 +2547:6060F0F04040 +2548:4040F0F06060 +2549:6060E0F06060 +254A:606070F06060 +254B:6060F0F06060 +254C:000000A00000 +254D:0000A0A00000 +254E:004040004040 +254F:006060006060 +2550:0000F000F000 +2551:606060606060 +2552:000070407040 +2553:000000706060 +2554:000070407060 +2555:0000C040C040 +2556:000000E06060 +2557:0000E020E060 +2558:404070407000 +2559:606060700000 +255A:606070407000 +255B:4040C040C000 +255C:606060E00000 +255D:6060E020E000 +255E:404070407040 +255F:606060706060 +2560:606070407060 +2561:4040C040C040 +2562:606060E06060 +2563:6060E020E060 +2564:0000F000F040 +2565:000000F06060 +2566:0000F000F060 +2567:4040F000F000 +2568:606060F00000 +2569:6060F000F000 +256A:4040F040F040 +256B:606060F06060 +256C:6060F000F060 +256D:000000304040 +256E:000000804040 +256F:404040800000 +2570:404040300000 +2571:102020404080 +2572:804040202010 +2573:909060609090 +2574:000000C00000 +2575:404040400000 +2576:000000700000 +2577:000000404040 +2578:0000C0C00000 +2579:606060600000 +257A:000070700000 +257B:000000606060 +257C:000030F00000 +257D:404040606060 +257E:0000C0F00000 +257F:606060604040 +2580:F8F8F8000000 +2581:0000000000F0 +2582:0000000000F8 +2583:00000000F8F8 +2584:000000F8F8F8 +2585:000000F8F8F8 +2586:0000F8F8F8F8 +2587:00F8F8F8F8F8 +2588:F8F8F8F8F8F8 +2589:F0F0F0F0F0F0 +258A:E0E0E0E0E0E0 +258B:E0E0E0E0E0E0 +258C:C0C0C0C0C0C0 +258D:C0C0C0C0C0C0 +258E:808080808080 +258F:808080808080 +2590:303030303030 +2591:802080208020 +2592:A850A850A850 +2593:B8E8B8E8B8E8 +2594:F80000000000 +2595:101010101010 +25A0:0000E0E0E000 +25A1:0000E0A0E000 +25C6:0040E0E04000 +2660:40E0E040E000 +2663:0040A040E000 +2665:00A0E0E04000 +2666:0040E0400000 +2669:404040C08000 +266A:406040C08000 +266B:70505050A000 +266C:70705050A000 +266D:8080E0A0C000 +266E:80E0A0E02000 +266F:A0E0A0E0A000 +FFFD:F090D0F0D0F0 diff --git a/src/col64/cruft/col64font_almost.bdf b/src/col64/cruft/col64font_almost.bdf new file mode 100644 index 0000000..9ff776c --- /dev/null +++ b/src/col64/cruft/col64font_almost.bdf @@ -0,0 +1,11994 @@ +STARTFONT 2.1 +COMMENT Contributed by Janne V. Kujala +COMMENT $Id: 4x6.bdf,v 1.5 2002-08-26 18:05:49+01 mgk25 Rel $ +COMMENT Send bug reports to Markus Kuhn +FONT -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1 +SIZE 6 75 75 +FONTBOUNDINGBOX 4 6 0 -1 +STARTPROPERTIES 23 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 6 +POINT_SIZE 60 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 40 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 5 +FONT_DESCENT 1 +DESTINATION 1 +COPYRIGHT "Public domain font. Share and enjoy." +CAP_HEIGHT 5 +X_HEIGHT 4 +DEFAULT_CHAR 0 +_GBDFED_INFO "Edited with gbdfed 1.4." +ENDPROPERTIES +CHARS 920 +STARTCHAR char0 +ENCODING 0 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR space +ENCODING 32 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +00 +40 +00 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +A0 +F0 +A0 +00 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +60 +50 +E0 +00 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +20 +40 +90 +00 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +A0 +D0 +00 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +40 +00 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +A0 +00 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +B0 +D0 +60 +00 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +10 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +F0 +20 +00 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +10 +E0 +00 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +E0 +90 +60 +00 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +10 +20 +40 +40 +00 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +60 +90 +60 +00 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +70 +10 +E0 +00 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +00 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +00 +20 +40 +00 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +80 +40 +20 +00 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +20 +40 +80 +00 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +20 +00 +20 +00 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +B0 +B0 +80 +60 +00 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +80 +90 +60 +00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +90 +90 +E0 +00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +F0 +00 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +B0 +90 +60 +00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +10 +10 +90 +60 +00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +F0 +00 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +D0 +90 +90 +00 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +D0 +B0 +90 +90 +00 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +A0 +50 +00 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +A0 +90 +00 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +90 +90 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +40 +40 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +40 +80 +F0 +00 +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +40 +40 +60 +00 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F0 +00 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +10 +70 +90 +70 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +80 +80 +70 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +70 +90 +70 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +A0 +70 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +70 +10 +60 +00 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +90 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +F0 +D0 +90 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +E0 +80 +00 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +90 +70 +10 +00 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +80 +80 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +C0 +30 +E0 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +80 +40 +60 +00 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +20 +40 +C0 +00 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR char127 +ENCODING 127 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +90 +00 +90 +D0 +00 +ENDCHAR +STARTCHAR space +ENCODING 160 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +40 +40 +00 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +E0 +40 +00 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +40 +A0 +00 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +00 +40 +40 +00 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +D0 +D0 +90 +60 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +00 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 173 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +D0 +60 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +C0 +00 +00 +ENDCHAR +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +40 +80 +00 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +D0 +D0 +50 +50 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +00 +00 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +50 +70 +10 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +10 +20 +30 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +50 +B0 +10 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +80 +60 +00 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +F0 +A0 +B0 +00 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +80 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +50 +D0 +50 +E0 +00 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +E0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +A0 +00 +00 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +E0 +80 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +80 +60 +40 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +40 +00 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR Amacron +ENCODING 256 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR amacron +ENCODING 257 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Abreve +ENCODING 258 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR abreve +ENCODING 259 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Aogonek +ENCODING 260 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR aogonek +ENCODING 261 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +A0 +60 +20 +ENDCHAR +STARTCHAR Cacute +ENCODING 262 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cacute +ENCODING 263 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +80 +60 +00 +ENDCHAR +STARTCHAR Ccircumflex +ENCODING 264 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccircumflex +ENCODING 265 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Cdotaccent +ENCODING 266 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cdotaccent +ENCODING 267 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Ccaron +ENCODING 268 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccaron +ENCODING 269 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Dcaron +ENCODING 270 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcaron +ENCODING 271 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Dcroat +ENCODING 272 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcroat +ENCODING 273 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Emacron +ENCODING 274 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR emacron +ENCODING 275 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Ebreve +ENCODING 276 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ebreve +ENCODING 277 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Edotaccent +ENCODING 278 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR edotaccent +ENCODING 279 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Eogonek +ENCODING 280 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +20 +ENDCHAR +STARTCHAR eogonek +ENCODING 281 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +40 +ENDCHAR +STARTCHAR Ecaron +ENCODING 282 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ecaron +ENCODING 283 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Gcircumflex +ENCODING 284 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gcircumflex +ENCODING 285 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gbreve +ENCODING 286 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gbreve +ENCODING 287 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gdotaccent +ENCODING 288 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gdotaccent +ENCODING 289 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gcommaaccent +ENCODING 290 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR gcommaaccent +ENCODING 291 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Hcircumflex +ENCODING 292 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hcircumflex +ENCODING 293 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Hbar +ENCODING 294 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hbar +ENCODING 295 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Itilde +ENCODING 296 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR itilde +ENCODING 297 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Imacron +ENCODING 298 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR imacron +ENCODING 299 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Ibreve +ENCODING 300 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR ibreve +ENCODING 301 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Iogonek +ENCODING 302 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR iogonek +ENCODING 303 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +20 +ENDCHAR +STARTCHAR Idotaccent +ENCODING 304 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR IJ +ENCODING 306 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +A0 +A0 +20 +60 +ENDCHAR +STARTCHAR ij +ENCODING 307 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Jcircumflex +ENCODING 308 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR jcircumflex +ENCODING 309 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +20 +20 +C0 +ENDCHAR +STARTCHAR Kcommaaccent +ENCODING 310 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kcommaaccent +ENCODING 311 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kgreenlandic +ENCODING 312 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR Lacute +ENCODING 313 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lacute +ENCODING 314 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Lcommaaccent +ENCODING 315 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR lcommaaccent +ENCODING 316 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR Lcaron +ENCODING 317 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +C0 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lcaron +ENCODING 318 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Ldot +ENCODING 319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +A0 +80 +E0 +00 +ENDCHAR +STARTCHAR ldot +ENCODING 320 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +50 +40 +E0 +00 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Nacute +ENCODING 323 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR nacute +ENCODING 324 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Ncommaaccent +ENCODING 325 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +20 +ENDCHAR +STARTCHAR ncommaaccent +ENCODING 326 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +40 +ENDCHAR +STARTCHAR Ncaron +ENCODING 327 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR ncaron +ENCODING 328 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR napostrophe +ENCODING 329 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +00 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Eng +ENCODING 330 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +A0 +20 +40 +ENDCHAR +STARTCHAR eng +ENCODING 331 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Omacron +ENCODING 332 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR omacron +ENCODING 333 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Obreve +ENCODING 334 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR obreve +ENCODING 335 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Ohungarumlaut +ENCODING 336 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR ohungarumlaut +ENCODING 337 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR Racute +ENCODING 340 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR racute +ENCODING 341 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Rcommaaccent +ENCODING 342 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +00 +40 +ENDCHAR +STARTCHAR rcommaaccent +ENCODING 343 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +C0 +80 +80 +20 +ENDCHAR +STARTCHAR Rcaron +ENCODING 344 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR rcaron +ENCODING 345 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Sacute +ENCODING 346 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR sacute +ENCODING 347 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scircumflex +ENCODING 348 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR scircumflex +ENCODING 349 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scedilla +ENCODING 350 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scedilla +ENCODING 351 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +E0 +00 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 354 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +20 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 355 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR Tcaron +ENCODING 356 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tcaron +ENCODING 357 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Tbar +ENCODING 358 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tbar +ENCODING 359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Utilde +ENCODING 360 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR utilde +ENCODING 361 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Umacron +ENCODING 362 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR umacron +ENCODING 363 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Ubreve +ENCODING 364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR ubreve +ENCODING 365 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Uring +ENCODING 366 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uring +ENCODING 367 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uhungarumlaut +ENCODING 368 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uhungarumlaut +ENCODING 369 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uogonek +ENCODING 370 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +20 +ENDCHAR +STARTCHAR uogonek +ENCODING 371 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +60 +40 +ENDCHAR +STARTCHAR Wcircumflex +ENCODING 372 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR wcircumflex +ENCODING 373 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ycircumflex +ENCODING 374 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ycircumflex +ENCODING 375 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +40 +80 +00 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Zacute +ENCODING 377 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zacute +ENCODING 378 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zdotaccent +ENCODING 379 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zdotaccent +ENCODING 380 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR longs +ENCODING 383 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR uni018F +ENCODING 399 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR florin +ENCODING 402 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +40 +80 +ENDCHAR +STARTCHAR Scommaaccent +ENCODING 536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scommaaccent +ENCODING 537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +00 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR uni0259 +ENCODING 601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR circumflex +ENCODING 710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR caron +ENCODING 711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR breve +ENCODING 728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dotaccent +ENCODING 729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ring +ENCODING 730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR ogonek +ENCODING 731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +80 +C0 +ENDCHAR +STARTCHAR tilde +ENCODING 732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR hungarumlaut +ENCODING 733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0374 +ENCODING 884 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0375 +ENCODING 885 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +80 +ENDCHAR +STARTCHAR uni037A +ENCODING 890 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +60 +ENDCHAR +STARTCHAR uni037E +ENCODING 894 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +80 +ENDCHAR +STARTCHAR tonos +ENCODING 900 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dieresistonos +ENCODING 901 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Alphatonos +ENCODING 902 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR anoteleia +ENCODING 903 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR Epsilontonos +ENCODING 904 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +60 +40 +60 +00 +ENDCHAR +STARTCHAR Etatonos +ENCODING 905 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Iotatonos +ENCODING 906 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Omicrontonos +ENCODING 908 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Upsilontonos +ENCODING 910 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR Omegatonos +ENCODING 911 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR iotadieresistonos +ENCODING 912 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +40 +20 +00 +ENDCHAR +STARTCHAR Alpha +ENCODING 913 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Beta +ENCODING 914 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Gamma +ENCODING 915 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR Delta +ENCODING 916 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Epsilon +ENCODING 917 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Zeta +ENCODING 918 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Eta +ENCODING 919 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Theta +ENCODING 920 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR Iota +ENCODING 921 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Kappa +ENCODING 922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Lambda +ENCODING 923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Mu +ENCODING 924 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Nu +ENCODING 925 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR Xi +ENCODING 926 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR Omicron +ENCODING 927 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Pi +ENCODING 928 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Rho +ENCODING 929 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR Sigma +ENCODING 931 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Tau +ENCODING 932 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Upsilon +ENCODING 933 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Phi +ENCODING 934 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR Chi +ENCODING 935 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR Psi +ENCODING 936 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 937 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR Iotadieresis +ENCODING 938 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR Upsilondieresis +ENCODING 939 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR alphatonos +ENCODING 940 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR epsilontonos +ENCODING 941 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR etatonos +ENCODING 942 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR iotatonos +ENCODING 943 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresistonos +ENCODING 944 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR alpha +ENCODING 945 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +A0 +50 +00 +ENDCHAR +STARTCHAR beta +ENCODING 946 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR gamma +ENCODING 947 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR delta +ENCODING 948 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR epsilon +ENCODING 949 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR zeta +ENCODING 950 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +80 +E0 +20 +40 +ENDCHAR +STARTCHAR eta +ENCODING 951 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR theta +ENCODING 952 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR iota +ENCODING 953 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR kappa +ENCODING 954 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR lambda +ENCODING 955 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR mu +ENCODING 956 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR nu +ENCODING 957 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +40 +00 +ENDCHAR +STARTCHAR xi +ENCODING 958 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR omicron +ENCODING 959 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR pi +ENCODING 960 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR rho +ENCODING 961 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR sigma1 +ENCODING 962 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +40 +C0 +00 +ENDCHAR +STARTCHAR sigma +ENCODING 963 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +A0 +40 +00 +ENDCHAR +STARTCHAR tau +ENCODING 964 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilon +ENCODING 965 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR phi +ENCODING 966 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +A0 +40 +40 +ENDCHAR +STARTCHAR chi +ENCODING 967 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +60 +A0 +00 +ENDCHAR +STARTCHAR psi +ENCODING 968 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR omega +ENCODING 969 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR iotadieresis +ENCODING 970 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresis +ENCODING 971 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omicrontonos +ENCODING 972 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR upsilontonos +ENCODING 973 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omegatonos +ENCODING 974 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10023 +ENCODING 1025 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10051 +ENCODING 1026 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10052 +ENCODING 1027 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10053 +ENCODING 1028 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10054 +ENCODING 1029 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10055 +ENCODING 1030 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10056 +ENCODING 1031 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10057 +ENCODING 1032 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10058 +ENCODING 1033 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10059 +ENCODING 1034 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10060 +ENCODING 1035 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10061 +ENCODING 1036 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10062 +ENCODING 1038 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10145 +ENCODING 1039 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10017 +ENCODING 1040 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10018 +ENCODING 1041 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10019 +ENCODING 1042 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10020 +ENCODING 1043 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10021 +ENCODING 1044 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10022 +ENCODING 1045 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10024 +ENCODING 1046 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10025 +ENCODING 1047 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10026 +ENCODING 1048 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +E0 +A0 +20 +00 +ENDCHAR +STARTCHAR afii10027 +ENCODING 1049 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR afii10028 +ENCODING 1050 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10029 +ENCODING 1051 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10030 +ENCODING 1052 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10031 +ENCODING 1053 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10032 +ENCODING 1054 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10033 +ENCODING 1055 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10034 +ENCODING 1056 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10035 +ENCODING 1057 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10036 +ENCODING 1058 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10037 +ENCODING 1059 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +40 +40 +80 +ENDCHAR +STARTCHAR afii10038 +ENCODING 1060 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR afii10039 +ENCODING 1061 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10040 +ENCODING 1062 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii10041 +ENCODING 1063 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +60 +20 +20 +00 +ENDCHAR +STARTCHAR afii10042 +ENCODING 1064 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10043 +ENCODING 1065 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10044 +ENCODING 1066 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10045 +ENCODING 1067 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10046 +ENCODING 1068 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10047 +ENCODING 1069 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10048 +ENCODING 1070 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +D0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10049 +ENCODING 1071 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10065 +ENCODING 1072 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR afii10066 +ENCODING 1073 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10067 +ENCODING 1074 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10068 +ENCODING 1075 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10069 +ENCODING 1076 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10070 +ENCODING 1077 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10072 +ENCODING 1078 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +60 +60 +B0 +00 +ENDCHAR +STARTCHAR afii10073 +ENCODING 1079 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10074 +ENCODING 1080 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10075 +ENCODING 1081 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10076 +ENCODING 1082 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10077 +ENCODING 1083 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10078 +ENCODING 1084 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10079 +ENCODING 1085 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10080 +ENCODING 1086 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10081 +ENCODING 1087 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10082 +ENCODING 1088 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii10083 +ENCODING 1089 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +80 +60 +00 +ENDCHAR +STARTCHAR afii10084 +ENCODING 1090 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10085 +ENCODING 1091 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR afii10086 +ENCODING 1092 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR afii10087 +ENCODING 1093 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii10088 +ENCODING 1094 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +20 +ENDCHAR +STARTCHAR afii10089 +ENCODING 1095 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +00 +ENDCHAR +STARTCHAR afii10090 +ENCODING 1096 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10091 +ENCODING 1097 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10092 +ENCODING 1098 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10093 +ENCODING 1099 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10094 +ENCODING 1100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10095 +ENCODING 1101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10096 +ENCODING 1102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10097 +ENCODING 1103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +60 +A0 +00 +ENDCHAR +STARTCHAR afii10071 +ENCODING 1105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10099 +ENCODING 1106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +20 +ENDCHAR +STARTCHAR afii10100 +ENCODING 1107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10101 +ENCODING 1108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10102 +ENCODING 1109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10103 +ENCODING 1110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10104 +ENCODING 1111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10105 +ENCODING 1112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +20 +20 +20 +C0 +ENDCHAR +STARTCHAR afii10106 +ENCODING 1113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10107 +ENCODING 1114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10108 +ENCODING 1115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10109 +ENCODING 1116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10110 +ENCODING 1118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10193 +ENCODING 1119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10050 +ENCODING 1168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10098 +ENCODING 1169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR uni0492 +ENCODING 1170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR uni0493 +ENCODING 1171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR afii57664 +ENCODING 1488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii57665 +ENCODING 1489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +F0 +00 +ENDCHAR +STARTCHAR afii57666 +ENCODING 1490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii57667 +ENCODING 1491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57668 +ENCODING 1492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57669 +ENCODING 1493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57670 +ENCODING 1494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii57671 +ENCODING 1495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57672 +ENCODING 1496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii57673 +ENCODING 1497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +20 +00 +00 +00 +ENDCHAR +STARTCHAR afii57674 +ENCODING 1498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +20 +ENDCHAR +STARTCHAR afii57675 +ENCODING 1499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +C0 +00 +ENDCHAR +STARTCHAR afii57676 +ENCODING 1500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +20 +40 +00 +ENDCHAR +STARTCHAR afii57677 +ENCODING 1501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57678 +ENCODING 1502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57679 +ENCODING 1503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57680 +ENCODING 1504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR afii57681 +ENCODING 1505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii57682 +ENCODING 1506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +60 +C0 +00 +ENDCHAR +STARTCHAR afii57683 +ENCODING 1507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +20 +20 +ENDCHAR +STARTCHAR afii57684 +ENCODING 1508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57685 +ENCODING 1509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57686 +ENCODING 1510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57687 +ENCODING 1511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57688 +ENCODING 1512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57689 +ENCODING 1513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +D0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57690 +ENCODING 1514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E02 +ENCODING 7682 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E03 +ENCODING 7683 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0A +ENCODING 7690 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0B +ENCODING 7691 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR uni1E1E +ENCODING 7710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E1F +ENCODING 7711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni1E40 +ENCODING 7744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E41 +ENCODING 7745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uni1E56 +ENCODING 7766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E57 +ENCODING 7767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR uni1E60 +ENCODING 7776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E61 +ENCODING 7777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E6A +ENCODING 7786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni1E6B +ENCODING 7787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +20 +ENDCHAR +STARTCHAR Wgrave +ENCODING 7808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wgrave +ENCODING 7809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wacute +ENCODING 7810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wacute +ENCODING 7811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wdieresis +ENCODING 7812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wdieresis +ENCODING 7813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ygrave +ENCODING 7922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ygrave +ENCODING 7923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +60 +20 +40 +ENDCHAR +STARTCHAR uni2010 +ENCODING 8208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR uni2011 +ENCODING 8209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR figuredash +ENCODING 8210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR afii00208 +ENCODING 8213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2016 +ENCODING 8214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR underscoredbl +ENCODING 8215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +F0 +ENDCHAR +STARTCHAR quoteleft +ENCODING 8216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +00 +00 +00 +ENDCHAR +STARTCHAR quoteright +ENCODING 8217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR quotesinglbase +ENCODING 8218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +20 +40 +ENDCHAR +STARTCHAR quotereversed +ENCODING 8219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblleft +ENCODING 8220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblright +ENCODING 8221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblbase +ENCODING 8222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +50 +50 +A0 +ENDCHAR +STARTCHAR uni201F +ENCODING 8223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +50 +00 +00 +00 +ENDCHAR +STARTCHAR dagger +ENCODING 8224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR daggerdbl +ENCODING 8225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2023 +ENCODING 8227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +E0 +C0 +00 +00 +ENDCHAR +STARTCHAR onedotenleader +ENCODING 8228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR twodotenleader +ENCODING 8229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +A0 +00 +ENDCHAR +STARTCHAR ellipsis +ENCODING 8230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +B0 +00 +ENDCHAR +STARTCHAR uni2027 +ENCODING 8231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR perthousand +ENCODING 8240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +80 +30 +00 +ENDCHAR +STARTCHAR guilsinglleft +ENCODING 8249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +80 +40 +00 +00 +ENDCHAR +STARTCHAR guilsinglright +ENCODING 8250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +20 +40 +00 +00 +ENDCHAR +STARTCHAR uni203E +ENCODING 8254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR nsuperior +ENCODING 8319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR peseta +ENCODING 8359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR Euro +ENCODING 8364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR afii61352 +ENCODING 8470 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +B0 +B0 +A0 +B0 +00 +ENDCHAR +STARTCHAR trademark +ENCODING 8482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +00 +E0 +A0 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 8486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni2127 +ENCODING 8487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR oneeighth +ENCODING 8539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +20 +50 +20 +ENDCHAR +STARTCHAR threeeighths +ENCODING 8540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +60 +D0 +20 +ENDCHAR +STARTCHAR fiveeighths +ENCODING 8541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +70 +A0 +50 +20 +ENDCHAR +STARTCHAR seveneighths +ENCODING 8542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +A0 +50 +20 +ENDCHAR +STARTCHAR arrowleft +ENCODING 8592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +F0 +40 +00 +00 +ENDCHAR +STARTCHAR arrowup +ENCODING 8593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR arrowright +ENCODING 8594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +F0 +20 +00 +00 +ENDCHAR +STARTCHAR arrowdown +ENCODING 8595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR arrowboth +ENCODING 8596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +F0 +50 +00 +00 +ENDCHAR +STARTCHAR arrowupdn +ENCODING 8597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR universal +ENCODING 8704 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR uni2201 +ENCODING 8705 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR partialdiff +ENCODING 8706 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR existential +ENCODING 8707 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR uni2204 +ENCODING 8708 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +E0 +60 +E0 +80 +ENDCHAR +STARTCHAR emptyset +ENCODING 8709 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR Delta +ENCODING 8710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR gradient +ENCODING 8711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR element +ENCODING 8712 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +80 +60 +00 +ENDCHAR +STARTCHAR notelement +ENCODING 8713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +E0 +A0 +60 +40 +ENDCHAR +STARTCHAR uni220A +ENCODING 8714 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +C0 +80 +40 +00 +ENDCHAR +STARTCHAR suchthat +ENCODING 8715 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +E0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni220C +ENCODING 8716 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +E0 +60 +C0 +80 +ENDCHAR +STARTCHAR uni220D +ENCODING 8717 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +C0 +40 +80 +00 +ENDCHAR +STARTCHAR uni220E +ENCODING 8718 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +00 +ENDCHAR +STARTCHAR product +ENCODING 8719 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2210 +ENCODING 8720 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR summation +ENCODING 8721 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR minus +ENCODING 8722 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2213 +ENCODING 8723 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni2214 +ENCODING 8724 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR fraction +ENCODING 8725 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR uni2216 +ENCODING 8726 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR asteriskmath +ENCODING 8727 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +70 +E0 +50 +40 +ENDCHAR +STARTCHAR uni2218 +ENCODING 8728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +00 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 8729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR radical +ENCODING 8730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +20 +A0 +60 +00 +ENDCHAR +STARTCHAR uni221B +ENCODING 8731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +50 +D0 +10 +50 +30 +ENDCHAR +STARTCHAR uni221C +ENCODING 8732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +D0 +50 +10 +50 +30 +ENDCHAR +STARTCHAR proportional +ENCODING 8733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +E0 +50 +00 +ENDCHAR +STARTCHAR infinity +ENCODING 8734 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +D0 +B0 +40 +00 +ENDCHAR +STARTCHAR orthogonal +ENCODING 8735 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR angle +ENCODING 8736 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR uni2221 +ENCODING 8737 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +A0 +40 +A0 +F0 +20 +ENDCHAR +STARTCHAR uni2222 +ENCODING 8738 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +A0 +A0 +60 +90 +ENDCHAR +STARTCHAR uni2223 +ENCODING 8739 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni2224 +ENCODING 8740 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +40 +00 +ENDCHAR +STARTCHAR uni2225 +ENCODING 8741 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2226 +ENCODING 8742 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +B0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicaland +ENCODING 8743 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicalor +ENCODING 8744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR intersection +ENCODING 8745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR union +ENCODING 8746 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR integral +ENCODING 8747 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni222C +ENCODING 8748 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +A0 +A0 +80 +ENDCHAR +STARTCHAR uni222D +ENCODING 8749 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +D0 +D0 +D0 +A0 +ENDCHAR +STARTCHAR uni222E +ENCODING 8750 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +E0 +40 +80 +ENDCHAR +STARTCHAR uni222F +ENCODING 8751 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +80 +ENDCHAR +STARTCHAR uni2230 +ENCODING 8752 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +F0 +F0 +D0 +A0 +ENDCHAR +STARTCHAR uni2231 +ENCODING 8753 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +50 +40 +80 +ENDCHAR +STARTCHAR uni2232 +ENCODING 8754 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +C0 +40 +80 +ENDCHAR +STARTCHAR uni2233 +ENCODING 8755 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +E0 +40 +80 +ENDCHAR +STARTCHAR therefore +ENCODING 8756 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2235 +ENCODING 8757 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +40 +00 +ENDCHAR +STARTCHAR uni2236 +ENCODING 8758 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2237 +ENCODING 8759 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2238 +ENCODING 8760 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2239 +ENCODING 8761 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +20 +C0 +20 +00 +ENDCHAR +STARTCHAR uni223A +ENCODING 8762 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni223B +ENCODING 8763 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +50 +A0 +00 +40 +ENDCHAR +STARTCHAR similar +ENCODING 8764 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni223D +ENCODING 8765 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni223E +ENCODING 8766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +D0 +B0 +00 +00 +ENDCHAR +STARTCHAR uni223F +ENCODING 8767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +50 +A0 +20 +00 +ENDCHAR +STARTCHAR uni2240 +ENCODING 8768 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +40 +40 +20 +00 +ENDCHAR +STARTCHAR uni2241 +ENCODING 8769 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +B0 +D0 +40 +80 +ENDCHAR +STARTCHAR uni2242 +ENCODING 8770 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +00 +A0 +50 +00 +ENDCHAR +STARTCHAR uni2243 +ENCODING 8771 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2244 +ENCODING 8772 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +D0 +B0 +40 +F0 +40 +ENDCHAR +STARTCHAR congruent +ENCODING 8773 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni2246 +ENCODING 8774 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR uni2247 +ENCODING 8775 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR approxequal +ENCODING 8776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +50 +A0 +00 +ENDCHAR +STARTCHAR uni2249 +ENCODING 8777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +40 +50 +E0 +80 +ENDCHAR +STARTCHAR uni224A +ENCODING 8778 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +00 +F0 +ENDCHAR +STARTCHAR uni224B +ENCODING 8779 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +40 +B0 +ENDCHAR +STARTCHAR uni224C +ENCODING 8780 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +50 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni224D +ENCODING 8781 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +40 +A0 +00 +ENDCHAR +STARTCHAR uni224E +ENCODING 8782 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +A0 +40 +00 +ENDCHAR +STARTCHAR uni224F +ENCODING 8783 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2250 +ENCODING 8784 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2251 +ENCODING 8785 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +40 +ENDCHAR +STARTCHAR uni2252 +ENCODING 8786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +00 +E0 +00 +20 +ENDCHAR +STARTCHAR uni2253 +ENCODING 8787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +00 +E0 +00 +80 +ENDCHAR +STARTCHAR uni2254 +ENCODING 8788 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +00 +B0 +00 +00 +ENDCHAR +STARTCHAR uni2255 +ENCODING 8789 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +D0 +00 +D0 +00 +00 +ENDCHAR +STARTCHAR uni2256 +ENCODING 8790 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2257 +ENCODING 8791 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2258 +ENCODING 8792 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2259 +ENCODING 8793 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225A +ENCODING 8794 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225B +ENCODING 8795 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225C +ENCODING 8796 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225D +ENCODING 8797 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225E +ENCODING 8798 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225F +ENCODING 8799 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR notequal +ENCODING 8800 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR equivalence +ENCODING 8801 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2262 +ENCODING 8802 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2263 +ENCODING 8803 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR lessequal +ENCODING 8804 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR greaterequal +ENCODING 8805 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2266 +ENCODING 8806 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2267 +ENCODING 8807 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2268 +ENCODING 8808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2269 +ENCODING 8809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni226A +ENCODING 8810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni226B +ENCODING 8811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni226C +ENCODING 8812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni226D +ENCODING 8813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR uni226E +ENCODING 8814 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +60 +80 +00 +ENDCHAR +STARTCHAR uni226F +ENCODING 8815 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +60 +C0 +80 +00 +ENDCHAR +STARTCHAR uni2270 +ENCODING 8816 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2271 +ENCODING 8817 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2272 +ENCODING 8818 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +50 +A0 +ENDCHAR +STARTCHAR uni2273 +ENCODING 8819 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2276 +ENCODING 8822 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +20 +80 +60 +C0 +ENDCHAR +STARTCHAR uni2277 +ENCODING 8823 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +80 +20 +C0 +60 +ENDCHAR +STARTCHAR uni2278 +ENCODING 8824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +60 +C0 +60 +C0 +ENDCHAR +STARTCHAR uni2279 +ENCODING 8825 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +60 +C0 +60 +ENDCHAR +STARTCHAR uni227A +ENCODING 8826 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +C0 +20 +00 +00 +ENDCHAR +STARTCHAR uni227B +ENCODING 8827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +60 +80 +00 +00 +ENDCHAR +STARTCHAR uni227C +ENCODING 8828 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227D +ENCODING 8829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +80 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227E +ENCODING 8830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni227F +ENCODING 8831 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2280 +ENCODING 8832 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2281 +ENCODING 8833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR propersubset +ENCODING 8834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +60 +00 +00 +ENDCHAR +STARTCHAR propersuperset +ENCODING 8835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +C0 +00 +00 +ENDCHAR +STARTCHAR notsubset +ENCODING 8836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2285 +ENCODING 8837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR reflexsubset +ENCODING 8838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR reflexsuperset +ENCODING 8839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2288 +ENCODING 8840 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2289 +ENCODING 8841 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +40 +ENDCHAR +STARTCHAR uni228A +ENCODING 8842 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni228B +ENCODING 8843 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +40 +E0 +80 +ENDCHAR +STARTCHAR revlogicalnot +ENCODING 8976 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +80 +00 +00 +ENDCHAR +STARTCHAR integraltp +ENCODING 8992 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR integralbt +ENCODING 8993 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +20 +20 +40 +ENDCHAR +STARTCHAR uni23BA +ENCODING 9146 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BB +ENCODING 9147 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BC +ENCODING 9148 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni23BD +ENCODING 9149 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2409 +ENCODING 9225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +70 +20 +20 +ENDCHAR +STARTCHAR uni240A +ENCODING 9226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +60 +40 +40 +ENDCHAR +STARTCHAR uni240B +ENCODING 9227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +70 +20 +20 +ENDCHAR +STARTCHAR uni240C +ENCODING 9228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +80 +60 +60 +40 +ENDCHAR +STARTCHAR uni240D +ENCODING 9229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +E0 +50 +60 +50 +ENDCHAR +STARTCHAR uni2423 +ENCODING 9251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +90 +F0 +ENDCHAR +STARTCHAR uni2424 +ENCODING 9252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +B0 +90 +20 +20 +30 +ENDCHAR +STARTCHAR SF100000 +ENCODING 9472 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2501 +ENCODING 9473 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +00 +00 +ENDCHAR +STARTCHAR SF110000 +ENCODING 9474 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni2503 +ENCODING 9475 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR uni2504 +ENCODING 9476 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2505 +ENCODING 9477 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni2506 +ENCODING 9478 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2507 +ENCODING 9479 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR uni2508 +ENCODING 9480 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2509 +ENCODING 9481 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni250A +ENCODING 9482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni250B +ENCODING 9483 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR SF010000 +ENCODING 9484 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +40 +40 +ENDCHAR +STARTCHAR uni250D +ENCODING 9485 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni250E +ENCODING 9486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR uni250F +ENCODING 9487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF030000 +ENCODING 9488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2511 +ENCODING 9489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2512 +ENCODING 9490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2513 +ENCODING 9491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF020000 +ENCODING 9492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +00 +00 +ENDCHAR +STARTCHAR uni2515 +ENCODING 9493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni2516 +ENCODING 9494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR uni2517 +ENCODING 9495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +00 +00 +ENDCHAR +STARTCHAR SF040000 +ENCODING 9496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2519 +ENCODING 9497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni251A +ENCODING 9498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR uni251B +ENCODING 9499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +00 +00 +ENDCHAR +STARTCHAR SF080000 +ENCODING 9500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +40 +40 +ENDCHAR +STARTCHAR uni251D +ENCODING 9501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni251E +ENCODING 9502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +40 +40 +ENDCHAR +STARTCHAR uni251F +ENCODING 9503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +60 +60 +ENDCHAR +STARTCHAR uni2520 +ENCODING 9504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR uni2521 +ENCODING 9505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni2522 +ENCODING 9506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +60 +60 +ENDCHAR +STARTCHAR uni2523 +ENCODING 9507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF090000 +ENCODING 9508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2525 +ENCODING 9509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2526 +ENCODING 9510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +40 +40 +ENDCHAR +STARTCHAR uni2527 +ENCODING 9511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2528 +ENCODING 9512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2529 +ENCODING 9513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +40 +40 +ENDCHAR +STARTCHAR uni252A +ENCODING 9514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR uni252B +ENCODING 9515 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF060000 +ENCODING 9516 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252D +ENCODING 9517 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252E +ENCODING 9518 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252F +ENCODING 9519 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2530 +ENCODING 9520 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2531 +ENCODING 9521 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2532 +ENCODING 9522 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2533 +ENCODING 9523 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR SF070000 +ENCODING 9524 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2535 +ENCODING 9525 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2536 +ENCODING 9526 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2537 +ENCODING 9527 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2538 +ENCODING 9528 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2539 +ENCODING 9529 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253A +ENCODING 9530 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253B +ENCODING 9531 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR SF050000 +ENCODING 9532 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253D +ENCODING 9533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253E +ENCODING 9534 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253F +ENCODING 9535 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2540 +ENCODING 9536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2541 +ENCODING 9537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2542 +ENCODING 9538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2543 +ENCODING 9539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2544 +ENCODING 9540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2545 +ENCODING 9541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2546 +ENCODING 9542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2547 +ENCODING 9543 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2548 +ENCODING 9544 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2549 +ENCODING 9545 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254A +ENCODING 9546 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254B +ENCODING 9547 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254C +ENCODING 9548 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254D +ENCODING 9549 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254E +ENCODING 9550 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +00 +40 +40 +ENDCHAR +STARTCHAR uni254F +ENCODING 9551 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +60 +00 +60 +60 +ENDCHAR +STARTCHAR SF430000 +ENCODING 9552 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF240000 +ENCODING 9553 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR SF510000 +ENCODING 9554 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF520000 +ENCODING 9555 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR SF390000 +ENCODING 9556 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF220000 +ENCODING 9557 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF210000 +ENCODING 9558 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR SF250000 +ENCODING 9559 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF500000 +ENCODING 9560 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF490000 +ENCODING 9561 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR SF380000 +ENCODING 9562 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF280000 +ENCODING 9563 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +00 +ENDCHAR +STARTCHAR SF270000 +ENCODING 9564 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR SF260000 +ENCODING 9565 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR SF360000 +ENCODING 9566 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF370000 +ENCODING 9567 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR SF420000 +ENCODING 9568 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF190000 +ENCODING 9569 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF200000 +ENCODING 9570 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR SF230000 +ENCODING 9571 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF470000 +ENCODING 9572 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +40 +ENDCHAR +STARTCHAR SF480000 +ENCODING 9573 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR SF410000 +ENCODING 9574 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR SF450000 +ENCODING 9575 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF460000 +ENCODING 9576 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR SF400000 +ENCODING 9577 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF540000 +ENCODING 9578 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +40 +F0 +40 +ENDCHAR +STARTCHAR SF530000 +ENCODING 9579 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR SF440000 +ENCODING 9580 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR uni256D +ENCODING 9581 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +30 +40 +40 +ENDCHAR +STARTCHAR uni256E +ENCODING 9582 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +80 +40 +40 +ENDCHAR +STARTCHAR uni256F +ENCODING 9583 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +80 +00 +00 +ENDCHAR +STARTCHAR uni2570 +ENCODING 9584 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +30 +00 +00 +ENDCHAR +STARTCHAR uni2571 +ENCODING 9585 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +20 +40 +40 +80 +ENDCHAR +STARTCHAR uni2572 +ENCODING 9586 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +20 +20 +10 +ENDCHAR +STARTCHAR uni2573 +ENCODING 9587 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +60 +90 +90 +ENDCHAR +STARTCHAR uni2574 +ENCODING 9588 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2575 +ENCODING 9589 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR uni2576 +ENCODING 9590 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +00 +00 +ENDCHAR +STARTCHAR uni2577 +ENCODING 9591 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +40 +40 +ENDCHAR +STARTCHAR uni2578 +ENCODING 9592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2579 +ENCODING 9593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR uni257A +ENCODING 9594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni257B +ENCODING 9595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +60 +60 +ENDCHAR +STARTCHAR uni257C +ENCODING 9596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +30 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257D +ENCODING 9597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +60 +60 +60 +ENDCHAR +STARTCHAR uni257E +ENCODING 9598 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257F +ENCODING 9599 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +40 +40 +ENDCHAR +STARTCHAR upblock +ENCODING 9600 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +00 +00 +00 +ENDCHAR +STARTCHAR uni2581 +ENCODING 9601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2582 +ENCODING 9602 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F8 +ENDCHAR +STARTCHAR uni2583 +ENCODING 9603 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F8 +F8 +ENDCHAR +STARTCHAR dnblock +ENCODING 9604 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2585 +ENCODING 9605 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2586 +ENCODING 9606 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2587 +ENCODING 9607 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR block +ENCODING 9608 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2589 +ENCODING 9609 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +F0 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR uni258A +ENCODING 9610 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR uni258B +ENCODING 9611 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR lfblock +ENCODING 9612 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258D +ENCODING 9613 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258E +ENCODING 9614 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni258F +ENCODING 9615 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR rtblock +ENCODING 9616 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR ltshade +ENCODING 9617 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +80 +20 +80 +20 +ENDCHAR +STARTCHAR shade +ENCODING 9618 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A8 +50 +A8 +50 +A8 +50 +ENDCHAR +STARTCHAR dkshade +ENCODING 9619 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B8 +E8 +B8 +E8 +B8 +E8 +ENDCHAR +STARTCHAR uni2594 +ENCODING 9620 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni2595 +ENCODING 9621 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR filledbox +ENCODING 9632 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR H22073 +ENCODING 9633 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uni25C6 +ENCODING 9670 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR spade +ENCODING 9824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR club +ENCODING 9827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +E0 +00 +ENDCHAR +STARTCHAR heart +ENCODING 9829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR diamond +ENCODING 9830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2669 +ENCODING 9833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnote +ENCODING 9834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnotedbl +ENCODING 9835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +50 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266C +ENCODING 9836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +70 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266D +ENCODING 9837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni266E +ENCODING 9838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +A0 +E0 +20 +00 +ENDCHAR +STARTCHAR uni266F +ENCODING 9839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uniFFFD +ENCODING 65533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +90 +D0 +F0 +D0 +F0 +ENDCHAR +ENDFONT diff --git a/src/col64/cruft/col64font_ext.bdf b/src/col64/cruft/col64font_ext.bdf new file mode 100644 index 0000000..c6cc5f0 --- /dev/null +++ b/src/col64/cruft/col64font_ext.bdf @@ -0,0 +1,11994 @@ +STARTFONT 2.1 +COMMENT Contributed by Janne V. Kujala +COMMENT $Id: 4x6.bdf,v 1.5 2002-08-26 18:05:49+01 mgk25 Rel $ +COMMENT Send bug reports to Markus Kuhn +FONT -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1 +SIZE 6 75 75 +FONTBOUNDINGBOX 4 6 0 -1 +STARTPROPERTIES 23 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 6 +POINT_SIZE 60 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 40 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 5 +FONT_DESCENT 1 +DESTINATION 1 +COPYRIGHT "Public domain font. Share and enjoy." +CAP_HEIGHT 5 +X_HEIGHT 4 +DEFAULT_CHAR 0 +_GBDFED_INFO "Edited with gbdfed 1.4." +ENDPROPERTIES +CHARS 920 +STARTCHAR char0 +ENCODING 0 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR space +ENCODING 32 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +00 +40 +00 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +A0 +F0 +A0 +00 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +60 +50 +E0 +00 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +20 +40 +90 +00 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +A0 +D0 +00 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +40 +00 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +A0 +00 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +B0 +D0 +60 +00 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +10 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +F0 +20 +00 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +10 +E0 +00 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +E0 +90 +60 +00 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +10 +20 +40 +40 +00 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +60 +90 +60 +00 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +70 +10 +E0 +00 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +00 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +00 +20 +40 +00 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +80 +40 +20 +00 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +20 +40 +80 +00 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +20 +00 +20 +00 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +B0 +B0 +80 +60 +00 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +80 +90 +60 +00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +90 +90 +E0 +00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +F0 +00 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +B0 +90 +60 +00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +10 +10 +90 +60 +00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +F0 +00 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +D0 +90 +90 +00 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +D0 +B0 +90 +90 +00 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +A0 +50 +00 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +A0 +90 +00 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +90 +90 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +20 +40 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +40 +80 +F0 +00 +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +40 +40 +60 +00 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F0 +00 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +90 +B0 +50 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +80 +80 +70 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +70 +90 +70 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +E0 +70 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +90 +70 +10 +00 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +90 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +60 +20 +20 +00 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +F0 +D0 +90 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +E0 +80 +00 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +90 +70 +10 +00 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +80 +80 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +C0 +30 +E0 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +60 +20 +00 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +80 +40 +60 +00 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +20 +40 +C0 +00 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR char127 +ENCODING 127 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +80 +10 +C0 +00 +ENDCHAR +STARTCHAR space +ENCODING 160 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +40 +40 +00 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +E0 +40 +00 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +40 +A0 +00 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +00 +40 +40 +00 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +D0 +D0 +90 +60 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +00 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 173 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +D0 +60 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +C0 +00 +00 +ENDCHAR +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +40 +80 +00 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +D0 +D0 +50 +50 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +00 +00 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +50 +70 +10 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +10 +20 +30 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +50 +B0 +10 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +80 +60 +00 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +F0 +A0 +B0 +00 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +80 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +50 +D0 +50 +E0 +00 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +E0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +A0 +00 +00 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +E0 +80 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +80 +60 +40 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +40 +00 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR Amacron +ENCODING 256 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR amacron +ENCODING 257 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Abreve +ENCODING 258 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR abreve +ENCODING 259 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Aogonek +ENCODING 260 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR aogonek +ENCODING 261 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +A0 +60 +20 +ENDCHAR +STARTCHAR Cacute +ENCODING 262 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cacute +ENCODING 263 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +80 +60 +00 +ENDCHAR +STARTCHAR Ccircumflex +ENCODING 264 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccircumflex +ENCODING 265 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Cdotaccent +ENCODING 266 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cdotaccent +ENCODING 267 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Ccaron +ENCODING 268 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccaron +ENCODING 269 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Dcaron +ENCODING 270 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcaron +ENCODING 271 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Dcroat +ENCODING 272 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcroat +ENCODING 273 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Emacron +ENCODING 274 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR emacron +ENCODING 275 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Ebreve +ENCODING 276 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ebreve +ENCODING 277 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Edotaccent +ENCODING 278 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR edotaccent +ENCODING 279 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Eogonek +ENCODING 280 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +20 +ENDCHAR +STARTCHAR eogonek +ENCODING 281 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +40 +ENDCHAR +STARTCHAR Ecaron +ENCODING 282 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ecaron +ENCODING 283 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Gcircumflex +ENCODING 284 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gcircumflex +ENCODING 285 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gbreve +ENCODING 286 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gbreve +ENCODING 287 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gdotaccent +ENCODING 288 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gdotaccent +ENCODING 289 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gcommaaccent +ENCODING 290 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR gcommaaccent +ENCODING 291 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Hcircumflex +ENCODING 292 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hcircumflex +ENCODING 293 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Hbar +ENCODING 294 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hbar +ENCODING 295 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Itilde +ENCODING 296 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR itilde +ENCODING 297 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Imacron +ENCODING 298 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR imacron +ENCODING 299 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Ibreve +ENCODING 300 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR ibreve +ENCODING 301 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Iogonek +ENCODING 302 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR iogonek +ENCODING 303 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +20 +ENDCHAR +STARTCHAR Idotaccent +ENCODING 304 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR IJ +ENCODING 306 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +A0 +A0 +20 +60 +ENDCHAR +STARTCHAR ij +ENCODING 307 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Jcircumflex +ENCODING 308 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR jcircumflex +ENCODING 309 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +20 +20 +C0 +ENDCHAR +STARTCHAR Kcommaaccent +ENCODING 310 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kcommaaccent +ENCODING 311 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kgreenlandic +ENCODING 312 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR Lacute +ENCODING 313 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lacute +ENCODING 314 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Lcommaaccent +ENCODING 315 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR lcommaaccent +ENCODING 316 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR Lcaron +ENCODING 317 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +C0 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lcaron +ENCODING 318 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Ldot +ENCODING 319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +A0 +80 +E0 +00 +ENDCHAR +STARTCHAR ldot +ENCODING 320 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +50 +40 +E0 +00 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Nacute +ENCODING 323 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR nacute +ENCODING 324 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Ncommaaccent +ENCODING 325 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +20 +ENDCHAR +STARTCHAR ncommaaccent +ENCODING 326 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +40 +ENDCHAR +STARTCHAR Ncaron +ENCODING 327 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR ncaron +ENCODING 328 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR napostrophe +ENCODING 329 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +00 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Eng +ENCODING 330 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +A0 +20 +40 +ENDCHAR +STARTCHAR eng +ENCODING 331 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Omacron +ENCODING 332 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR omacron +ENCODING 333 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Obreve +ENCODING 334 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR obreve +ENCODING 335 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Ohungarumlaut +ENCODING 336 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR ohungarumlaut +ENCODING 337 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR Racute +ENCODING 340 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR racute +ENCODING 341 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Rcommaaccent +ENCODING 342 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +00 +40 +ENDCHAR +STARTCHAR rcommaaccent +ENCODING 343 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +C0 +80 +80 +20 +ENDCHAR +STARTCHAR Rcaron +ENCODING 344 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR rcaron +ENCODING 345 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Sacute +ENCODING 346 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR sacute +ENCODING 347 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scircumflex +ENCODING 348 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR scircumflex +ENCODING 349 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scedilla +ENCODING 350 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scedilla +ENCODING 351 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +E0 +00 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 354 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +20 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 355 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR Tcaron +ENCODING 356 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tcaron +ENCODING 357 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Tbar +ENCODING 358 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tbar +ENCODING 359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Utilde +ENCODING 360 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR utilde +ENCODING 361 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Umacron +ENCODING 362 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR umacron +ENCODING 363 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Ubreve +ENCODING 364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR ubreve +ENCODING 365 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Uring +ENCODING 366 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uring +ENCODING 367 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uhungarumlaut +ENCODING 368 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uhungarumlaut +ENCODING 369 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uogonek +ENCODING 370 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +20 +ENDCHAR +STARTCHAR uogonek +ENCODING 371 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +60 +40 +ENDCHAR +STARTCHAR Wcircumflex +ENCODING 372 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR wcircumflex +ENCODING 373 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ycircumflex +ENCODING 374 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ycircumflex +ENCODING 375 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +40 +80 +00 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Zacute +ENCODING 377 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zacute +ENCODING 378 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zdotaccent +ENCODING 379 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zdotaccent +ENCODING 380 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR longs +ENCODING 383 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR uni018F +ENCODING 399 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR florin +ENCODING 402 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +40 +80 +ENDCHAR +STARTCHAR Scommaaccent +ENCODING 536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scommaaccent +ENCODING 537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +00 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR uni0259 +ENCODING 601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR circumflex +ENCODING 710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR caron +ENCODING 711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR breve +ENCODING 728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dotaccent +ENCODING 729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ring +ENCODING 730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR ogonek +ENCODING 731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +80 +C0 +ENDCHAR +STARTCHAR tilde +ENCODING 732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR hungarumlaut +ENCODING 733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0374 +ENCODING 884 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0375 +ENCODING 885 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +80 +ENDCHAR +STARTCHAR uni037A +ENCODING 890 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +60 +ENDCHAR +STARTCHAR uni037E +ENCODING 894 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +80 +ENDCHAR +STARTCHAR tonos +ENCODING 900 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dieresistonos +ENCODING 901 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Alphatonos +ENCODING 902 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR anoteleia +ENCODING 903 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR Epsilontonos +ENCODING 904 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +60 +40 +60 +00 +ENDCHAR +STARTCHAR Etatonos +ENCODING 905 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Iotatonos +ENCODING 906 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Omicrontonos +ENCODING 908 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Upsilontonos +ENCODING 910 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR Omegatonos +ENCODING 911 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR iotadieresistonos +ENCODING 912 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +40 +20 +00 +ENDCHAR +STARTCHAR Alpha +ENCODING 913 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Beta +ENCODING 914 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Gamma +ENCODING 915 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR Delta +ENCODING 916 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Epsilon +ENCODING 917 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Zeta +ENCODING 918 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Eta +ENCODING 919 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Theta +ENCODING 920 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR Iota +ENCODING 921 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Kappa +ENCODING 922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Lambda +ENCODING 923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Mu +ENCODING 924 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Nu +ENCODING 925 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR Xi +ENCODING 926 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR Omicron +ENCODING 927 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Pi +ENCODING 928 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Rho +ENCODING 929 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR Sigma +ENCODING 931 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Tau +ENCODING 932 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Upsilon +ENCODING 933 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Phi +ENCODING 934 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR Chi +ENCODING 935 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR Psi +ENCODING 936 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 937 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR Iotadieresis +ENCODING 938 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR Upsilondieresis +ENCODING 939 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR alphatonos +ENCODING 940 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR epsilontonos +ENCODING 941 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR etatonos +ENCODING 942 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR iotatonos +ENCODING 943 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresistonos +ENCODING 944 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR alpha +ENCODING 945 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +A0 +50 +00 +ENDCHAR +STARTCHAR beta +ENCODING 946 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR gamma +ENCODING 947 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR delta +ENCODING 948 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR epsilon +ENCODING 949 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR zeta +ENCODING 950 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +80 +E0 +20 +40 +ENDCHAR +STARTCHAR eta +ENCODING 951 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR theta +ENCODING 952 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR iota +ENCODING 953 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR kappa +ENCODING 954 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR lambda +ENCODING 955 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR mu +ENCODING 956 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR nu +ENCODING 957 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +40 +00 +ENDCHAR +STARTCHAR xi +ENCODING 958 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR omicron +ENCODING 959 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR pi +ENCODING 960 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR rho +ENCODING 961 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR sigma1 +ENCODING 962 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +40 +C0 +00 +ENDCHAR +STARTCHAR sigma +ENCODING 963 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +A0 +40 +00 +ENDCHAR +STARTCHAR tau +ENCODING 964 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilon +ENCODING 965 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR phi +ENCODING 966 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +A0 +40 +40 +ENDCHAR +STARTCHAR chi +ENCODING 967 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +60 +A0 +00 +ENDCHAR +STARTCHAR psi +ENCODING 968 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR omega +ENCODING 969 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR iotadieresis +ENCODING 970 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresis +ENCODING 971 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omicrontonos +ENCODING 972 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR upsilontonos +ENCODING 973 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omegatonos +ENCODING 974 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10023 +ENCODING 1025 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10051 +ENCODING 1026 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10052 +ENCODING 1027 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10053 +ENCODING 1028 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10054 +ENCODING 1029 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10055 +ENCODING 1030 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10056 +ENCODING 1031 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10057 +ENCODING 1032 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10058 +ENCODING 1033 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10059 +ENCODING 1034 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10060 +ENCODING 1035 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10061 +ENCODING 1036 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10062 +ENCODING 1038 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10145 +ENCODING 1039 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10017 +ENCODING 1040 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10018 +ENCODING 1041 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10019 +ENCODING 1042 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10020 +ENCODING 1043 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10021 +ENCODING 1044 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10022 +ENCODING 1045 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10024 +ENCODING 1046 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10025 +ENCODING 1047 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10026 +ENCODING 1048 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +E0 +A0 +20 +00 +ENDCHAR +STARTCHAR afii10027 +ENCODING 1049 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR afii10028 +ENCODING 1050 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10029 +ENCODING 1051 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10030 +ENCODING 1052 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10031 +ENCODING 1053 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10032 +ENCODING 1054 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10033 +ENCODING 1055 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10034 +ENCODING 1056 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10035 +ENCODING 1057 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10036 +ENCODING 1058 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10037 +ENCODING 1059 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +40 +40 +80 +ENDCHAR +STARTCHAR afii10038 +ENCODING 1060 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR afii10039 +ENCODING 1061 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10040 +ENCODING 1062 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii10041 +ENCODING 1063 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +60 +20 +20 +00 +ENDCHAR +STARTCHAR afii10042 +ENCODING 1064 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10043 +ENCODING 1065 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10044 +ENCODING 1066 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10045 +ENCODING 1067 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10046 +ENCODING 1068 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10047 +ENCODING 1069 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10048 +ENCODING 1070 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +D0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10049 +ENCODING 1071 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10065 +ENCODING 1072 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR afii10066 +ENCODING 1073 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10067 +ENCODING 1074 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10068 +ENCODING 1075 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10069 +ENCODING 1076 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10070 +ENCODING 1077 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10072 +ENCODING 1078 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +60 +60 +B0 +00 +ENDCHAR +STARTCHAR afii10073 +ENCODING 1079 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10074 +ENCODING 1080 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10075 +ENCODING 1081 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10076 +ENCODING 1082 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10077 +ENCODING 1083 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10078 +ENCODING 1084 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10079 +ENCODING 1085 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10080 +ENCODING 1086 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10081 +ENCODING 1087 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10082 +ENCODING 1088 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii10083 +ENCODING 1089 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +80 +60 +00 +ENDCHAR +STARTCHAR afii10084 +ENCODING 1090 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10085 +ENCODING 1091 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR afii10086 +ENCODING 1092 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR afii10087 +ENCODING 1093 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii10088 +ENCODING 1094 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +20 +ENDCHAR +STARTCHAR afii10089 +ENCODING 1095 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +00 +ENDCHAR +STARTCHAR afii10090 +ENCODING 1096 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10091 +ENCODING 1097 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10092 +ENCODING 1098 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10093 +ENCODING 1099 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10094 +ENCODING 1100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10095 +ENCODING 1101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10096 +ENCODING 1102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10097 +ENCODING 1103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +60 +A0 +00 +ENDCHAR +STARTCHAR afii10071 +ENCODING 1105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10099 +ENCODING 1106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +20 +ENDCHAR +STARTCHAR afii10100 +ENCODING 1107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10101 +ENCODING 1108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10102 +ENCODING 1109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10103 +ENCODING 1110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10104 +ENCODING 1111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10105 +ENCODING 1112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +20 +20 +20 +C0 +ENDCHAR +STARTCHAR afii10106 +ENCODING 1113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10107 +ENCODING 1114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10108 +ENCODING 1115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10109 +ENCODING 1116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10110 +ENCODING 1118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10193 +ENCODING 1119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10050 +ENCODING 1168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10098 +ENCODING 1169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR uni0492 +ENCODING 1170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR uni0493 +ENCODING 1171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR afii57664 +ENCODING 1488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii57665 +ENCODING 1489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +F0 +00 +ENDCHAR +STARTCHAR afii57666 +ENCODING 1490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii57667 +ENCODING 1491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57668 +ENCODING 1492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57669 +ENCODING 1493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57670 +ENCODING 1494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii57671 +ENCODING 1495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57672 +ENCODING 1496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii57673 +ENCODING 1497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +20 +00 +00 +00 +ENDCHAR +STARTCHAR afii57674 +ENCODING 1498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +20 +ENDCHAR +STARTCHAR afii57675 +ENCODING 1499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +C0 +00 +ENDCHAR +STARTCHAR afii57676 +ENCODING 1500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +20 +40 +00 +ENDCHAR +STARTCHAR afii57677 +ENCODING 1501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57678 +ENCODING 1502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57679 +ENCODING 1503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57680 +ENCODING 1504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR afii57681 +ENCODING 1505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii57682 +ENCODING 1506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +60 +C0 +00 +ENDCHAR +STARTCHAR afii57683 +ENCODING 1507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +20 +20 +ENDCHAR +STARTCHAR afii57684 +ENCODING 1508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57685 +ENCODING 1509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57686 +ENCODING 1510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57687 +ENCODING 1511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57688 +ENCODING 1512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57689 +ENCODING 1513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +D0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57690 +ENCODING 1514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E02 +ENCODING 7682 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E03 +ENCODING 7683 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0A +ENCODING 7690 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0B +ENCODING 7691 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR uni1E1E +ENCODING 7710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E1F +ENCODING 7711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni1E40 +ENCODING 7744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E41 +ENCODING 7745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uni1E56 +ENCODING 7766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E57 +ENCODING 7767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR uni1E60 +ENCODING 7776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E61 +ENCODING 7777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E6A +ENCODING 7786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni1E6B +ENCODING 7787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +20 +ENDCHAR +STARTCHAR Wgrave +ENCODING 7808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wgrave +ENCODING 7809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wacute +ENCODING 7810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wacute +ENCODING 7811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wdieresis +ENCODING 7812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wdieresis +ENCODING 7813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ygrave +ENCODING 7922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ygrave +ENCODING 7923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +60 +20 +40 +ENDCHAR +STARTCHAR uni2010 +ENCODING 8208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR uni2011 +ENCODING 8209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR figuredash +ENCODING 8210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR afii00208 +ENCODING 8213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2016 +ENCODING 8214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR underscoredbl +ENCODING 8215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +F0 +ENDCHAR +STARTCHAR quoteleft +ENCODING 8216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +00 +00 +00 +ENDCHAR +STARTCHAR quoteright +ENCODING 8217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR quotesinglbase +ENCODING 8218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +20 +40 +ENDCHAR +STARTCHAR quotereversed +ENCODING 8219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblleft +ENCODING 8220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblright +ENCODING 8221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblbase +ENCODING 8222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +50 +50 +A0 +ENDCHAR +STARTCHAR uni201F +ENCODING 8223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +50 +00 +00 +00 +ENDCHAR +STARTCHAR dagger +ENCODING 8224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR daggerdbl +ENCODING 8225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2023 +ENCODING 8227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +E0 +C0 +00 +00 +ENDCHAR +STARTCHAR onedotenleader +ENCODING 8228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR twodotenleader +ENCODING 8229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +A0 +00 +ENDCHAR +STARTCHAR ellipsis +ENCODING 8230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +B0 +00 +ENDCHAR +STARTCHAR uni2027 +ENCODING 8231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR perthousand +ENCODING 8240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +80 +30 +00 +ENDCHAR +STARTCHAR guilsinglleft +ENCODING 8249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +80 +40 +00 +00 +ENDCHAR +STARTCHAR guilsinglright +ENCODING 8250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +20 +40 +00 +00 +ENDCHAR +STARTCHAR uni203E +ENCODING 8254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR nsuperior +ENCODING 8319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR peseta +ENCODING 8359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR Euro +ENCODING 8364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR afii61352 +ENCODING 8470 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +B0 +B0 +A0 +B0 +00 +ENDCHAR +STARTCHAR trademark +ENCODING 8482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +00 +E0 +A0 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 8486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni2127 +ENCODING 8487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR oneeighth +ENCODING 8539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +20 +50 +20 +ENDCHAR +STARTCHAR threeeighths +ENCODING 8540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +60 +D0 +20 +ENDCHAR +STARTCHAR fiveeighths +ENCODING 8541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +70 +A0 +50 +20 +ENDCHAR +STARTCHAR seveneighths +ENCODING 8542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +A0 +50 +20 +ENDCHAR +STARTCHAR arrowleft +ENCODING 8592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +F0 +40 +00 +00 +ENDCHAR +STARTCHAR arrowup +ENCODING 8593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR arrowright +ENCODING 8594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +F0 +20 +00 +00 +ENDCHAR +STARTCHAR arrowdown +ENCODING 8595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR arrowboth +ENCODING 8596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +F0 +50 +00 +00 +ENDCHAR +STARTCHAR arrowupdn +ENCODING 8597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR universal +ENCODING 8704 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR uni2201 +ENCODING 8705 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR partialdiff +ENCODING 8706 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR existential +ENCODING 8707 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR uni2204 +ENCODING 8708 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +E0 +60 +E0 +80 +ENDCHAR +STARTCHAR emptyset +ENCODING 8709 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR Delta +ENCODING 8710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR gradient +ENCODING 8711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR element +ENCODING 8712 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +80 +60 +00 +ENDCHAR +STARTCHAR notelement +ENCODING 8713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +E0 +A0 +60 +40 +ENDCHAR +STARTCHAR uni220A +ENCODING 8714 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +C0 +80 +40 +00 +ENDCHAR +STARTCHAR suchthat +ENCODING 8715 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +E0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni220C +ENCODING 8716 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +E0 +60 +C0 +80 +ENDCHAR +STARTCHAR uni220D +ENCODING 8717 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +C0 +40 +80 +00 +ENDCHAR +STARTCHAR uni220E +ENCODING 8718 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +00 +ENDCHAR +STARTCHAR product +ENCODING 8719 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2210 +ENCODING 8720 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR summation +ENCODING 8721 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR minus +ENCODING 8722 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2213 +ENCODING 8723 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni2214 +ENCODING 8724 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR fraction +ENCODING 8725 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR uni2216 +ENCODING 8726 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR asteriskmath +ENCODING 8727 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +70 +E0 +50 +40 +ENDCHAR +STARTCHAR uni2218 +ENCODING 8728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +00 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 8729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR radical +ENCODING 8730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +20 +A0 +60 +00 +ENDCHAR +STARTCHAR uni221B +ENCODING 8731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +50 +D0 +10 +50 +30 +ENDCHAR +STARTCHAR uni221C +ENCODING 8732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +D0 +50 +10 +50 +30 +ENDCHAR +STARTCHAR proportional +ENCODING 8733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +E0 +50 +00 +ENDCHAR +STARTCHAR infinity +ENCODING 8734 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +D0 +B0 +40 +00 +ENDCHAR +STARTCHAR orthogonal +ENCODING 8735 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR angle +ENCODING 8736 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR uni2221 +ENCODING 8737 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +A0 +40 +A0 +F0 +20 +ENDCHAR +STARTCHAR uni2222 +ENCODING 8738 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +A0 +A0 +60 +90 +ENDCHAR +STARTCHAR uni2223 +ENCODING 8739 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni2224 +ENCODING 8740 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +40 +00 +ENDCHAR +STARTCHAR uni2225 +ENCODING 8741 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2226 +ENCODING 8742 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +B0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicaland +ENCODING 8743 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicalor +ENCODING 8744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR intersection +ENCODING 8745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR union +ENCODING 8746 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR integral +ENCODING 8747 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni222C +ENCODING 8748 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +A0 +A0 +80 +ENDCHAR +STARTCHAR uni222D +ENCODING 8749 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +D0 +D0 +D0 +A0 +ENDCHAR +STARTCHAR uni222E +ENCODING 8750 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +E0 +40 +80 +ENDCHAR +STARTCHAR uni222F +ENCODING 8751 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +80 +ENDCHAR +STARTCHAR uni2230 +ENCODING 8752 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +F0 +F0 +D0 +A0 +ENDCHAR +STARTCHAR uni2231 +ENCODING 8753 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +50 +40 +80 +ENDCHAR +STARTCHAR uni2232 +ENCODING 8754 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +C0 +40 +80 +ENDCHAR +STARTCHAR uni2233 +ENCODING 8755 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +E0 +40 +80 +ENDCHAR +STARTCHAR therefore +ENCODING 8756 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2235 +ENCODING 8757 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +40 +00 +ENDCHAR +STARTCHAR uni2236 +ENCODING 8758 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2237 +ENCODING 8759 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2238 +ENCODING 8760 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2239 +ENCODING 8761 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +20 +C0 +20 +00 +ENDCHAR +STARTCHAR uni223A +ENCODING 8762 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni223B +ENCODING 8763 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +50 +A0 +00 +40 +ENDCHAR +STARTCHAR similar +ENCODING 8764 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni223D +ENCODING 8765 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni223E +ENCODING 8766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +D0 +B0 +00 +00 +ENDCHAR +STARTCHAR uni223F +ENCODING 8767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +50 +A0 +20 +00 +ENDCHAR +STARTCHAR uni2240 +ENCODING 8768 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +40 +40 +20 +00 +ENDCHAR +STARTCHAR uni2241 +ENCODING 8769 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +B0 +D0 +40 +80 +ENDCHAR +STARTCHAR uni2242 +ENCODING 8770 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +00 +A0 +50 +00 +ENDCHAR +STARTCHAR uni2243 +ENCODING 8771 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2244 +ENCODING 8772 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +D0 +B0 +40 +F0 +40 +ENDCHAR +STARTCHAR congruent +ENCODING 8773 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni2246 +ENCODING 8774 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR uni2247 +ENCODING 8775 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR approxequal +ENCODING 8776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +50 +A0 +00 +ENDCHAR +STARTCHAR uni2249 +ENCODING 8777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +40 +50 +E0 +80 +ENDCHAR +STARTCHAR uni224A +ENCODING 8778 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +00 +F0 +ENDCHAR +STARTCHAR uni224B +ENCODING 8779 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +40 +B0 +ENDCHAR +STARTCHAR uni224C +ENCODING 8780 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +50 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni224D +ENCODING 8781 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +40 +A0 +00 +ENDCHAR +STARTCHAR uni224E +ENCODING 8782 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +A0 +40 +00 +ENDCHAR +STARTCHAR uni224F +ENCODING 8783 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2250 +ENCODING 8784 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2251 +ENCODING 8785 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +40 +ENDCHAR +STARTCHAR uni2252 +ENCODING 8786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +00 +E0 +00 +20 +ENDCHAR +STARTCHAR uni2253 +ENCODING 8787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +00 +E0 +00 +80 +ENDCHAR +STARTCHAR uni2254 +ENCODING 8788 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +00 +B0 +00 +00 +ENDCHAR +STARTCHAR uni2255 +ENCODING 8789 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +D0 +00 +D0 +00 +00 +ENDCHAR +STARTCHAR uni2256 +ENCODING 8790 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2257 +ENCODING 8791 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2258 +ENCODING 8792 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2259 +ENCODING 8793 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225A +ENCODING 8794 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225B +ENCODING 8795 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225C +ENCODING 8796 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225D +ENCODING 8797 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225E +ENCODING 8798 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225F +ENCODING 8799 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR notequal +ENCODING 8800 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR equivalence +ENCODING 8801 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2262 +ENCODING 8802 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2263 +ENCODING 8803 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR lessequal +ENCODING 8804 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR greaterequal +ENCODING 8805 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2266 +ENCODING 8806 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2267 +ENCODING 8807 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2268 +ENCODING 8808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2269 +ENCODING 8809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni226A +ENCODING 8810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni226B +ENCODING 8811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni226C +ENCODING 8812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni226D +ENCODING 8813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR uni226E +ENCODING 8814 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +60 +80 +00 +ENDCHAR +STARTCHAR uni226F +ENCODING 8815 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +60 +C0 +80 +00 +ENDCHAR +STARTCHAR uni2270 +ENCODING 8816 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2271 +ENCODING 8817 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2272 +ENCODING 8818 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +50 +A0 +ENDCHAR +STARTCHAR uni2273 +ENCODING 8819 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2276 +ENCODING 8822 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +20 +80 +60 +C0 +ENDCHAR +STARTCHAR uni2277 +ENCODING 8823 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +80 +20 +C0 +60 +ENDCHAR +STARTCHAR uni2278 +ENCODING 8824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +60 +C0 +60 +C0 +ENDCHAR +STARTCHAR uni2279 +ENCODING 8825 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +60 +C0 +60 +ENDCHAR +STARTCHAR uni227A +ENCODING 8826 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +C0 +20 +00 +00 +ENDCHAR +STARTCHAR uni227B +ENCODING 8827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +60 +80 +00 +00 +ENDCHAR +STARTCHAR uni227C +ENCODING 8828 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227D +ENCODING 8829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +80 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227E +ENCODING 8830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni227F +ENCODING 8831 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2280 +ENCODING 8832 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2281 +ENCODING 8833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR propersubset +ENCODING 8834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +60 +00 +00 +ENDCHAR +STARTCHAR propersuperset +ENCODING 8835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +C0 +00 +00 +ENDCHAR +STARTCHAR notsubset +ENCODING 8836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2285 +ENCODING 8837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR reflexsubset +ENCODING 8838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR reflexsuperset +ENCODING 8839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2288 +ENCODING 8840 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2289 +ENCODING 8841 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +40 +ENDCHAR +STARTCHAR uni228A +ENCODING 8842 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni228B +ENCODING 8843 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +40 +E0 +80 +ENDCHAR +STARTCHAR revlogicalnot +ENCODING 8976 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +80 +00 +00 +ENDCHAR +STARTCHAR integraltp +ENCODING 8992 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR integralbt +ENCODING 8993 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +20 +20 +40 +ENDCHAR +STARTCHAR uni23BA +ENCODING 9146 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BB +ENCODING 9147 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BC +ENCODING 9148 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni23BD +ENCODING 9149 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2409 +ENCODING 9225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +70 +20 +20 +ENDCHAR +STARTCHAR uni240A +ENCODING 9226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +60 +40 +40 +ENDCHAR +STARTCHAR uni240B +ENCODING 9227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +70 +20 +20 +ENDCHAR +STARTCHAR uni240C +ENCODING 9228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +80 +60 +60 +40 +ENDCHAR +STARTCHAR uni240D +ENCODING 9229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +E0 +50 +60 +50 +ENDCHAR +STARTCHAR uni2423 +ENCODING 9251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +90 +F0 +ENDCHAR +STARTCHAR uni2424 +ENCODING 9252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +B0 +90 +20 +20 +30 +ENDCHAR +STARTCHAR SF100000 +ENCODING 9472 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2501 +ENCODING 9473 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +00 +00 +ENDCHAR +STARTCHAR SF110000 +ENCODING 9474 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni2503 +ENCODING 9475 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR uni2504 +ENCODING 9476 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2505 +ENCODING 9477 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni2506 +ENCODING 9478 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2507 +ENCODING 9479 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR uni2508 +ENCODING 9480 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2509 +ENCODING 9481 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni250A +ENCODING 9482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni250B +ENCODING 9483 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR SF010000 +ENCODING 9484 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +40 +40 +ENDCHAR +STARTCHAR uni250D +ENCODING 9485 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni250E +ENCODING 9486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR uni250F +ENCODING 9487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF030000 +ENCODING 9488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2511 +ENCODING 9489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2512 +ENCODING 9490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2513 +ENCODING 9491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF020000 +ENCODING 9492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +00 +00 +ENDCHAR +STARTCHAR uni2515 +ENCODING 9493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni2516 +ENCODING 9494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR uni2517 +ENCODING 9495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +00 +00 +ENDCHAR +STARTCHAR SF040000 +ENCODING 9496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2519 +ENCODING 9497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni251A +ENCODING 9498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR uni251B +ENCODING 9499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +00 +00 +ENDCHAR +STARTCHAR SF080000 +ENCODING 9500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +40 +40 +ENDCHAR +STARTCHAR uni251D +ENCODING 9501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni251E +ENCODING 9502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +40 +40 +ENDCHAR +STARTCHAR uni251F +ENCODING 9503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +60 +60 +ENDCHAR +STARTCHAR uni2520 +ENCODING 9504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR uni2521 +ENCODING 9505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni2522 +ENCODING 9506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +60 +60 +ENDCHAR +STARTCHAR uni2523 +ENCODING 9507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF090000 +ENCODING 9508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2525 +ENCODING 9509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2526 +ENCODING 9510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +40 +40 +ENDCHAR +STARTCHAR uni2527 +ENCODING 9511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2528 +ENCODING 9512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2529 +ENCODING 9513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +40 +40 +ENDCHAR +STARTCHAR uni252A +ENCODING 9514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR uni252B +ENCODING 9515 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF060000 +ENCODING 9516 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252D +ENCODING 9517 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252E +ENCODING 9518 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252F +ENCODING 9519 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2530 +ENCODING 9520 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2531 +ENCODING 9521 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2532 +ENCODING 9522 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2533 +ENCODING 9523 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR SF070000 +ENCODING 9524 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2535 +ENCODING 9525 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2536 +ENCODING 9526 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2537 +ENCODING 9527 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2538 +ENCODING 9528 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2539 +ENCODING 9529 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253A +ENCODING 9530 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253B +ENCODING 9531 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR SF050000 +ENCODING 9532 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253D +ENCODING 9533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253E +ENCODING 9534 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253F +ENCODING 9535 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2540 +ENCODING 9536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2541 +ENCODING 9537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2542 +ENCODING 9538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2543 +ENCODING 9539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2544 +ENCODING 9540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2545 +ENCODING 9541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2546 +ENCODING 9542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2547 +ENCODING 9543 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2548 +ENCODING 9544 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2549 +ENCODING 9545 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254A +ENCODING 9546 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254B +ENCODING 9547 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254C +ENCODING 9548 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254D +ENCODING 9549 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254E +ENCODING 9550 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +00 +40 +40 +ENDCHAR +STARTCHAR uni254F +ENCODING 9551 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +60 +00 +60 +60 +ENDCHAR +STARTCHAR SF430000 +ENCODING 9552 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF240000 +ENCODING 9553 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR SF510000 +ENCODING 9554 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF520000 +ENCODING 9555 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR SF390000 +ENCODING 9556 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF220000 +ENCODING 9557 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF210000 +ENCODING 9558 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR SF250000 +ENCODING 9559 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF500000 +ENCODING 9560 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF490000 +ENCODING 9561 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR SF380000 +ENCODING 9562 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF280000 +ENCODING 9563 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +00 +ENDCHAR +STARTCHAR SF270000 +ENCODING 9564 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR SF260000 +ENCODING 9565 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR SF360000 +ENCODING 9566 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF370000 +ENCODING 9567 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR SF420000 +ENCODING 9568 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF190000 +ENCODING 9569 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF200000 +ENCODING 9570 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR SF230000 +ENCODING 9571 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF470000 +ENCODING 9572 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +40 +ENDCHAR +STARTCHAR SF480000 +ENCODING 9573 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR SF410000 +ENCODING 9574 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR SF450000 +ENCODING 9575 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF460000 +ENCODING 9576 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR SF400000 +ENCODING 9577 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF540000 +ENCODING 9578 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +40 +F0 +40 +ENDCHAR +STARTCHAR SF530000 +ENCODING 9579 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR SF440000 +ENCODING 9580 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR uni256D +ENCODING 9581 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +30 +40 +40 +ENDCHAR +STARTCHAR uni256E +ENCODING 9582 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +80 +40 +40 +ENDCHAR +STARTCHAR uni256F +ENCODING 9583 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +80 +00 +00 +ENDCHAR +STARTCHAR uni2570 +ENCODING 9584 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +30 +00 +00 +ENDCHAR +STARTCHAR uni2571 +ENCODING 9585 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +20 +40 +40 +80 +ENDCHAR +STARTCHAR uni2572 +ENCODING 9586 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +20 +20 +10 +ENDCHAR +STARTCHAR uni2573 +ENCODING 9587 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +60 +90 +90 +ENDCHAR +STARTCHAR uni2574 +ENCODING 9588 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2575 +ENCODING 9589 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR uni2576 +ENCODING 9590 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +00 +00 +ENDCHAR +STARTCHAR uni2577 +ENCODING 9591 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +40 +40 +ENDCHAR +STARTCHAR uni2578 +ENCODING 9592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2579 +ENCODING 9593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR uni257A +ENCODING 9594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni257B +ENCODING 9595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +60 +60 +ENDCHAR +STARTCHAR uni257C +ENCODING 9596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +30 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257D +ENCODING 9597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +60 +60 +60 +ENDCHAR +STARTCHAR uni257E +ENCODING 9598 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257F +ENCODING 9599 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +40 +40 +ENDCHAR +STARTCHAR upblock +ENCODING 9600 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +00 +00 +00 +ENDCHAR +STARTCHAR uni2581 +ENCODING 9601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2582 +ENCODING 9602 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F8 +ENDCHAR +STARTCHAR uni2583 +ENCODING 9603 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F8 +F8 +ENDCHAR +STARTCHAR dnblock +ENCODING 9604 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2585 +ENCODING 9605 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2586 +ENCODING 9606 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2587 +ENCODING 9607 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR block +ENCODING 9608 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2589 +ENCODING 9609 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +F0 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR uni258A +ENCODING 9610 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR uni258B +ENCODING 9611 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR lfblock +ENCODING 9612 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258D +ENCODING 9613 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258E +ENCODING 9614 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni258F +ENCODING 9615 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR rtblock +ENCODING 9616 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR ltshade +ENCODING 9617 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +80 +20 +80 +20 +ENDCHAR +STARTCHAR shade +ENCODING 9618 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A8 +50 +A8 +50 +A8 +50 +ENDCHAR +STARTCHAR dkshade +ENCODING 9619 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B8 +E8 +B8 +E8 +B8 +E8 +ENDCHAR +STARTCHAR uni2594 +ENCODING 9620 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni2595 +ENCODING 9621 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR filledbox +ENCODING 9632 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR H22073 +ENCODING 9633 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uni25C6 +ENCODING 9670 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR spade +ENCODING 9824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR club +ENCODING 9827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +E0 +00 +ENDCHAR +STARTCHAR heart +ENCODING 9829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR diamond +ENCODING 9830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2669 +ENCODING 9833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnote +ENCODING 9834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnotedbl +ENCODING 9835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +50 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266C +ENCODING 9836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +70 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266D +ENCODING 9837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni266E +ENCODING 9838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +A0 +E0 +20 +00 +ENDCHAR +STARTCHAR uni266F +ENCODING 9839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uniFFFD +ENCODING 65533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +90 +D0 +F0 +D0 +F0 +ENDCHAR +ENDFONT diff --git a/src/col64/cruft/col64font_ext.hex b/src/col64/cruft/col64font_ext.hex new file mode 100644 index 0000000..2fefbf5 --- /dev/null +++ b/src/col64/cruft/col64font_ext.hex @@ -0,0 +1,920 @@ +0000:A000A000A000 +0020:000000000000 +0021:404040004000 +0022:A0A000000000 +0023:A0F0A0F0A000 +0024:70A06050E000 +0025:009020409000 +0026:40A040A0D000 +0027:202040000000 +0028:204040402000 +0029:402020204000 +002A:A040E040A000 +002B:4040E0404000 +002C:000000204000 +002D:0000F0000000 +002E:000000004000 +002F:202040808000 +0030:6090B0D06000 +0031:40C04040E000 +0032:60902040F000 +0033:E0106010E000 +0034:2060A0F02000 +0035:F080E010E000 +0036:7080E0906000 +0037:F01020404000 +0038:609060906000 +0039:60907010E000 +003A:004000004000 +003B:002000204000 +003C:204080402000 +003D:00F000F00000 +003E:804020408000 +003F:709020002000 +0040:60B0B0806000 +0041:6090F0909000 +0042:E090E090E000 +0043:609080906000 +0044:E0909090E000 +0045:F080E080F000 +0046:F080E0808000 +0047:7080B0906000 +0048:9090F0909000 +0049:E0404040E000 +004A:301010906000 +004B:90A0C0A09000 +004C:80808080F000 +004D:A0F0D0909000 +004E:90D0B0909000 +004F:609090906000 +0050:E090E0808000 +0051:609090A05000 +0052:E090E0A09000 +0053:70806010E000 +0054:F04040404000 +0055:909090906000 +0056:909090A04000 +0057:9090D0F0A000 +0058:909060909000 +0059:909060204000 +005A:F0204080F000 +005B:604040406000 +005C:808040202000 +005D:602020206000 +005E:40A000000000 +005F:00000000F000 +0060:404020000000 +0061:007090B05000 +0062:8080E090E000 +0063:007080807000 +0064:101070907000 +0065:006090E07000 +0066:6040E0404000 +0067:007090701000 +0068:8080E0909000 +0069:4000C040E000 +006A:200060202000 +006B:80A0C0A09000 +006C:C0404040E000 +006D:00A0F0D09000 +006E:00E090909000 +006F:006090906000 +0070:00E090E08000 +0071:007090701000 +0072:00A0D0808000 +0073:0070C030E000 +0074:40E040402000 +0075:009090906000 +0076:009090A04000 +0077:0090D0F0A000 +0078:009060609000 +0079:009090602000 +007A:00F02040F000 +007B:604080406000 +007C:404040404000 +007D:C0402040C000 +007E:0050A0000000 +007F:60C08010C000 +00A0:000000000000 +00A1:400040404000 +00A2:40E080E04000 +00A3:20406040A000 +00A4:009060609000 +00A5:A040E0404000 +00A6:404000404000 +00A7:60C0A06020C0 +00A8:A00000000000 +00A9:6090D0D09060 +00AA:60A06000E000 +00AB:0050A0500000 +00AC:0000E0200000 +00AD:0000E0000000 +00AE:60F0D0600000 +00AF:E00000000000 +00B0:40A040000000 +00B1:40E04000E000 +00B2:C04080C00000 +00B3:C04080408000 +00B4:204000000000 +00B5:00A0A0A0C080 +00B6:70D0D0505000 +00B7:000040000000 +00B8:000000204000 +00B9:40C040400000 +00BA:40A04000E000 +00BB:00A050A00000 +00BC:808080507010 +00BD:8080B0102030 +00BE:C0408050B010 +00BF:400040806000 +00C0:8040A0E0A000 +00C1:2040A0E0A000 +00C2:C040A0E0A000 +00C3:60C0A0E0A000 +00C4:A040A0E0A000 +00C5:4040A0E0A000 +00C6:70A0F0A0B000 +00C7:40A080A04080 +00C8:80E0C080E000 +00C9:20E0C080E000 +00CA:60E0C080E000 +00CB:A0E0C080E000 +00CC:80E04040E000 +00CD:20E04040E000 +00CE:40E04040E000 +00CF:A0404040E000 +00D0:E050D050E000 +00D1:50A0E0E0A000 +00D2:8040A0A04000 +00D3:2040A0A04000 +00D4:4040A0A04000 +00D5:70E0A0A04000 +00D6:A040A0A04000 +00D7:00A040A00000 +00D8:60A0E0A0C000 +00D9:8040A0A0E000 +00DA:2040A0A0E000 +00DB:4000A0A0E000 +00DC:A000A0A0E000 +00DD:2000A0404000 +00DE:80C0A0C08000 +00DF:40A0C0A0E080 +00E0:804060A06000 +00E1:204060A06000 +00E2:600060A06000 +00E3:50A060A06000 +00E4:A00060A06000 +00E5:400060A06000 +00E6:0070B0A07000 +00E7:0040A0806040 +00E8:8040A0C06000 +00E9:2040A0C06000 +00EA:C040A0C06000 +00EB:A040A0C06000 +00EC:80404040E000 +00ED:20C04040E000 +00EE:40A04040E000 +00EF:A000C040E000 +00F0:A04060A04000 +00F1:50A0C0A0A000 +00F2:804040A04000 +00F3:204040A04000 +00F4:400040A04000 +00F5:E00040A04000 +00F6:A00040A04000 +00F7:4000E0004000 +00F8:0060A0A0C000 +00F9:8040A0A06000 +00FA:2040A0A06000 +00FB:4000A0A06000 +00FC:A000A0A06000 +00FD:2040A0E020C0 +00FE:8080C0A0C080 +00FF:A000A0E020C0 +0100:E040A0E0A000 +0101:E00060A06000 +0102:A040A0E0A000 +0103:A04060A06000 +0104:0040A0E0A020 +0105:000060A06020 +0106:60A080A04000 +0107:2040A0806000 +0108:E0A080A04000 +0109:600060806000 +010A:40E080A04000 +010B:400060806000 +010C:E0A080A04000 +010D:A04060806000 +010E:E0C0A0A0C000 +010F:302060A06000 +0110:C0A0E0A0C000 +0111:602060A06000 +0112:E0E0C080E000 +0113:E040A0C06000 +0114:A0E0C080E000 +0115:A040A0C06000 +0116:40E0C080E000 +0117:4040A0C06000 +0118:E080C080E020 +0119:0040A0C06040 +011A:A0E0C080E000 +011B:A040A0C06000 +011C:606080A06000 +011D:6060A06020C0 +011E:A06080A06000 +011F:A040A06020C0 +0120:406080A06000 +0121:4060A06020C0 +0122:6080A0A04040 +0123:4060A06020C0 +0124:6000A0E0A000 +0125:40A0C0A0A000 +0126:A0E0A0E0A000 +0127:80C0C0A0A000 +0128:50A04040E000 +0129:50A0C040E000 +012A:E000E040E000 +012B:E000C040E000 +012C:A040E040E000 +012D:A040C040E000 +012E:E0404040E020 +012F:4000C040E020 +0130:4000E040E000 +0131:0000C040E000 +0132:80A0A0A02060 +0133:A000A0A02040 +0134:60A020A04000 +0135:40A0002020C0 +0136:A0A0C0A02040 +0137:80A0C0A02040 +0138:00A0A0C0A000 +0139:40808080E000 +013A:20C04040E000 +013B:80808080E020 +013C:C0404040E020 +013D:A0C08080E000 +013E:D0404040E000 +013F:8080A080E000 +0140:C0405040E000 +0141:80A0C080E000 +0142:C060C040E000 +0143:20A0E0A08000 +0144:2040C0A0A000 +0145:20A0E0A08020 +0146:00C0A0A00040 +0147:20A0E0A08000 +0148:A040C0A0A000 +0149:8000C0A0A000 +014A:A0E0E0A02040 +014B:00C0A0A02040 +014C:E040A0A04000 +014D:E00040A04000 +014E:A040A0A04000 +014F:A04040A04000 +0150:A040A0A04000 +0151:A0A040A04000 +0152:50A0B0A07000 +0153:0070B0A07000 +0154:20C0A0C0A000 +0155:2000A0C08000 +0156:C0A0C0A00040 +0157:00A0C0808020 +0158:60C0A0C0A000 +0159:6000A0C08000 +015A:2060C020C000 +015B:2060C020C000 +015C:6060C020C000 +015D:6060C020C000 +015E:60804020C040 +015F:0060C020E040 +0160:6060C020E000 +0161:6060C020C000 +0162:E04040402040 +0163:40E040402040 +0164:A040E0404000 +0165:A040E0402000 +0166:E040E0404000 +0167:E040E0402000 +0168:D020A0A0E000 +0169:50A000A06000 +016A:E000A0A0E000 +016B:E000A0A06000 +016C:A040A0A0E000 +016D:A04000A06000 +016E:4000A0A0E000 +016F:4000A0A06000 +0170:A000A0A0E000 +0171:A000A0A06000 +0172:00A0A0A04020 +0173:00A0A0A06040 +0174:40A0A0E0A000 +0175:4000A0E0E000 +0176:6000A0404000 +0177:4000A0408000 +0178:A000A0404000 +0179:40E04080E000 +017A:40E04080E000 +017B:40E04080E000 +017C:40E04080E000 +017D:A0E04080E000 +017E:A0E04080E000 +017F:2040C0404000 +018F:00C060A04000 +0192:2040E0404080 +0218:60804020C040 +0219:0060C020E040 +021A:E04040400040 +021B:40E040402040 +0259:00C060A04000 +02C6:40A000000000 +02C7:A04000000000 +02C9:E00000000000 +02D8:906000000000 +02D9:400000000000 +02DA:40A040000000 +02DB:0000004080C0 +02DC:50A000000000 +02DD:A0A000000000 +0374:204000000000 +0375:000000004080 +037A:000000004060 +037E:004000004080 +0384:204000000000 +0385:B04000000000 +0386:C0A0E0A0A000 +0387:000040000000 +0388:E0C060406000 +0389:A020E0A0A000 +038A:E0C04040E000 +038C:C0A0A0A04000 +038E:A0A0C0404000 +038F:C0A0A040A000 +0390:B04000402000 +0391:40A0E0A0A000 +0392:C0A0C0A0C000 +0393:E08080808000 +0394:4040A0A0E000 +0395:E080C080E000 +0396:E0204080E000 +0397:A0A0E0A0A000 +0398:40A0E0A04000 +0399:E0404040E000 +039A:A0A0C0A0A000 +039B:4040A0A0A000 +039C:A0E0A0A0A000 +039D:20A0E0A08000 +039E:E0004000E000 +039F:40A0A0A04000 +03A0:E0A0A0A0A000 +03A1:C0A0C0808000 +03A3:E0804080E000 +03A4:E04040404000 +03A5:A0A040404000 +03A6:40E0A0E04000 +03A7:A0A040A0A000 +03A8:A0E0E0404000 +03A9:40A0A040A000 +03AA:A000E040E000 +03AB:A000A0404000 +03AC:408060A06000 +03AD:20C040806000 +03AE:2040C0A02040 +03AF:200040402000 +03B0:B040A0A0C000 +03B1:0050A0A05000 +03B2:40A0C0A0C000 +03B3:00A060404000 +03B4:608040A04000 +03B5:00E0C0806000 +03B6:E04080E02040 +03B7:00C0A0A02040 +03B8:40A0E0A04000 +03B9:004040402000 +03BA:00A0A0C0A000 +03BB:C02060A0A000 +03BC:00A0A0A0C080 +03BD:00A0A0604000 +03BE:60A040806000 +03BF:0040A0A04000 +03C0:00E0A0A0A000 +03C1:0040A0A0C080 +03C2:00608040C000 +03C3:0060C0A04000 +03C4:00E040402000 +03C5:0080A0A0C000 +03C6:0040E0A04040 +03C7:00A04060A000 +03C8:00A0E0E04000 +03C9:00A0A0E0E000 +03CA:A00040402000 +03CB:A000A0A0C000 +03CC:204040A04000 +03CD:2000A0A0C000 +03CE:2000A0E0E000 +0401:A0E0C080E000 +0402:E080C0A0A000 +0403:20E080808000 +0404:6080C0806000 +0405:60804020C000 +0406:E0404040E000 +0407:A0E04040E000 +0408:202020A04000 +0409:E060A0B0B000 +040A:A0A0E0B0B000 +040B:C080C0A0A000 +040C:2080A0C0A000 +040E:A04000A04080 +040F:A0A0A0A0E040 +0410:40A0E0A0A000 +0411:E080C0A0C000 +0412:C0A0C0A0C000 +0413:E08080808000 +0414:E060A0A0E0A0 +0415:E080C080E000 +0416:A0E040E0A000 +0417:C0204020C000 +0418:80A0E0A02000 +0419:6080A0E0A020 +041A:A0A0C0A0A000 +041B:60A0A0A0A000 +041C:A0E0A0A0A000 +041D:A0A0E0A0A000 +041E:40A0A0A04000 +041F:E0A0A0A0A000 +0420:C0A0C0808000 +0421:40A080A04000 +0422:E04040404000 +0423:A0A0A0404080 +0424:40E0A0E04000 +0425:A0A040A0A000 +0426:A0A0A0A0E000 +0427:A0A060202000 +0428:A0A0E0E0E000 +0429:A0A0E0E0F010 +042A:C04060506000 +042B:9090D0B0D000 +042C:8080C0A0C000 +042D:C0206020C000 +042E:A0D0D0D0A000 +042F:60A060A0A000 +0430:0060A0A06000 +0431:6080E0A04000 +0432:00E0C0A0C000 +0433:00E080808000 +0434:0060A0A0E0A0 +0435:0040A0C06000 +0436:00B06060B000 +0437:00E04020C000 +0438:00A0E0E0A000 +0439:A040A0E0A000 +043A:00A0A0C0A000 +043B:0060A0A0A000 +043C:00A0E0A0A000 +043D:00A0E0A0A000 +043E:0040A0A04000 +043F:00E0A0A0A000 +0440:00C0A0C08080 +0441:006080806000 +0442:00E040404000 +0443:00A0A06020C0 +0444:4040A0A04040 +0445:00A04040A000 +0446:00A0A0A0E020 +0447:00A0A0602000 +0448:00A0E0E0E000 +0449:00A0E0E0F010 +044A:00C060506000 +044B:0090D0B0D000 +044C:0080C0A0C000 +044D:00C06020C000 +044E:00A0D0D0A000 +044F:0060A060A000 +0451:A040A0C06000 +0452:80C080C0A020 +0453:2040E0808000 +0454:0060C0806000 +0455:0060C020C000 +0456:4000C040E000 +0457:A000C040E000 +0458:2000202020C0 +0459:0060A0B0B000 +045A:00A0E0B0B000 +045B:80C080C0A000 +045C:2080A0C0A000 +045E:A04000A04080 +045F:00A0A0A0E040 +0490:20E080808000 +0491:0020E0808000 +0492:6040E0404000 +0493:006040E04000 +05D0:00A060C0A000 +05D1:00E02020F000 +05D2:80404040A000 +05D3:00E020202000 +05D4:80E020A0A000 +05D5:402020202000 +05D6:806040404000 +05D7:00E0A0A0A000 +05D8:A0A0A0A0C000 +05D9:C02020000000 +05DA:00E020202020 +05DB:00E02020C000 +05DC:80E020204000 +05DD:8060A0A0E000 +05DE:8060A0A0A000 +05DF:806020202000 +05E0:402020206000 +05E1:8060A0A04000 +05E2:A0A0A060C000 +05E3:00E0A0202020 +05E4:00E0A020E000 +05E5:00A0A0C08080 +05E6:00A04020E000 +05E7:00E020C08080 +05E8:00C020202000 +05E9:00F0D0A0E000 +05EA:8060A0A0A000 +1E02:40E0C0A0C000 +1E03:A080C0A0C000 +1E0A:40C0A0A0C000 +1E0B:A02060A06000 +1E1E:40E080C08000 +1E1F:802040E04000 +1E40:4000E0A0A000 +1E41:4000A0E0A000 +1E56:40C0A0C08000 +1E57:4000C0A0C080 +1E60:40E0C020C000 +1E61:4060C020C000 +1E6A:40E040404000 +1E6B:400040E04020 +1E80:8020A0E0E000 +1E81:8040A0A0E000 +1E82:2080A0E0E000 +1E83:2040A0A0E000 +1E84:A000A0E0E000 +1E85:A000A0E0E000 +1EF2:8020A0404000 +1EF3:8040A0602040 +2010:000060000000 +2011:000060000000 +2012:0000E0000000 +2013:0000E0000000 +2014:0000F0000000 +2015:0000F0000000 +2016:A0A0A0A0A0A0 +2017:000000F000F0 +2018:204060000000 +2019:602040000000 +201A:000000602040 +201B:604020000000 +201C:50A0A0000000 +201D:5050A0000000 +201E:0000005050A0 +201F:A0A050000000 +2020:40E040404000 +2021:40E040E04000 +2022:0040E0400000 +2023:00C0E0C00000 +2024:000000004000 +2025:00000000A000 +2026:00000000B000 +2027:000040000000 +2030:802040803000 +2039:004080400000 +203A:004020400000 +203E:F80000000000 +207F:00C0A0A00000 +20A7:60F060404000 +20AC:2040E0402000 +2116:C0B0B0A0B000 +2122:E04000E0A000 +2126:40A0A040A000 +2127:A040A0A04000 +215B:8080B0205020 +215C:C040B060D020 +215D:C08070A05020 +215E:C040B0A05020 +2190:0040F0400000 +2191:0040E0404000 +2192:0020F0200000 +2193:004040E04000 +2194:0050F0500000 +2195:40E040E04000 +2200:A0A0E0A04000 +2201:40A080A04000 +2202:C02060A04000 +2203:E020E020E000 +2204:F020E060E080 +2205:2060A0A0C080 +2206:4040A0A0E000 +2207:E0A0A0404000 +2208:6080E0806000 +2209:70A0E0A06040 +220A:4080C0804000 +220B:C020E020C000 +220C:D020E060C080 +220D:8040C0408000 +220E:C0C0C0C0C000 +220F:E0A0A0A0A000 +2210:A0A0A0A0E000 +2211:E0804080E000 +2212:0000E0000000 +2213:E00040E04000 +2214:400040E04000 +2215:202040808000 +2216:808040202000 +2217:20A070E05040 +2218:0040A0400000 +2219:0040E0400000 +221A:302020A06000 +221B:D050D0105030 +221C:D0D050105030 +221D:000050E05000 +221E:0020D0B04000 +221F:00008080E000 +2220:00204080E000 +2221:10A040A0F020 +2222:9060A0A06090 +2223:404040404000 +2224:406040C04000 +2225:A0A0A0A0A000 +2226:A0B0E0A0A000 +2227:004040A0A000 +2228:00A0A0404000 +2229:0040A0A0A000 +222A:00A0A0A04000 +222B:204040404080 +222C:50A0A0A0A080 +222D:50D0D0D0D0A0 +222E:2040E0E04080 +222F:50A0E0E0A080 +2230:50D0F0F0D0A0 +2231:2040E0504080 +2232:2040E0C04080 +2233:2040C0E04080 +2234:00004000A000 +2235:0000A0004000 +2236:000040004000 +2237:0000A000A000 +2238:004000E00000 +2239:000020C02000 +223A:A000E000A000 +223B:200050A00040 +223C:000050A00000 +223D:0000A0500000 +223E:0000D0B00000 +223F:004050A02000 +2240:402040402000 +2241:1020B0D04080 +2242:00E000A05000 +2243:0050A000E000 +2244:20D0B040F040 +2245:50A000E000E0 +2246:50A020F040F0 +2247:70A020F040F0 +2248:50A00050A000 +2249:70A04050E080 +224A:40B040B000F0 +224B:40B040B040B0 +224C:A05000E000E0 +224D:A0400040A000 +224E:40A000A04000 +224F:40A000E00000 +2250:4000E000E000 +2251:40E000E00040 +2252:80E000E00020 +2253:20E000E00080 +2254:00B000B00000 +2255:00D000D00000 +2256:00E040E00000 +2257:40E000E00000 +2258:40E000E00000 +2259:40E000E00000 +225A:A0E000E00000 +225B:40E000E00000 +225C:40E000E00000 +225D:4000E000E000 +225E:4000E000E000 +225F:4000E000E000 +2260:20E040E08000 +2261:E000E000E000 +2262:E020E040E080 +2263:E000E000E000 +2264:2040E000E000 +2265:8040E000E000 +2266:2040E000E000 +2267:8040E000E000 +2268:002040E00000 +2269:008040E00000 +226A:0050A0500000 +226B:00A050A00000 +226C:A040A040A000 +226D:20E040E08000 +226E:2060C0608000 +226F:20C060C08000 +2270:2040E040E080 +2271:A060E040E080 +2272:2040E00050A0 +2273:8040E000A050 +2276:60C0208060C0 +2277:C0608020C060 +2278:60C060C060C0 +2279:C060C060C060 +227A:0020C0200000 +227B:008060800000 +227C:20C02000E000 +227D:80608000E000 +227E:20C02000A050 +227F:20C02000A050 +2280:4060C0604000 +2281:40C060C04000 +2282:006080600000 +2283:00C020C00000 +2284:4060C0604000 +2285:40C060C04000 +2286:60806000E000 +2287:C020C000E000 +2288:60A06040E080 +2289:C060C040E040 +228A:60806040E080 +228B:C020C040E080 +2310:0000E0800000 +2320:204040404040 +2321:202020202040 +23BA:F00000000000 +23BB:00F000000000 +23BC:000000F00000 +23BD:0000000000F0 +2409:A0E0A0702020 +240A:8080E0604040 +240B:A0A040702020 +240C:C0C080606040 +240D:E080E0506050 +2423:0000000090F0 +2424:D0B090202030 +2500:000000F00000 +2501:0000F8F80000 +2502:404040404040 +2503:606060606060 +2504:000000A00000 +2505:0000A8A80000 +2506:400040004000 +2507:600060006000 +2508:000000A00000 +2509:0000A8A80000 +250A:400040004000 +250B:600060006000 +250C:000000704040 +250D:000070704040 +250E:000000706060 +250F:000070706060 +2510:000000C04040 +2511:0000C0C04040 +2512:000000E06060 +2513:0000E0E06060 +2514:404040700000 +2515:404070700000 +2516:606060700000 +2517:606070700000 +2518:404040C00000 +2519:4040C0C00000 +251A:606060E00000 +251B:6060E0E00000 +251C:404040704040 +251D:404070704040 +251E:606060704040 +251F:404040706060 +2520:606060706060 +2521:606070704040 +2522:404070706060 +2523:606070706060 +2524:404040C04040 +2525:4040C0C04040 +2526:606060E04040 +2527:404040E06060 +2528:606060E06060 +2529:6060E0E04040 +252A:4040E0E06060 +252B:6060E0E06060 +252C:000000F04040 +252D:0000C0F04040 +252E:000070F04040 +252F:0000F0F04040 +2530:000000F06060 +2531:0000E0F06060 +2532:000070F06060 +2533:0000F0F06060 +2534:404040F00000 +2535:4040C0F00000 +2536:404070F00000 +2537:4040F0F00000 +2538:606060F00000 +2539:6060E0F00000 +253A:606070F00000 +253B:6060F0F00000 +253C:404040F04040 +253D:4040C0F04040 +253E:404070F04040 +253F:4040F0F04040 +2540:606060F04040 +2541:404040F06060 +2542:606060F06060 +2543:6060E0F04040 +2544:606070F04040 +2545:4040E0F06060 +2546:404070F06060 +2547:6060F0F04040 +2548:4040F0F06060 +2549:6060E0F06060 +254A:606070F06060 +254B:6060F0F06060 +254C:000000A00000 +254D:0000A0A00000 +254E:004040004040 +254F:006060006060 +2550:0000F000F000 +2551:606060606060 +2552:000070407040 +2553:000000706060 +2554:000070407060 +2555:0000C040C040 +2556:000000E06060 +2557:0000E020E060 +2558:404070407000 +2559:606060700000 +255A:606070407000 +255B:4040C040C000 +255C:606060E00000 +255D:6060E020E000 +255E:404070407040 +255F:606060706060 +2560:606070407060 +2561:4040C040C040 +2562:606060E06060 +2563:6060E020E060 +2564:0000F000F040 +2565:000000F06060 +2566:0000F000F060 +2567:4040F000F000 +2568:606060F00000 +2569:6060F000F000 +256A:4040F040F040 +256B:606060F06060 +256C:6060F000F060 +256D:000000304040 +256E:000000804040 +256F:404040800000 +2570:404040300000 +2571:102020404080 +2572:804040202010 +2573:909060609090 +2574:000000C00000 +2575:404040400000 +2576:000000700000 +2577:000000404040 +2578:0000C0C00000 +2579:606060600000 +257A:000070700000 +257B:000000606060 +257C:000030F00000 +257D:404040606060 +257E:0000C0F00000 +257F:606060604040 +2580:F8F8F8000000 +2581:0000000000F0 +2582:0000000000F8 +2583:00000000F8F8 +2584:000000F8F8F8 +2585:000000F8F8F8 +2586:0000F8F8F8F8 +2587:00F8F8F8F8F8 +2588:F8F8F8F8F8F8 +2589:F0F0F0F0F0F0 +258A:E0E0E0E0E0E0 +258B:E0E0E0E0E0E0 +258C:C0C0C0C0C0C0 +258D:C0C0C0C0C0C0 +258E:808080808080 +258F:808080808080 +2590:303030303030 +2591:802080208020 +2592:A850A850A850 +2593:B8E8B8E8B8E8 +2594:F80000000000 +2595:101010101010 +25A0:0000E0E0E000 +25A1:0000E0A0E000 +25C6:0040E0E04000 +2660:40E0E040E000 +2663:0040A040E000 +2665:00A0E0E04000 +2666:0040E0400000 +2669:404040C08000 +266A:406040C08000 +266B:70505050A000 +266C:70705050A000 +266D:8080E0A0C000 +266E:80E0A0E02000 +266F:A0E0A0E0A000 +FFFD:F090D0F0D0F0 diff --git a/src/col64/cruft/col64font_new.bdf b/src/col64/cruft/col64font_new.bdf new file mode 100644 index 0000000..b28df9e --- /dev/null +++ b/src/col64/cruft/col64font_new.bdf @@ -0,0 +1,11994 @@ +STARTFONT 2.1 +COMMENT Contributed by Janne V. Kujala +COMMENT $Id: 4x6.bdf,v 1.5 2002-08-26 18:05:49+01 mgk25 Rel $ +COMMENT Send bug reports to Markus Kuhn +FONT -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1 +SIZE 6 75 75 +FONTBOUNDINGBOX 4 6 0 -1 +STARTPROPERTIES 23 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 6 +POINT_SIZE 60 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 40 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 5 +FONT_DESCENT 1 +DESTINATION 1 +COPYRIGHT "Public domain font. Share and enjoy." +CAP_HEIGHT 5 +X_HEIGHT 4 +DEFAULT_CHAR 0 +_GBDFED_INFO "Edited with gbdfed 1.4." +ENDPROPERTIES +CHARS 920 +STARTCHAR char0 +ENCODING 0 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR space +ENCODING 32 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +00 +40 +00 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +A0 +F0 +A0 +00 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +60 +50 +E0 +00 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +20 +40 +90 +00 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +A0 +D0 +00 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +40 +00 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +A0 +00 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +B0 +D0 +60 +00 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +10 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +F0 +20 +00 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +10 +E0 +00 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +E0 +90 +60 +00 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +10 +20 +40 +40 +00 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +60 +90 +60 +00 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +70 +10 +E0 +00 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +00 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +00 +20 +40 +00 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +80 +40 +20 +00 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +20 +40 +80 +00 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +20 +00 +20 +00 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +B0 +B0 +80 +60 +00 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +80 +90 +60 +00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +90 +90 +E0 +00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +F0 +00 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +80 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +B0 +90 +60 +00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +F0 +90 +90 +00 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +10 +10 +90 +60 +00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +F0 +00 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +F0 +D0 +90 +90 +00 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +D0 +B0 +90 +90 +00 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +90 +A0 +50 +00 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +90 +E0 +A0 +90 +00 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +80 +60 +10 +E0 +00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +90 +90 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +20 +40 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +40 +80 +F0 +00 +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +40 +40 +60 +00 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F0 +00 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +B0 +90 +70 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +E0 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +80 +80 +70 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +70 +90 +70 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +E0 +70 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +90 +70 +10 +60 +00 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +90 +90 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +90 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +F0 +D0 +90 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +90 +E0 +80 +00 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +90 +70 +10 +00 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +80 +80 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +C0 +30 +E0 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +90 +A0 +40 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +F0 +A0 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +20 +40 +F0 +00 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +80 +40 +60 +00 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +20 +40 +C0 +00 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR char127 +ENCODING 127 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +90 +00 +90 +D0 +00 +ENDCHAR +STARTCHAR space +ENCODING 160 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +40 +40 +00 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +E0 +40 +00 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +40 +A0 +00 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +00 +40 +40 +00 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +90 +D0 +D0 +90 +60 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +00 +00 +ENDCHAR +STARTCHAR hyphen +ENCODING 173 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +D0 +60 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +C0 +00 +00 +ENDCHAR +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +40 +80 +00 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +D0 +D0 +50 +50 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +20 +40 +00 +ENDCHAR +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +40 +40 +00 +00 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +50 +70 +10 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +10 +20 +30 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +80 +50 +B0 +10 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +80 +60 +00 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +F0 +A0 +B0 +00 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +80 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +50 +D0 +50 +E0 +00 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +E0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +A0 +00 +00 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +E0 +80 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +80 +60 +40 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +40 +00 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +20 +C0 +ENDCHAR +STARTCHAR Amacron +ENCODING 256 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR amacron +ENCODING 257 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Abreve +ENCODING 258 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR abreve +ENCODING 259 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Aogonek +ENCODING 260 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR aogonek +ENCODING 261 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +A0 +60 +20 +ENDCHAR +STARTCHAR Cacute +ENCODING 262 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cacute +ENCODING 263 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +80 +60 +00 +ENDCHAR +STARTCHAR Ccircumflex +ENCODING 264 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccircumflex +ENCODING 265 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Cdotaccent +ENCODING 266 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR cdotaccent +ENCODING 267 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Ccaron +ENCODING 268 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR ccaron +ENCODING 269 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +60 +80 +60 +00 +ENDCHAR +STARTCHAR Dcaron +ENCODING 270 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcaron +ENCODING 271 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Dcroat +ENCODING 272 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR dcroat +ENCODING 273 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR Emacron +ENCODING 274 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR emacron +ENCODING 275 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Ebreve +ENCODING 276 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ebreve +ENCODING 277 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Edotaccent +ENCODING 278 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR edotaccent +ENCODING 279 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Eogonek +ENCODING 280 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +20 +ENDCHAR +STARTCHAR eogonek +ENCODING 281 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +40 +ENDCHAR +STARTCHAR Ecaron +ENCODING 282 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR ecaron +ENCODING 283 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR Gcircumflex +ENCODING 284 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gcircumflex +ENCODING 285 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gbreve +ENCODING 286 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gbreve +ENCODING 287 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gdotaccent +ENCODING 288 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +80 +A0 +60 +00 +ENDCHAR +STARTCHAR gdotaccent +ENCODING 289 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Gcommaaccent +ENCODING 290 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR gcommaaccent +ENCODING 291 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR Hcircumflex +ENCODING 292 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hcircumflex +ENCODING 293 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Hbar +ENCODING 294 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR hbar +ENCODING 295 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Itilde +ENCODING 296 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR itilde +ENCODING 297 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Imacron +ENCODING 298 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR imacron +ENCODING 299 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Ibreve +ENCODING 300 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR ibreve +ENCODING 301 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Iogonek +ENCODING 302 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR iogonek +ENCODING 303 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +20 +ENDCHAR +STARTCHAR Idotaccent +ENCODING 304 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR IJ +ENCODING 306 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +A0 +A0 +20 +60 +ENDCHAR +STARTCHAR ij +ENCODING 307 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Jcircumflex +ENCODING 308 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR jcircumflex +ENCODING 309 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +20 +20 +C0 +ENDCHAR +STARTCHAR Kcommaaccent +ENCODING 310 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kcommaaccent +ENCODING 311 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR kgreenlandic +ENCODING 312 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR Lacute +ENCODING 313 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lacute +ENCODING 314 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Lcommaaccent +ENCODING 315 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +E0 +20 +ENDCHAR +STARTCHAR lcommaaccent +ENCODING 316 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +40 +40 +E0 +20 +ENDCHAR +STARTCHAR Lcaron +ENCODING 317 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +C0 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR lcaron +ENCODING 318 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Ldot +ENCODING 319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +A0 +80 +E0 +00 +ENDCHAR +STARTCHAR ldot +ENCODING 320 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +50 +40 +E0 +00 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR Nacute +ENCODING 323 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR nacute +ENCODING 324 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Ncommaaccent +ENCODING 325 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +20 +ENDCHAR +STARTCHAR ncommaaccent +ENCODING 326 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +40 +ENDCHAR +STARTCHAR Ncaron +ENCODING 327 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR ncaron +ENCODING 328 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR napostrophe +ENCODING 329 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +00 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Eng +ENCODING 330 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +A0 +20 +40 +ENDCHAR +STARTCHAR eng +ENCODING 331 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR Omacron +ENCODING 332 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR omacron +ENCODING 333 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Obreve +ENCODING 334 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR obreve +ENCODING 335 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR Ohungarumlaut +ENCODING 336 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR ohungarumlaut +ENCODING 337 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +70 +B0 +A0 +70 +00 +ENDCHAR +STARTCHAR Racute +ENCODING 340 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR racute +ENCODING 341 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Rcommaaccent +ENCODING 342 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +00 +40 +ENDCHAR +STARTCHAR rcommaaccent +ENCODING 343 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +C0 +80 +80 +20 +ENDCHAR +STARTCHAR Rcaron +ENCODING 344 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR rcaron +ENCODING 345 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR Sacute +ENCODING 346 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR sacute +ENCODING 347 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scircumflex +ENCODING 348 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR scircumflex +ENCODING 349 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Scedilla +ENCODING 350 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scedilla +ENCODING 351 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +E0 +00 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 354 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +20 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 355 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR Tcaron +ENCODING 356 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tcaron +ENCODING 357 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Tbar +ENCODING 358 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR tbar +ENCODING 359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR Utilde +ENCODING 360 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR utilde +ENCODING 361 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Umacron +ENCODING 362 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR umacron +ENCODING 363 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Ubreve +ENCODING 364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR ubreve +ENCODING 365 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +60 +00 +ENDCHAR +STARTCHAR Uring +ENCODING 366 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uring +ENCODING 367 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uhungarumlaut +ENCODING 368 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uhungarumlaut +ENCODING 369 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR Uogonek +ENCODING 370 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +20 +ENDCHAR +STARTCHAR uogonek +ENCODING 371 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +60 +40 +ENDCHAR +STARTCHAR Wcircumflex +ENCODING 372 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR wcircumflex +ENCODING 373 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ycircumflex +ENCODING 374 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ycircumflex +ENCODING 375 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +40 +80 +00 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR Zacute +ENCODING 377 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zacute +ENCODING 378 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zdotaccent +ENCODING 379 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zdotaccent +ENCODING 380 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR longs +ENCODING 383 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR uni018F +ENCODING 399 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR florin +ENCODING 402 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +40 +80 +ENDCHAR +STARTCHAR Scommaaccent +ENCODING 536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +40 +ENDCHAR +STARTCHAR scommaaccent +ENCODING 537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +E0 +40 +ENDCHAR +STARTCHAR Tcommaaccent +ENCODING 538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +00 +40 +ENDCHAR +STARTCHAR tcommaaccent +ENCODING 539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +20 +40 +ENDCHAR +STARTCHAR uni0259 +ENCODING 601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR circumflex +ENCODING 710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR caron +ENCODING 711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR macron +ENCODING 713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR breve +ENCODING 728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dotaccent +ENCODING 729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ring +ENCODING 730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +40 +00 +00 +00 +ENDCHAR +STARTCHAR ogonek +ENCODING 731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +80 +C0 +ENDCHAR +STARTCHAR tilde +ENCODING 732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR hungarumlaut +ENCODING 733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0374 +ENCODING 884 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni0375 +ENCODING 885 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +80 +ENDCHAR +STARTCHAR uni037A +ENCODING 890 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +60 +ENDCHAR +STARTCHAR uni037E +ENCODING 894 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +00 +40 +80 +ENDCHAR +STARTCHAR tonos +ENCODING 900 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR dieresistonos +ENCODING 901 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Alphatonos +ENCODING 902 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR anoteleia +ENCODING 903 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR Epsilontonos +ENCODING 904 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +60 +40 +60 +00 +ENDCHAR +STARTCHAR Etatonos +ENCODING 905 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Iotatonos +ENCODING 906 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +C0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Omicrontonos +ENCODING 908 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Upsilontonos +ENCODING 910 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +40 +40 +00 +ENDCHAR +STARTCHAR Omegatonos +ENCODING 911 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR iotadieresistonos +ENCODING 912 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +00 +40 +20 +00 +ENDCHAR +STARTCHAR Alpha +ENCODING 913 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Beta +ENCODING 914 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR Gamma +ENCODING 915 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR Delta +ENCODING 916 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Epsilon +ENCODING 917 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR Zeta +ENCODING 918 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Eta +ENCODING 919 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Theta +ENCODING 920 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR Iota +ENCODING 921 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR Kappa +ENCODING 922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Lambda +ENCODING 923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Mu +ENCODING 924 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Nu +ENCODING 925 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +E0 +A0 +80 +00 +ENDCHAR +STARTCHAR Xi +ENCODING 926 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +00 +E0 +00 +ENDCHAR +STARTCHAR Omicron +ENCODING 927 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR Pi +ENCODING 928 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR Rho +ENCODING 929 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR Sigma +ENCODING 931 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR Tau +ENCODING 932 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Upsilon +ENCODING 933 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Phi +ENCODING 934 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR Chi +ENCODING 935 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR Psi +ENCODING 936 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 937 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR Iotadieresis +ENCODING 938 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR Upsilondieresis +ENCODING 939 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR alphatonos +ENCODING 940 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR epsilontonos +ENCODING 941 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR etatonos +ENCODING 942 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +A0 +20 +40 +ENDCHAR +STARTCHAR iotatonos +ENCODING 943 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresistonos +ENCODING 944 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B0 +40 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR alpha +ENCODING 945 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +A0 +50 +00 +ENDCHAR +STARTCHAR beta +ENCODING 946 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR gamma +ENCODING 947 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR delta +ENCODING 948 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR epsilon +ENCODING 949 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR zeta +ENCODING 950 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +80 +E0 +20 +40 +ENDCHAR +STARTCHAR eta +ENCODING 951 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +20 +40 +ENDCHAR +STARTCHAR theta +ENCODING 952 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR iota +ENCODING 953 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR kappa +ENCODING 954 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR lambda +ENCODING 955 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR mu +ENCODING 956 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR nu +ENCODING 957 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +40 +00 +ENDCHAR +STARTCHAR xi +ENCODING 958 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +40 +80 +60 +00 +ENDCHAR +STARTCHAR omicron +ENCODING 959 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR pi +ENCODING 960 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR rho +ENCODING 961 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR sigma1 +ENCODING 962 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +40 +C0 +00 +ENDCHAR +STARTCHAR sigma +ENCODING 963 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +A0 +40 +00 +ENDCHAR +STARTCHAR tau +ENCODING 964 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilon +ENCODING 965 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR phi +ENCODING 966 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +A0 +40 +40 +ENDCHAR +STARTCHAR chi +ENCODING 967 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +60 +A0 +00 +ENDCHAR +STARTCHAR psi +ENCODING 968 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR omega +ENCODING 969 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR iotadieresis +ENCODING 970 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +40 +40 +20 +00 +ENDCHAR +STARTCHAR upsilondieresis +ENCODING 971 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omicrontonos +ENCODING 972 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +A0 +40 +00 +ENDCHAR +STARTCHAR upsilontonos +ENCODING 973 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR omegatonos +ENCODING 974 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10023 +ENCODING 1025 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10051 +ENCODING 1026 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10052 +ENCODING 1027 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10053 +ENCODING 1028 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10054 +ENCODING 1029 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10055 +ENCODING 1030 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10056 +ENCODING 1031 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10057 +ENCODING 1032 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10058 +ENCODING 1033 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10059 +ENCODING 1034 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10060 +ENCODING 1035 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10061 +ENCODING 1036 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10062 +ENCODING 1038 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10145 +ENCODING 1039 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10017 +ENCODING 1040 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10018 +ENCODING 1041 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10019 +ENCODING 1042 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10020 +ENCODING 1043 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10021 +ENCODING 1044 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10022 +ENCODING 1045 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +C0 +80 +E0 +00 +ENDCHAR +STARTCHAR afii10024 +ENCODING 1046 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +40 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10025 +ENCODING 1047 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10026 +ENCODING 1048 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +A0 +E0 +A0 +20 +00 +ENDCHAR +STARTCHAR afii10027 +ENCODING 1049 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +A0 +E0 +A0 +20 +ENDCHAR +STARTCHAR afii10028 +ENCODING 1050 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +C0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10029 +ENCODING 1051 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10030 +ENCODING 1052 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10031 +ENCODING 1053 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10032 +ENCODING 1054 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10033 +ENCODING 1055 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10034 +ENCODING 1056 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +A0 +C0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10035 +ENCODING 1057 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10036 +ENCODING 1058 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10037 +ENCODING 1059 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +40 +40 +80 +ENDCHAR +STARTCHAR afii10038 +ENCODING 1060 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +A0 +E0 +40 +00 +ENDCHAR +STARTCHAR afii10039 +ENCODING 1061 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10040 +ENCODING 1062 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii10041 +ENCODING 1063 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +60 +20 +20 +00 +ENDCHAR +STARTCHAR afii10042 +ENCODING 1064 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10043 +ENCODING 1065 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10044 +ENCODING 1066 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10045 +ENCODING 1067 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10046 +ENCODING 1068 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10047 +ENCODING 1069 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10048 +ENCODING 1070 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +D0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10049 +ENCODING 1071 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10065 +ENCODING 1072 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +60 +00 +ENDCHAR +STARTCHAR afii10066 +ENCODING 1073 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10067 +ENCODING 1074 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10068 +ENCODING 1075 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10069 +ENCODING 1076 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +E0 +A0 +ENDCHAR +STARTCHAR afii10070 +ENCODING 1077 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10072 +ENCODING 1078 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +60 +60 +B0 +00 +ENDCHAR +STARTCHAR afii10073 +ENCODING 1079 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10074 +ENCODING 1080 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10075 +ENCODING 1081 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR afii10076 +ENCODING 1082 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10077 +ENCODING 1083 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10078 +ENCODING 1084 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10079 +ENCODING 1085 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10080 +ENCODING 1086 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii10081 +ENCODING 1087 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii10082 +ENCODING 1088 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii10083 +ENCODING 1089 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +80 +60 +00 +ENDCHAR +STARTCHAR afii10084 +ENCODING 1090 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii10085 +ENCODING 1091 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +C0 +ENDCHAR +STARTCHAR afii10086 +ENCODING 1092 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +40 +40 +ENDCHAR +STARTCHAR afii10087 +ENCODING 1093 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii10088 +ENCODING 1094 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +20 +ENDCHAR +STARTCHAR afii10089 +ENCODING 1095 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +60 +20 +00 +ENDCHAR +STARTCHAR afii10090 +ENCODING 1096 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR afii10091 +ENCODING 1097 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +F0 +10 +ENDCHAR +STARTCHAR afii10092 +ENCODING 1098 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +50 +60 +00 +ENDCHAR +STARTCHAR afii10093 +ENCODING 1099 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +90 +D0 +B0 +D0 +00 +ENDCHAR +STARTCHAR afii10094 +ENCODING 1100 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii10095 +ENCODING 1101 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +60 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10096 +ENCODING 1102 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +D0 +D0 +A0 +00 +ENDCHAR +STARTCHAR afii10097 +ENCODING 1103 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +60 +A0 +00 +ENDCHAR +STARTCHAR afii10071 +ENCODING 1105 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +C0 +60 +00 +ENDCHAR +STARTCHAR afii10099 +ENCODING 1106 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +20 +ENDCHAR +STARTCHAR afii10100 +ENCODING 1107 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR afii10101 +ENCODING 1108 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +80 +60 +00 +ENDCHAR +STARTCHAR afii10102 +ENCODING 1109 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR afii10103 +ENCODING 1110 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10104 +ENCODING 1111 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +C0 +40 +E0 +00 +ENDCHAR +STARTCHAR afii10105 +ENCODING 1112 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +20 +20 +20 +C0 +ENDCHAR +STARTCHAR afii10106 +ENCODING 1113 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +A0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10107 +ENCODING 1114 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +B0 +B0 +00 +ENDCHAR +STARTCHAR afii10108 +ENCODING 1115 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +C0 +80 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10109 +ENCODING 1116 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii10110 +ENCODING 1118 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +A0 +40 +80 +ENDCHAR +STARTCHAR afii10193 +ENCODING 1119 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +E0 +40 +ENDCHAR +STARTCHAR afii10050 +ENCODING 1168 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR afii10098 +ENCODING 1169 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +E0 +80 +80 +00 +ENDCHAR +STARTCHAR uni0492 +ENCODING 1170 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR uni0493 +ENCODING 1171 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR afii57664 +ENCODING 1488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +60 +C0 +A0 +00 +ENDCHAR +STARTCHAR afii57665 +ENCODING 1489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +F0 +00 +ENDCHAR +STARTCHAR afii57666 +ENCODING 1490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +40 +A0 +00 +ENDCHAR +STARTCHAR afii57667 +ENCODING 1491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57668 +ENCODING 1492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57669 +ENCODING 1493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57670 +ENCODING 1494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +40 +40 +40 +00 +ENDCHAR +STARTCHAR afii57671 +ENCODING 1495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57672 +ENCODING 1496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR afii57673 +ENCODING 1497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +20 +00 +00 +00 +ENDCHAR +STARTCHAR afii57674 +ENCODING 1498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +20 +20 +ENDCHAR +STARTCHAR afii57675 +ENCODING 1499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +20 +C0 +00 +ENDCHAR +STARTCHAR afii57676 +ENCODING 1500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +20 +20 +40 +00 +ENDCHAR +STARTCHAR afii57677 +ENCODING 1501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57678 +ENCODING 1502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR afii57679 +ENCODING 1503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57680 +ENCODING 1504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +20 +20 +60 +00 +ENDCHAR +STARTCHAR afii57681 +ENCODING 1505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR afii57682 +ENCODING 1506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +60 +C0 +00 +ENDCHAR +STARTCHAR afii57683 +ENCODING 1507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +20 +20 +ENDCHAR +STARTCHAR afii57684 +ENCODING 1508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +A0 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57685 +ENCODING 1509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57686 +ENCODING 1510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +40 +20 +E0 +00 +ENDCHAR +STARTCHAR afii57687 +ENCODING 1511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +20 +C0 +80 +80 +ENDCHAR +STARTCHAR afii57688 +ENCODING 1512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +20 +20 +00 +ENDCHAR +STARTCHAR afii57689 +ENCODING 1513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +D0 +A0 +E0 +00 +ENDCHAR +STARTCHAR afii57690 +ENCODING 1514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E02 +ENCODING 7682 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E03 +ENCODING 7683 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +80 +C0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0A +ENCODING 7690 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni1E0B +ENCODING 7691 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +20 +60 +A0 +60 +00 +ENDCHAR +STARTCHAR uni1E1E +ENCODING 7710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +80 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E1F +ENCODING 7711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni1E40 +ENCODING 7744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni1E41 +ENCODING 7745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uni1E56 +ENCODING 7766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +A0 +C0 +80 +00 +ENDCHAR +STARTCHAR uni1E57 +ENCODING 7767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +C0 +A0 +C0 +80 +ENDCHAR +STARTCHAR uni1E60 +ENCODING 7776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E61 +ENCODING 7777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni1E6A +ENCODING 7786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni1E6B +ENCODING 7787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +20 +ENDCHAR +STARTCHAR Wgrave +ENCODING 7808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wgrave +ENCODING 7809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wacute +ENCODING 7810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +80 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wacute +ENCODING 7811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR Wdieresis +ENCODING 7812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR wdieresis +ENCODING 7813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +A0 +E0 +E0 +00 +ENDCHAR +STARTCHAR Ygrave +ENCODING 7922 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR ygrave +ENCODING 7923 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +A0 +60 +20 +40 +ENDCHAR +STARTCHAR uni2010 +ENCODING 8208 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR uni2011 +ENCODING 8209 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +60 +00 +00 +00 +ENDCHAR +STARTCHAR figuredash +ENCODING 8210 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR afii00208 +ENCODING 8213 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2016 +ENCODING 8214 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR underscoredbl +ENCODING 8215 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +F0 +ENDCHAR +STARTCHAR quoteleft +ENCODING 8216 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +60 +00 +00 +00 +ENDCHAR +STARTCHAR quoteright +ENCODING 8217 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +20 +40 +00 +00 +00 +ENDCHAR +STARTCHAR quotesinglbase +ENCODING 8218 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +20 +40 +ENDCHAR +STARTCHAR quotereversed +ENCODING 8219 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +40 +20 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblleft +ENCODING 8220 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblright +ENCODING 8221 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +50 +A0 +00 +00 +00 +ENDCHAR +STARTCHAR quotedblbase +ENCODING 8222 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +50 +50 +A0 +ENDCHAR +STARTCHAR uni201F +ENCODING 8223 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +50 +00 +00 +00 +ENDCHAR +STARTCHAR dagger +ENCODING 8224 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR daggerdbl +ENCODING 8225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2023 +ENCODING 8227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +E0 +C0 +00 +00 +ENDCHAR +STARTCHAR onedotenleader +ENCODING 8228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +40 +00 +ENDCHAR +STARTCHAR twodotenleader +ENCODING 8229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +A0 +00 +ENDCHAR +STARTCHAR ellipsis +ENCODING 8230 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +B0 +00 +ENDCHAR +STARTCHAR uni2027 +ENCODING 8231 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +00 +00 +ENDCHAR +STARTCHAR perthousand +ENCODING 8240 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +40 +80 +30 +00 +ENDCHAR +STARTCHAR guilsinglleft +ENCODING 8249 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +80 +40 +00 +00 +ENDCHAR +STARTCHAR guilsinglright +ENCODING 8250 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +20 +40 +00 +00 +ENDCHAR +STARTCHAR uni203E +ENCODING 8254 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR nsuperior +ENCODING 8319 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR peseta +ENCODING 8359 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +F0 +60 +40 +40 +00 +ENDCHAR +STARTCHAR Euro +ENCODING 8364 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +20 +00 +ENDCHAR +STARTCHAR afii61352 +ENCODING 8470 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +B0 +B0 +A0 +B0 +00 +ENDCHAR +STARTCHAR trademark +ENCODING 8482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +40 +00 +E0 +A0 +00 +ENDCHAR +STARTCHAR Omega +ENCODING 8486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni2127 +ENCODING 8487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR oneeighth +ENCODING 8539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +B0 +20 +50 +20 +ENDCHAR +STARTCHAR threeeighths +ENCODING 8540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +60 +D0 +20 +ENDCHAR +STARTCHAR fiveeighths +ENCODING 8541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +80 +70 +A0 +50 +20 +ENDCHAR +STARTCHAR seveneighths +ENCODING 8542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +40 +B0 +A0 +50 +20 +ENDCHAR +STARTCHAR arrowleft +ENCODING 8592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +F0 +40 +00 +00 +ENDCHAR +STARTCHAR arrowup +ENCODING 8593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +40 +00 +ENDCHAR +STARTCHAR arrowright +ENCODING 8594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +F0 +20 +00 +00 +ENDCHAR +STARTCHAR arrowdown +ENCODING 8595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR arrowboth +ENCODING 8596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +F0 +50 +00 +00 +ENDCHAR +STARTCHAR arrowupdn +ENCODING 8597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR universal +ENCODING 8704 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +E0 +A0 +40 +00 +ENDCHAR +STARTCHAR uni2201 +ENCODING 8705 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +80 +A0 +40 +00 +ENDCHAR +STARTCHAR partialdiff +ENCODING 8706 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +60 +A0 +40 +00 +ENDCHAR +STARTCHAR existential +ENCODING 8707 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR uni2204 +ENCODING 8708 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +20 +E0 +60 +E0 +80 +ENDCHAR +STARTCHAR emptyset +ENCODING 8709 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +A0 +A0 +C0 +80 +ENDCHAR +STARTCHAR Delta +ENCODING 8710 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR gradient +ENCODING 8711 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR element +ENCODING 8712 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +E0 +80 +60 +00 +ENDCHAR +STARTCHAR notelement +ENCODING 8713 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +E0 +A0 +60 +40 +ENDCHAR +STARTCHAR uni220A +ENCODING 8714 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +80 +C0 +80 +40 +00 +ENDCHAR +STARTCHAR suchthat +ENCODING 8715 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +E0 +20 +C0 +00 +ENDCHAR +STARTCHAR uni220C +ENCODING 8716 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +20 +E0 +60 +C0 +80 +ENDCHAR +STARTCHAR uni220D +ENCODING 8717 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +C0 +40 +80 +00 +ENDCHAR +STARTCHAR uni220E +ENCODING 8718 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +00 +ENDCHAR +STARTCHAR product +ENCODING 8719 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2210 +ENCODING 8720 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +E0 +00 +ENDCHAR +STARTCHAR summation +ENCODING 8721 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR minus +ENCODING 8722 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +00 +00 +00 +ENDCHAR +STARTCHAR uni2213 +ENCODING 8723 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR uni2214 +ENCODING 8724 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +E0 +40 +00 +ENDCHAR +STARTCHAR fraction +ENCODING 8725 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +40 +80 +80 +00 +ENDCHAR +STARTCHAR uni2216 +ENCODING 8726 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +40 +20 +20 +00 +ENDCHAR +STARTCHAR asteriskmath +ENCODING 8727 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +A0 +70 +E0 +50 +40 +ENDCHAR +STARTCHAR uni2218 +ENCODING 8728 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +00 +00 +ENDCHAR +STARTCHAR periodcentered +ENCODING 8729 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR radical +ENCODING 8730 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +20 +20 +A0 +60 +00 +ENDCHAR +STARTCHAR uni221B +ENCODING 8731 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +50 +D0 +10 +50 +30 +ENDCHAR +STARTCHAR uni221C +ENCODING 8732 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +D0 +50 +10 +50 +30 +ENDCHAR +STARTCHAR proportional +ENCODING 8733 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +E0 +50 +00 +ENDCHAR +STARTCHAR infinity +ENCODING 8734 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +D0 +B0 +40 +00 +ENDCHAR +STARTCHAR orthogonal +ENCODING 8735 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +80 +80 +E0 +00 +ENDCHAR +STARTCHAR angle +ENCODING 8736 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +80 +E0 +00 +ENDCHAR +STARTCHAR uni2221 +ENCODING 8737 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +A0 +40 +A0 +F0 +20 +ENDCHAR +STARTCHAR uni2222 +ENCODING 8738 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +60 +A0 +A0 +60 +90 +ENDCHAR +STARTCHAR uni2223 +ENCODING 8739 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR uni2224 +ENCODING 8740 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +40 +00 +ENDCHAR +STARTCHAR uni2225 +ENCODING 8741 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR uni2226 +ENCODING 8742 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +B0 +E0 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicaland +ENCODING 8743 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +A0 +A0 +00 +ENDCHAR +STARTCHAR logicalor +ENCODING 8744 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +40 +40 +00 +ENDCHAR +STARTCHAR intersection +ENCODING 8745 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +A0 +A0 +00 +ENDCHAR +STARTCHAR union +ENCODING 8746 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +A0 +A0 +40 +00 +ENDCHAR +STARTCHAR integral +ENCODING 8747 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni222C +ENCODING 8748 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +A0 +A0 +A0 +80 +ENDCHAR +STARTCHAR uni222D +ENCODING 8749 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +D0 +D0 +D0 +A0 +ENDCHAR +STARTCHAR uni222E +ENCODING 8750 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +E0 +40 +80 +ENDCHAR +STARTCHAR uni222F +ENCODING 8751 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +E0 +E0 +A0 +80 +ENDCHAR +STARTCHAR uni2230 +ENCODING 8752 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +D0 +F0 +F0 +D0 +A0 +ENDCHAR +STARTCHAR uni2231 +ENCODING 8753 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +50 +40 +80 +ENDCHAR +STARTCHAR uni2232 +ENCODING 8754 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +C0 +40 +80 +ENDCHAR +STARTCHAR uni2233 +ENCODING 8755 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +C0 +E0 +40 +80 +ENDCHAR +STARTCHAR therefore +ENCODING 8756 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2235 +ENCODING 8757 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +40 +00 +ENDCHAR +STARTCHAR uni2236 +ENCODING 8758 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2237 +ENCODING 8759 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni2238 +ENCODING 8760 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2239 +ENCODING 8761 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +20 +C0 +20 +00 +ENDCHAR +STARTCHAR uni223A +ENCODING 8762 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +00 +E0 +00 +A0 +00 +ENDCHAR +STARTCHAR uni223B +ENCODING 8763 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +00 +50 +A0 +00 +40 +ENDCHAR +STARTCHAR similar +ENCODING 8764 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni223D +ENCODING 8765 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni223E +ENCODING 8766 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +D0 +B0 +00 +00 +ENDCHAR +STARTCHAR uni223F +ENCODING 8767 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +50 +A0 +20 +00 +ENDCHAR +STARTCHAR uni2240 +ENCODING 8768 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +20 +40 +40 +20 +00 +ENDCHAR +STARTCHAR uni2241 +ENCODING 8769 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +B0 +D0 +40 +80 +ENDCHAR +STARTCHAR uni2242 +ENCODING 8770 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +00 +A0 +50 +00 +ENDCHAR +STARTCHAR uni2243 +ENCODING 8771 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2244 +ENCODING 8772 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +D0 +B0 +40 +F0 +40 +ENDCHAR +STARTCHAR congruent +ENCODING 8773 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni2246 +ENCODING 8774 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR uni2247 +ENCODING 8775 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +20 +F0 +40 +F0 +ENDCHAR +STARTCHAR approxequal +ENCODING 8776 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +50 +A0 +00 +50 +A0 +00 +ENDCHAR +STARTCHAR uni2249 +ENCODING 8777 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +A0 +40 +50 +E0 +80 +ENDCHAR +STARTCHAR uni224A +ENCODING 8778 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +00 +F0 +ENDCHAR +STARTCHAR uni224B +ENCODING 8779 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +B0 +40 +B0 +40 +B0 +ENDCHAR +STARTCHAR uni224C +ENCODING 8780 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +50 +00 +E0 +00 +E0 +ENDCHAR +STARTCHAR uni224D +ENCODING 8781 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +00 +40 +A0 +00 +ENDCHAR +STARTCHAR uni224E +ENCODING 8782 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +A0 +40 +00 +ENDCHAR +STARTCHAR uni224F +ENCODING 8783 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +A0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2250 +ENCODING 8784 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2251 +ENCODING 8785 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +40 +ENDCHAR +STARTCHAR uni2252 +ENCODING 8786 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +00 +E0 +00 +20 +ENDCHAR +STARTCHAR uni2253 +ENCODING 8787 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +00 +E0 +00 +80 +ENDCHAR +STARTCHAR uni2254 +ENCODING 8788 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +B0 +00 +B0 +00 +00 +ENDCHAR +STARTCHAR uni2255 +ENCODING 8789 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +D0 +00 +D0 +00 +00 +ENDCHAR +STARTCHAR uni2256 +ENCODING 8790 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +E0 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2257 +ENCODING 8791 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2258 +ENCODING 8792 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2259 +ENCODING 8793 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225A +ENCODING 8794 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225B +ENCODING 8795 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225C +ENCODING 8796 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +00 +E0 +00 +00 +ENDCHAR +STARTCHAR uni225D +ENCODING 8797 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225E +ENCODING 8798 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni225F +ENCODING 8799 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR notequal +ENCODING 8800 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR equivalence +ENCODING 8801 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2262 +ENCODING 8802 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +20 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2263 +ENCODING 8803 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +00 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR lessequal +ENCODING 8804 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR greaterequal +ENCODING 8805 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2266 +ENCODING 8806 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2267 +ENCODING 8807 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2268 +ENCODING 8808 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni2269 +ENCODING 8809 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +40 +E0 +00 +00 +ENDCHAR +STARTCHAR uni226A +ENCODING 8810 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +50 +A0 +50 +00 +00 +ENDCHAR +STARTCHAR uni226B +ENCODING 8811 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +50 +A0 +00 +00 +ENDCHAR +STARTCHAR uni226C +ENCODING 8812 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +40 +A0 +40 +A0 +00 +ENDCHAR +STARTCHAR uni226D +ENCODING 8813 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +E0 +40 +E0 +80 +00 +ENDCHAR +STARTCHAR uni226E +ENCODING 8814 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +60 +C0 +60 +80 +00 +ENDCHAR +STARTCHAR uni226F +ENCODING 8815 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +60 +C0 +80 +00 +ENDCHAR +STARTCHAR uni2270 +ENCODING 8816 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2271 +ENCODING 8817 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +60 +E0 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2272 +ENCODING 8818 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +E0 +00 +50 +A0 +ENDCHAR +STARTCHAR uni2273 +ENCODING 8819 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +E0 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2276 +ENCODING 8822 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +20 +80 +60 +C0 +ENDCHAR +STARTCHAR uni2277 +ENCODING 8823 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +80 +20 +C0 +60 +ENDCHAR +STARTCHAR uni2278 +ENCODING 8824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +C0 +60 +C0 +60 +C0 +ENDCHAR +STARTCHAR uni2279 +ENCODING 8825 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +60 +C0 +60 +ENDCHAR +STARTCHAR uni227A +ENCODING 8826 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +20 +C0 +20 +00 +00 +ENDCHAR +STARTCHAR uni227B +ENCODING 8827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +80 +60 +80 +00 +00 +ENDCHAR +STARTCHAR uni227C +ENCODING 8828 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227D +ENCODING 8829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +60 +80 +00 +E0 +00 +ENDCHAR +STARTCHAR uni227E +ENCODING 8830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni227F +ENCODING 8831 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +C0 +20 +00 +A0 +50 +ENDCHAR +STARTCHAR uni2280 +ENCODING 8832 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2281 +ENCODING 8833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR propersubset +ENCODING 8834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +80 +60 +00 +00 +ENDCHAR +STARTCHAR propersuperset +ENCODING 8835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +C0 +20 +C0 +00 +00 +ENDCHAR +STARTCHAR notsubset +ENCODING 8836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +C0 +60 +40 +00 +ENDCHAR +STARTCHAR uni2285 +ENCODING 8837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +C0 +60 +C0 +40 +00 +ENDCHAR +STARTCHAR reflexsubset +ENCODING 8838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +00 +E0 +00 +ENDCHAR +STARTCHAR reflexsuperset +ENCODING 8839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +00 +E0 +00 +ENDCHAR +STARTCHAR uni2288 +ENCODING 8840 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +A0 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni2289 +ENCODING 8841 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +60 +C0 +40 +E0 +40 +ENDCHAR +STARTCHAR uni228A +ENCODING 8842 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +80 +60 +40 +E0 +80 +ENDCHAR +STARTCHAR uni228B +ENCODING 8843 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +20 +C0 +40 +E0 +80 +ENDCHAR +STARTCHAR revlogicalnot +ENCODING 8976 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +80 +00 +00 +ENDCHAR +STARTCHAR integraltp +ENCODING 8992 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR integralbt +ENCODING 8993 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +20 +20 +20 +20 +20 +40 +ENDCHAR +STARTCHAR uni23BA +ENCODING 9146 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BB +ENCODING 9147 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni23BC +ENCODING 9148 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni23BD +ENCODING 9149 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2409 +ENCODING 9225 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +70 +20 +20 +ENDCHAR +STARTCHAR uni240A +ENCODING 9226 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +60 +40 +40 +ENDCHAR +STARTCHAR uni240B +ENCODING 9227 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +A0 +40 +70 +20 +20 +ENDCHAR +STARTCHAR uni240C +ENCODING 9228 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +80 +60 +60 +40 +ENDCHAR +STARTCHAR uni240D +ENCODING 9229 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +80 +E0 +50 +60 +50 +ENDCHAR +STARTCHAR uni2423 +ENCODING 9251 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +90 +F0 +ENDCHAR +STARTCHAR uni2424 +ENCODING 9252 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +D0 +B0 +90 +20 +20 +30 +ENDCHAR +STARTCHAR SF100000 +ENCODING 9472 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2501 +ENCODING 9473 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +00 +00 +ENDCHAR +STARTCHAR SF110000 +ENCODING 9474 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni2503 +ENCODING 9475 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR uni2504 +ENCODING 9476 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2505 +ENCODING 9477 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni2506 +ENCODING 9478 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni2507 +ENCODING 9479 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR uni2508 +ENCODING 9480 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni2509 +ENCODING 9481 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A8 +A8 +00 +00 +ENDCHAR +STARTCHAR uni250A +ENCODING 9482 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +00 +40 +00 +40 +00 +ENDCHAR +STARTCHAR uni250B +ENCODING 9483 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +00 +60 +00 +60 +00 +ENDCHAR +STARTCHAR SF010000 +ENCODING 9484 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +40 +40 +ENDCHAR +STARTCHAR uni250D +ENCODING 9485 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni250E +ENCODING 9486 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR uni250F +ENCODING 9487 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF030000 +ENCODING 9488 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2511 +ENCODING 9489 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2512 +ENCODING 9490 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2513 +ENCODING 9491 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF020000 +ENCODING 9492 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +00 +00 +ENDCHAR +STARTCHAR uni2515 +ENCODING 9493 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni2516 +ENCODING 9494 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR uni2517 +ENCODING 9495 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +00 +00 +ENDCHAR +STARTCHAR SF040000 +ENCODING 9496 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2519 +ENCODING 9497 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni251A +ENCODING 9498 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR uni251B +ENCODING 9499 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +00 +00 +ENDCHAR +STARTCHAR SF080000 +ENCODING 9500 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +40 +40 +ENDCHAR +STARTCHAR uni251D +ENCODING 9501 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni251E +ENCODING 9502 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +40 +40 +ENDCHAR +STARTCHAR uni251F +ENCODING 9503 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +70 +60 +60 +ENDCHAR +STARTCHAR uni2520 +ENCODING 9504 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR uni2521 +ENCODING 9505 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +40 +40 +ENDCHAR +STARTCHAR uni2522 +ENCODING 9506 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +70 +60 +60 +ENDCHAR +STARTCHAR uni2523 +ENCODING 9507 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +70 +60 +60 +ENDCHAR +STARTCHAR SF090000 +ENCODING 9508 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2525 +ENCODING 9509 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +C0 +40 +40 +ENDCHAR +STARTCHAR uni2526 +ENCODING 9510 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +40 +40 +ENDCHAR +STARTCHAR uni2527 +ENCODING 9511 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2528 +ENCODING 9512 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR uni2529 +ENCODING 9513 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +40 +40 +ENDCHAR +STARTCHAR uni252A +ENCODING 9514 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR uni252B +ENCODING 9515 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +E0 +60 +60 +ENDCHAR +STARTCHAR SF060000 +ENCODING 9516 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252D +ENCODING 9517 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252E +ENCODING 9518 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni252F +ENCODING 9519 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2530 +ENCODING 9520 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2531 +ENCODING 9521 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2532 +ENCODING 9522 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2533 +ENCODING 9523 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR SF070000 +ENCODING 9524 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2535 +ENCODING 9525 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2536 +ENCODING 9526 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2537 +ENCODING 9527 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2538 +ENCODING 9528 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR uni2539 +ENCODING 9529 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253A +ENCODING 9530 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +00 +00 +ENDCHAR +STARTCHAR uni253B +ENCODING 9531 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +00 +00 +ENDCHAR +STARTCHAR SF050000 +ENCODING 9532 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253D +ENCODING 9533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253E +ENCODING 9534 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni253F +ENCODING 9535 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2540 +ENCODING 9536 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2541 +ENCODING 9537 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2542 +ENCODING 9538 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2543 +ENCODING 9539 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2544 +ENCODING 9540 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2545 +ENCODING 9541 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2546 +ENCODING 9542 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2547 +ENCODING 9543 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +40 +40 +ENDCHAR +STARTCHAR uni2548 +ENCODING 9544 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni2549 +ENCODING 9545 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254A +ENCODING 9546 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254B +ENCODING 9547 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +F0 +60 +60 +ENDCHAR +STARTCHAR uni254C +ENCODING 9548 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254D +ENCODING 9549 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +A0 +A0 +00 +00 +ENDCHAR +STARTCHAR uni254E +ENCODING 9550 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +40 +00 +40 +40 +ENDCHAR +STARTCHAR uni254F +ENCODING 9551 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +60 +60 +00 +60 +60 +ENDCHAR +STARTCHAR SF430000 +ENCODING 9552 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF240000 +ENCODING 9553 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR SF510000 +ENCODING 9554 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF520000 +ENCODING 9555 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +60 +60 +ENDCHAR +STARTCHAR SF390000 +ENCODING 9556 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF220000 +ENCODING 9557 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF210000 +ENCODING 9558 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +E0 +60 +60 +ENDCHAR +STARTCHAR SF250000 +ENCODING 9559 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF500000 +ENCODING 9560 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF490000 +ENCODING 9561 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +00 +00 +ENDCHAR +STARTCHAR SF380000 +ENCODING 9562 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +00 +ENDCHAR +STARTCHAR SF280000 +ENCODING 9563 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +00 +ENDCHAR +STARTCHAR SF270000 +ENCODING 9564 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +00 +00 +ENDCHAR +STARTCHAR SF260000 +ENCODING 9565 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +00 +ENDCHAR +STARTCHAR SF360000 +ENCODING 9566 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +70 +40 +70 +40 +ENDCHAR +STARTCHAR SF370000 +ENCODING 9567 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +70 +60 +60 +ENDCHAR +STARTCHAR SF420000 +ENCODING 9568 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +70 +40 +70 +60 +ENDCHAR +STARTCHAR SF190000 +ENCODING 9569 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +C0 +40 +C0 +40 +ENDCHAR +STARTCHAR SF200000 +ENCODING 9570 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +E0 +60 +60 +ENDCHAR +STARTCHAR SF230000 +ENCODING 9571 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +E0 +20 +E0 +60 +ENDCHAR +STARTCHAR SF470000 +ENCODING 9572 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +40 +ENDCHAR +STARTCHAR SF480000 +ENCODING 9573 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F0 +60 +60 +ENDCHAR +STARTCHAR SF410000 +ENCODING 9574 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR SF450000 +ENCODING 9575 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF460000 +ENCODING 9576 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +00 +00 +ENDCHAR +STARTCHAR SF400000 +ENCODING 9577 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +00 +ENDCHAR +STARTCHAR SF540000 +ENCODING 9578 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +F0 +40 +F0 +40 +ENDCHAR +STARTCHAR SF530000 +ENCODING 9579 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +F0 +60 +60 +ENDCHAR +STARTCHAR SF440000 +ENCODING 9580 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +F0 +00 +F0 +60 +ENDCHAR +STARTCHAR uni256D +ENCODING 9581 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +30 +40 +40 +ENDCHAR +STARTCHAR uni256E +ENCODING 9582 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +80 +40 +40 +ENDCHAR +STARTCHAR uni256F +ENCODING 9583 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +80 +00 +00 +ENDCHAR +STARTCHAR uni2570 +ENCODING 9584 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +30 +00 +00 +ENDCHAR +STARTCHAR uni2571 +ENCODING 9585 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +20 +20 +40 +40 +80 +ENDCHAR +STARTCHAR uni2572 +ENCODING 9586 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +40 +40 +20 +20 +10 +ENDCHAR +STARTCHAR uni2573 +ENCODING 9587 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +90 +90 +60 +60 +90 +90 +ENDCHAR +STARTCHAR uni2574 +ENCODING 9588 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2575 +ENCODING 9589 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR uni2576 +ENCODING 9590 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +70 +00 +00 +ENDCHAR +STARTCHAR uni2577 +ENCODING 9591 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +40 +40 +40 +ENDCHAR +STARTCHAR uni2578 +ENCODING 9592 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +C0 +00 +00 +ENDCHAR +STARTCHAR uni2579 +ENCODING 9593 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR uni257A +ENCODING 9594 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +70 +70 +00 +00 +ENDCHAR +STARTCHAR uni257B +ENCODING 9595 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +60 +60 +60 +ENDCHAR +STARTCHAR uni257C +ENCODING 9596 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +30 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257D +ENCODING 9597 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +60 +60 +60 +ENDCHAR +STARTCHAR uni257E +ENCODING 9598 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +C0 +F0 +00 +00 +ENDCHAR +STARTCHAR uni257F +ENCODING 9599 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +60 +60 +60 +60 +40 +40 +ENDCHAR +STARTCHAR upblock +ENCODING 9600 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +00 +00 +00 +ENDCHAR +STARTCHAR uni2581 +ENCODING 9601 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F0 +ENDCHAR +STARTCHAR uni2582 +ENCODING 9602 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +00 +F8 +ENDCHAR +STARTCHAR uni2583 +ENCODING 9603 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +00 +F8 +F8 +ENDCHAR +STARTCHAR dnblock +ENCODING 9604 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2585 +ENCODING 9605 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +00 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2586 +ENCODING 9606 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2587 +ENCODING 9607 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR block +ENCODING 9608 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +F8 +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR uni2589 +ENCODING 9609 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +F0 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR uni258A +ENCODING 9610 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR uni258B +ENCODING 9611 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR lfblock +ENCODING 9612 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258D +ENCODING 9613 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni258E +ENCODING 9614 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni258F +ENCODING 9615 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR rtblock +ENCODING 9616 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR ltshade +ENCODING 9617 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +20 +80 +20 +80 +20 +ENDCHAR +STARTCHAR shade +ENCODING 9618 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A8 +50 +A8 +50 +A8 +50 +ENDCHAR +STARTCHAR dkshade +ENCODING 9619 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +B8 +E8 +B8 +E8 +B8 +E8 +ENDCHAR +STARTCHAR uni2594 +ENCODING 9620 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR uni2595 +ENCODING 9621 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR filledbox +ENCODING 9632 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +E0 +E0 +00 +ENDCHAR +STARTCHAR H22073 +ENCODING 9633 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +00 +E0 +A0 +E0 +00 +ENDCHAR +STARTCHAR uni25C6 +ENCODING 9670 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR spade +ENCODING 9824 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +E0 +E0 +40 +E0 +00 +ENDCHAR +STARTCHAR club +ENCODING 9827 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +A0 +40 +E0 +00 +ENDCHAR +STARTCHAR heart +ENCODING 9829 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +A0 +E0 +E0 +40 +00 +ENDCHAR +STARTCHAR diamond +ENCODING 9830 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +00 +40 +E0 +40 +00 +00 +ENDCHAR +STARTCHAR uni2669 +ENCODING 9833 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +40 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnote +ENCODING 9834 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +40 +60 +40 +C0 +80 +00 +ENDCHAR +STARTCHAR musicalnotedbl +ENCODING 9835 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +50 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266C +ENCODING 9836 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +70 +70 +50 +50 +A0 +00 +ENDCHAR +STARTCHAR uni266D +ENCODING 9837 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +80 +E0 +A0 +C0 +00 +ENDCHAR +STARTCHAR uni266E +ENCODING 9838 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +80 +E0 +A0 +E0 +20 +00 +ENDCHAR +STARTCHAR uni266F +ENCODING 9839 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +A0 +E0 +A0 +E0 +A0 +00 +ENDCHAR +STARTCHAR uniFFFD +ENCODING 65533 +SWIDTH 640 0 +DWIDTH 4 0 +BBX 4 6 0 -1 +BITMAP +F0 +90 +D0 +F0 +D0 +F0 +ENDCHAR +ENDFONT diff --git a/src/col64/cruft/coltbl.pl b/src/col64/cruft/coltbl.pl new file mode 100644 index 0000000..e933437 --- /dev/null +++ b/src/col64/cruft/coltbl.pl @@ -0,0 +1,17 @@ +#!/usr/bin/perl -w + +for(0..63) { + $pix = $_*5; + $byte = int($pix/8); + $mask = 0xf800; + $offs = $pix % 8; + $mask >>= $offs; + $mask = (~$mask) & 0xffff; + $mleft = sprintf "%02X", $mask >> 8; + $mright = sprintf "%02X", $mask & 0xff; + $m = sprintf("%016b", $mask); + printf "\$%02X, ", $offs; +# print < small.inc + +; ...then use a8eol to convert it to ATASCII format. + +; 20061028 bkw: Originally downloaded from: + +; http://atrey.karlin.mff.cuni.cz/~pavel/atari/atrb.html + +; ...and converted to DASM/ATASM/CA65 format. dasm, atasm, and ca65 use +; similar enough syntax that this file can be used as-is with any of +; them. Unfortunately, this means I can't do conditional assembly in this +; file, since the two assemblers use different semantics... macros are +; even less compatible :( + +; If you use ca65, you need this line in your source: + +;; .FEATURE labels_without_colons + +; before including this file, or else run ca65 with +; "--feature labels_without_colons"). + +; 20070529 bkw: updated, added missing GTIA/POKEY/ANTIC equates, +; documented where the shadows are for those GTIA/POKEY/ANTIC/PIA +; registers that have them. Also added a list of error messages and +; explanation of the cassette buffer layout, and organized the C_* +; CIO constants. Made minor modifications to get this file to assemble +; with ATasm as well as DASM. + +; I have added a few missing equates: this file only +; contained OS ROM locations when I got it. +; I added a few from FMS/DOS as well (e.g. RUNAD and INITAD). + +; XL-specific locations in the original file were duplicate labels +; (e.g. PTIMOT was defined as both $1C and $314), which keeps DASM +; from being able to assemble the file. I prefixed the XL/XL versions +; with "XL_" + +; Also, I've prefixed the CIO command and AUX1 constants with C_, since some +; of them conflicted with other labels in the original version. + +; Areas listed as "unmapped" are literally not connected to anything. +; Trying to read from unmapped address space results in reading whatever +; garbage was on the data bus when the read happened. On my 1200XL, this +; generally results in all 1's ($FF or 255). +; In a 400, 600XL or other Atari with less than 48K of RAM, the missing +; RAM address space is also unmapped. + +; Still TODO: +; - Rest of the DOS/FMS equates +; - Mark 800-ony locations with OSB_ +; - ifdef code, so the user can set the machine type (OSB or XL), +; then refer to e.g. PTIMOT and get either OSB_PTIMOT or XL_PTIMOT +; - Split into separate files? I'd rather not (it's only about 1000 lines) + +; This file's mostly intended for new development. It could also be +; useful for porting old ASM/ED or Mac65 code to DASM, but such code +; may need work... you can always assemble it with ATasm, in that case, +; since it's 99.999% source code compatible with Mac65. + +; References to "APPENDIX C" and such are referring to the Atari System +; Reference Manual, a version of which can be found at: + +; http://atrey.karlin.mff.cuni.cz/~pavel/atari/atrtblc.html + +; References to "Mapping" refer to "Mapping the Atari, Revised Edition", +; which can be found at: + +; http://www.atariarchives.org/mapping/index.php + +; I've pasted a few quotes from Mapping into this file; I consider them +; small enough to be covered under the "fair use" provisions of copyright law +; (I am not a lawyer, though). + +; +; +; DEVICE NAMES +; +; +;SCREDT = "E" SCREEN EDITOR +;KBD = "K" KEYBOARD +;DISPLY = "S" DISPLAY +;PRINTR = "P" PRINTER +;CASSET = "C" CASSETTE +;DISK = "D" DISK DRIVE +; +; +; +; STATUS CODES +; +; + +; 20070529 bkw: These are returned as error codes, though various DOSes +; also define their own codes (usually in the range 160-255). +; Errors 2-21 are defined by BASIC. +; Errors 150-154 are defined by the R: (850 or compatible, RS-232) handler. +SUCCES = $01 ; 1 +BRKABT = $80 ; 128 BREAK KEY ABORT +PRVOPN = $82 ; 130 IOCB ALREADY OPEN +NONDEV = $82 ; 130 NONEXISTANT DEVICE +WRONLY = $83 ; 131 OPENED FOR WRITE ONLY +NVALID = $84 ; 132 INVALID COMMAND +NOTOPN = $85 ; 133 DEVICE OR FILE NOT OPEN +BADIOC = $86 ; 134 INVALID IOCB NUMBER +RDONLY = $87 ; 135 OPENED FOR READ ONLY +EOFERR = $88 ; 136 END OF FILE +TRNRCD = $89 ; 137 TRUNCATED RECORD +TIMOUT = $8A ; 138 PERIPHERAL TIME OUT +DNACK = $8B ; 139 DEVICE DOES NOT ACKNOWLEDGE +FRMERR = $8C ; 140 SERIAL BUS FRAMING ERROR +CRSROR = $8D ; 141 CURSOR OUT OF RANGE +OVRRUN = $8E ; 142 SERIAL BUS DATA OVERRUN +CHKERR = $8F ; 143 SERIAL BUS CHECKSUM ERROR +DERROR = $90 ; 144 PERIPHERAL DEVICE ERROR +BADMOD = $91 ; 145 NON EXISTANT SCREEN MODE +FNCNOT = $92 ; 146 FUNCTION NOT IMPLEMENTED +SCRMEM = $93 ; 147 NOT ENOUGH MEMORY FOR SCREEN MODE + +; BASIC error codes (also used by e.g. Basic XL/XE and Turbo BASIC): +;; 2: Insufficient Memory +;; 3: Value Error +;; 4: Too Many Variables +;; 5: String Length Error +;; 6: Out of Data Error +;; 7: Number Greater than 32767 +;; 8: Input Statement Error +;; 9: Array or String DIM Error +;; 10: Argument Stack Overflow +;; 11: Floating Point Overflow or Underflow Error +;; 12: Line Not Found +;; 13: No Matching FOR Statement +;; 14: Line Too Long +;; 15: GOSUB or FOR Line Deleted +;; 16: RETURN Error +;; 17: Garbage Error +;; 18: Invalid String Character +;; 19: LOAD Program Too Long +;; 20: Bad Channel Number +;; 21: LOAD File Error + +; 850/R: error codes: +;; 150: Serial Port Already Open +;; 151: Concurrent Mode Not Enabled +;; 152: Illegal User-Supplied Buffer +;; 153: Active Concurrent Mode Error +;; 154: Concurrent Mode Not Active + +; DOS error codes (DOS 2.0S only; other DOSes may define other errors) +;; 160: Device Number Error +;; 161: Too Many OPEN Files +;; 162: Disk Full +;; 163: Fatal System Error +;; 164: File Number Mismatch +;; 165: Bad File Name +;; 166: POINT Data Length Error +;; 167: File Locked +;; 168: Invalid XIO Command +;; 169: Directory Full +;; 170: File Not Found +;; 171: POINT Invalid +;; 172: DOS 1 File +;; 173: Bad Sector +;; 255: FORMATTING Error (DOS 2.5) + +; +; +; +; +; COMMAND CODES FOR CIO +; +; + +; Command byte goes in ICCOM,x + +;; General-purpose commands: +C_OPEN = $03 ; 3 OPEN (BASIC OPEN) +C_GETREC = $05 ; 5 GET RECORD +C_GETCHR = $07 ; 7 GET BYTE +C_PUTREC = $09 ; 9 WRITE RECORD +C_PUTCHR = $0B ; 11 PUT-BYTE +C_CLOSE = $0C ; 12 +C_STATUS = $0D ; 13 +C_SPECIL = $0E ; 14 BEGINNING OF SPECIAL COMMANDS (aka XIO) +;; Commands for S: device: +C_DRAWLN = $11 ; 17 SCREEN DRAW (BASIC DRAWTO) +C_FILLIN = $12 ; 18 SCREEN FILL +;; Commands for D: device (only when DOS is loaded): +C_RENAME = $20 ; 32 +C_DELETE = $21 ; 33 +C_LOCK = $23 ; 35 +C_UNLOCK = $24 ; 36 +C_POINT = $25 ; 37 +C_NOTE = $26 ; 38 + +; AUX1 modes (ICAX1,x or 2nd parameter of BASIC OPEN command): +C_OPREAD = $04 ; 4 OPEN FOR INPUT +C_OWRITE = $08 ; 8 OPEN FOR OUTPUT +C_APPEND = $09 ; 9 OPEN TO APPEND TO END OF DISK FILE +C_OUPDAT = $0C ; 12 OPEN FOR INPUT AND OUTPUT AT THE SAME TIME +;; D: (DOS) only: +C_OPDIR = $06 ; 6 OPEN TO DISK DIRECTORY +;; S: only: +C_MXDMOD = $10 ; 16 OPEN TO SPLIT SCREEN (MIXED MODE) +C_INSCLR = $20 ; 32 OPEN TO SCREEN BUT DON'T ERASE +;; C: only: +C_NOIRG = $80 ; 128 NO GAP CASSETTE MODE + +;; Command bytes (ICCOM) for the RS-232 (R:) device: +;; +;; Output partial block 32 $20 +;; Control RTS,XMT,DTR 34 $22 +;; Baud, stop bits, word size 36 $24 +;; Translation mode 38 $26 +;; Concurrent mode 40 $28 +;; +;; (see the 850 Interface Manual for details) + + +; SIO command bytes (not part of CIO): +S_DFRMAT = $21 ; 33 FORMAT DISK (RESIDENT DISK HANDLER (RDH)) +S_PTSECT = $50 ; 80 RDH PUT SECTOR +S_GTSECT = $52 ; 82 RDH GET SECTOR +S_DSTAT = $53 ; 83 RDH GET STATUS +S_PSECTV = $57 ; 87 RDH PUT SECTOR AND VERIFY +; Various other SIO commands are supported by different drives + +; 20061028 bkw: CR/EOL not really part of CIO, but useful: +CR = $9B ; 155 CARRIAGE RETURN (EOL) +EOL = CR ; defined in SYSEQU.ASM + +; +IOCBSZ = $10 ; 16 IOCB SIZE +MAXIOC = $80 ; 128 MAX IOCB BLOCK SIZE +IOCBF = $FF ; 255 IOCB FREE +; +LEDGE = $02 ; 2 DEFAULT LEFT MARGIN +REDGE = $27 ; 39 DEFAULT RIGHT MARGIN + +; OS VARIABLES +; +; PAGE 0 +; +LINZBS = $00 ; 0 (800) FOR ORIGINAL DEBUGGER +; $00 0 (XL) RESERVED +NGFLAG = $01 ; 1 (XL) FOR POWER-UP SELF TEST +CASINI = $02 ; 2 +RAMLO = $04 ; 4 POINTER FOR SELF TEST +TRAMSZ = $06 ; 6 TEMPORARY RAM SIZE +TSTDAT = $07 ; 7 TEST DATA +WARMST = $08 ; 8 +BOOTQ = $09 ; 9 SUCCESSFUL BOOT FLAG +; aka BOOT? in the OS source, but some assemblers don't support ? in labels +DOSVEC = $0A ; 10 PROGRAM RUN VECTOR +DOSINI = $0C ; 12 PROGRAM INITIALIZATION +APPMHI = $0E ; 14 DISPLAY LOW LIMIT +POKMSK = $10 ; 16 IRQ ENABLE FLAGS (shadow for IRQEN) +BRKKEY = $11 ; 17 FLAG +RTCLOK = $12 ; 18 3 BYTES, MSB FIRST +BUFADR = $15 ; 21 INDIRECT BUFFER ADDRESS +ICCOMT = $17 ; 23 COMMAND FOR VECTOR +DSKFMS = $18 ; 24 DISK FILE MANAGER POINTER +DSKUTL = $1A ; 26 DISK UTILITY POINTER (DUP.SYS) +PTIMOT = $1C ; 28 (800) PRINTER TIME OUT REGISTER +ABUFPT = $1C ; 28 (XL) RESERVED +PBPNT = $1D ; 29 (800) PRINTER BUFFER POINTER +; $1D ; 29 (XL) RESERVED +PBUFSZ = $1E ; 30 (800) PRINTER BUFFER SIZE +; $1E ; 30 (XL) RESERVED +PTEMP = $1F ; 31 (800) TEMPORARY REGISTER (PTEMP deleted in XL OS) +; $1F ; 31 (XL) RESERVED +ZIOCB = $20 ; 32 ZERO PAGE IOCB +ICHIDZ = $20 ; 32 HANDLER INDEX NUMBER (ID) +ICDNOZ = $21 ; 33 DEVICE NUMBER +ICCOMZ = $22 ; 34 COMMAND +ICSTAZ = $23 ; 35 STATUS +ICBALZ = $24 ; 36 BUFFER POINTER LOW BYTE +ICBAHZ = $25 ; 37 BUFFER POINTER HIGH BYTE +ICPTLZ = $26 ; 38 PUT ROUTINE POINTER LOW +ICPTHZ = $27 ; 39 PUT ROUTINE POINTER HIGH +ICBLLZ = $28 ; 40 BUFFER LENGTH LOW +ICBLHZ = $29 ; 41 +ICAX1Z = $2A ; 42 AUXILIARY INFORMATION BYTE 1 +ICAX2Z = $2B ; 43 +ICSPRZ = $2C ; 44 TWO SPARE BYTES (CIO USE) +ICIDNO = $2E ; 46 IOCB NUMBER X 16 +CIOCHR = $2F ; 47 CHARACTER BYTE FOR CURRENT OPERATION +; +STATUS = $30 ; 48 STATUS STORAGE +CHKSUM = $31 ; 49 SUM WITH CARRY ADDED BACK +BUFRLO = $32 ; 50 DATA BUFFER LOW BYTE +BUFRHI = $33 ; 51 +BFENLO = $34 ; 52 ADDRESS OF LAST BUFFER BYTE +1 (LOW) +BFENHI = $35 ; 53 +CRETRY = $36 ; 54 (800) NUMBER OF COMMAND FRAME RETRIES +XL_LTEMP = $36 ; 54 (XL) LOADER TEMPORARY STORAGE, 2 BYTES +DRETRY = $37 ; 55 (800) DEVICE RETRIES +BUFRFL = $38 ; 56 BUFFER FULL FLAG +RECVDN = $39 ; 57 RECEIVE DONE FLAG +XMTDON = $3A ; 58 TRANSMISSION DONE FLAG +CHKSNT = $3B ; 59 CHECKSUM-SENT FLAG +NOCKSM = $3C ; 60 CHECKSUM-DOES-NOT-FOLLOW-DATA FLAG +BPTR = $3D ; 61 +FTYPE = $3E ; 62 +FEOF = $3F ; 63 +FREQ = $40 ; 64 +; +SOUNDR = $41 ; 65 0=QUIET I/O +CRITIC = $42 ; 66 CRITICAL FUNCTION FLAG, NO DEFFERED VBI +FMSZPG = $43 ; 67 DOS ZERO PAGE, 7 BYTES +CKEY = $4A ; 74 (800) START KEY FLAG +XL_ZCHAIN = $4A ; 74 (XL) HANDLER LOADER TEMP, 2 BYTES +CASSBT = $4B ; 75 (800) CASSETTE BOOT FLAG +DSTAT = $4C ; 76 DISPLAY STATUS +; +ATRACT = $4D ; 77 +DRKMSK = $4E ; 78 ATTRACT MASK +COLRSH = $4F ; 79 ATTRACT COLOR SHIFTER (EORed WITH GRAPHICS) +; +TMPCHR = $50 ; 80 +HOLD1 = $51 ; 81 +LMARGN = $52 ; 82 SCREEN LEFT MARGIN REGISTER +RMARGN = $53 ; 83 SCREEN RIGHT MARGIN +ROWCRS = $54 ; 84 CURSOR ROW +COLCRS = $55 ; 85 CURSOR COLUMN, 2 BYTES +DINDEX = $57 ; 87 DISPLAY MODE +SAVMSC = $58 ; 88 SCREEN ADDRESS +OLDROW = $5A ; 90 CURSOR BEFORE DRAW OR FILL +OLDCOL = $5B ; 91 +OLDCHR = $5D ; 93 DATA UNDER CURSOR +OLDADR = $5E ; 94 CURSOR ADDRESS +XL_FKDEF = $60 ; 96 (XL) FUNCTION KEY DEFINITION POINTER (LSB/MSB) +NEWROW = $60 ; 96 (800) DRAWTO DESTINATION +NEWCOL = $61 ; 97 (800) DRAWTO DESTINATION, 2 BYTES +XL_PALNTS = $62 ; 98 (XL) EUROPE/NORTH AMERICA TV FLAG +LOGCOL = $63 ; 99 LOGICAL LINE COLUMN POINTER +MLTTMP = $66 ; 102 +OPNTMP = $66 ; 102 TEMPORARY STORAGE FOR CHANNEL OPEN +SAVADR = $68 ; 104 +RAMTOP = $6A ; 106 START OF ROM (END OF RAM + 1), HIGH BYTE ONLY +BUFCNT = $6B ; 107 BUFFER COUNT +BUFSTR = $6C ; 108 POINTER USED BY EDITOR +BITMSK = $6E ; 110 POINTER USED BY EDITOR +SHFAMT = $6F ; 111 +ROWAC = $70 ; 112 +COLAC = $72 ; 114 +ENDPT = $74 ; 116 +DELTAR = $76 ; 118 +DELTAC = $77 ; 119 +ROWINC = $79 ; 121 (800) +XL_KEYDEF = $79 ; 121 (XL) KEY DEFINITION POINTER, 2 BYTES +COLINC = $7A ; 122 (800) +SWPFLG = $7B ; 123 NON 0 IF TEXT AND REGULAR RAM IS SWAPPED +HOLDCH = $7C ; 124 CH MOVED HERE BEFORE CTRL AND SHIFT +INSDAT = $7D ; 125 used by S: handler, tmp for char under cursor +COUNTR = $7E ; 126 used by XIO DRAW command (2 bytes) + +; $80 to $FF are free if BASIC and floating point are not used. +; If BASIC is not used, but FP is, $80 to $D0 are still free. +; There is no way to use BASIC without constantly using FP, as all BASIC +; numbers are FP (even "integers" such as line numbers). +ZROFRE = $80 ; 128 FREE ZERO PAGE, 84 BYTES + +; BASIC zero page variables: +LOMEM = $80 ; 128 LSB, BASIC start-of-memory pointer +; $81 ; 129 MSB, LOMEM (not to be confused with the OS's MEMLO!) +VNTP = $82 ; 130 LSB, BASIC start of Variable Name Table pointer +; $83 ; 131 MSB, VNTP +VNTD = $84 ; 132 LSB, BASIC end of Variable Name Table pointer (+1 byte) +; $85 ; 133 MSB, VNTP +VVTP = $86 ; 134 LSB, BASIC start of Variable Value Table pointer +; $87 ; 135 MSB, VVTP +STMTAB = $88 ; 136 LSB, BASIC start of Statement Table pointer +; $89 ; 137 MSB, STMTAB +STMCUR = $8A ; 138 LSB, BASIC current statement pointer +; $8B ; 139 MSB, STMCUR +STARP = $8C ; 140 LSB, BASIC current string/array table pointer +; $8D ; 141 MSB, STARP (also points to end of BASIC program) +RUNSTK = $8E ; 142 LSB, BASIC runtime stack pointer +; $8F ; 143 MSG, RUNSTK +; BASIC and the OS both use the name MEMTOP; I've renamed the BASIC one. +BAS_MEMTOP = $90 ; 144 LSB, pointer to top of BASIC memory +; $91 ; 145 MSB, BAS_MEMTOP +MEOLFLG = $92 ; 146 "modified EOL flag register", whatever that is +; $93 ; 147 listed as "spare" by Mapping's Errata +;COX = $94 ; 148 current output index (?) +POKADR = $95 ; 149 LSB, address of last POKE location +; ; 150 MSB, POKADR + +; Locations $96 to $B5 are used for various purposes by BASIC, +; and most of them are of little or no interest, even for someone +; writing assembly code meant to run as a USR() routine, so I haven't +; bothered listing them all here. See Compute! Books' "Atari BASIC Sourcebook" +; for the gory details. In fact, you can see it here: + +; http://users.telenet.be/kim1-6502/6502/absb.html + +; It's fascinating (at least it is to me)... includes full source code +; to Atari BASIC! + +; DATAD and DATALN are reset to 0 by BASIC RESTORE command. +DATAD = $B6 ; 182 the data element being read (e.g. 10 for 10th item + ; in a DATA statement) +DATALN = $B7 ; 183 LSB current DATA statement line number +; $B8 ; 184 MSB, DATALN +;ERRNUM = $B9 ; 185 Most recent error number. Gets cleared before you + ; can PEEK it; use ERRSAVE instead. +STOPLN = $BA ; 186 LSB, line where a program stopped by STOP/break/error +; $BB ; 187 MSB, STOPLN +; what are $BC and $BD for? +SAVCUR = $BE ; 190 Saves the current line address (LSB?) +; $BF ; 191 presumably, the MSB of SAVCUR? +IOCMD = $C0 ; 192, I/O Command (Mapping Errata) +IODVC = $C1 ; 193, I/O Device (Mapping Errata) +PROMPT = $C2 ; 194, Prompt character (Mapping Errata, presumably INPUT?) +ERRSAVE = $C3 ; 195 Error code that caused a stop or TRAP +;TEMPA = $C4 ; 196 a 2-byte temp +;ZTEMP2 = $C6 ; 198 a 2-byte temp +COLOR = $C8 ; 200 Stores color from COLOR command +PTABW = $C9 ; 201 Number of columns between tab stops + ; (for PRINT with commas, not the TAB key) +LOADFLG = $CA ; 202 Load in progress flag. I can tell you from bitter + ; experience that BASIC clears this often. + +; $CB - $CF are unused by BASIC or the ASM/ED cart. +; $D0 and $D1 are unused by BASIC (does that mean they *are* used by ASM/ED?) + +; $D2 and $D3 are used by BASIC. Mapping Errata calls them the "BASIC +; floating-point work area". They get cleared to 0 by BASIC, probably +; every time a FP number is used (e.g. "POKE 210,1:? PEEK(210)" prints 0). +; The BASIC source code labels $D2 as TVTYPE and VTYPE, and $D3 as +; TVNUM and VNUM. + +; Floating point zero page variables: +FPZRO = $D4 ; 212 FLOATING POINT RAM, 43 BYTES + ; (20070530 bkw: pretty sure that comment is wrong, and + ; should read 44 bytes; see $FF below) +FR0 = $D4 ; 212 FP REGISTER 0 (also used by BASIC for USR() return val) + ; (FR0/FRE/FR1/FR2 are each 6 bytes long) +FRE = $DA ; 218 +FR1 = $E0 ; 224 FP REGISTER 1 +FR2 = $E6 ; 230 FP REGISTER 2 +FRX = $EC ; 236 SPARE +EEXP = $ED ; 237 VALUE OF E +NSIGN = $ED ; 237 SIGN OF FP NUMBER +ESIGN = $EF ; 239 SIGN OF FP EXPONENT +FCHFLG = $F0 ; 240 FIRST CHARACTER FLAG +DIGRT = $F1 ; 241 NUMBER OF DIGITS RIGHT OF DECIMAL POINT +CIX = $F2 ; 242 INPUT INDEX +INBUFF = $F3 ; 243 POINTER TO ASCII FP NUMBER +ZTEMP1 = $F5 ; 245 +ZTEMP4 = $F7 ; 247 +ZTEMP3 = $F9 ; 249 +DEGFLG = $FB ; 251 +RADFLG = $FB ; 251 0=RADIANS, 6=DEGREES +FLPTR = $FC ; 252 POINTER TO BCD FP NUMBER (2 bytes) +FPTR2 = $FE ; 254 maybe a 2nd pointer to an FP number? (2 bytes) +; $FF ; 255 This *definitely* is used by the FP package + ; Try: POKE 255,0:? SIN(1):? PEEK(255) + +; +; PAGE 1 +; +; 65O2 STACK +; +; + +; +; +; PAGE 2 +; +; +; 20070529 bkw: Bytes listed as "spare" should NOT be used for your own +; purposes. They may not really be unused (just undocumented), and/or they +; may be unused on the 800 but not the XL (or vice versa). +INTABS = $0200 ; 512 INTERRUPT RAM +VDSLST = $0200 ; 512 NMI VECTOR +VPRCED = $0202 ; 514 PROCEED LINE IRQ VECTOR +VINTER = $0204 ; 516 INTERRUPT LINE IRQ VECTOR +VBREAK = $0206 ; 518 break key IRQ vector (not in OS rev. A) +VKEYBD = $0208 ; 520 keyboard IRQ vector (not break/console keys) +VSERIN = $020A ; 522 SERIAL INPUT READY IRQ +VSEROR = $020C ; 524 SERIAL OUTPUT READY IRQ +VSEROC = $020E ; 526 SERIAL OUTPUT COMPLETE IRQ +VTIMR1 = $0210 ; 528 TIMER 1 IRQ vector +VTIMR2 = $0212 ; 530 TIMER 2 IRQ vector +VTIMR4 = $0214 ; 532 TIMER 4 IRQ vector +VIMIRQ = $0216 ; 534 IRQ VECTOR +CDTMV1 = $0218 ; 536 COUNTDOWN TIMER 1 vector +CDTMV2 = $021A ; 538 COUNTDOWN TIMER 2 vector +CDTMV3 = $021C ; 540 COUNTDOWN TIMER 3 vector +CDTMV4 = $021E ; 542 COUNTDOWN TIMER 4 vector +CDTMV5 = $0220 ; 544 COUNTDOWN TIMER 5 vector +VVBLKI = $0222 ; 546 immediate VBLANK vector +VVBLKD = $0224 ; 548 deferred VBLANK vector (ignore if CRITIC != 0) +CDTMA1 = $0226 ; 550 COUNTDOWN TIMER 1 JSR ADDRESS +CDTMA2 = $0228 ; 552 COUNTDOWN TIMER 2 JSR ADDRESS +CDTMF3 = $022A ; 554 COUNTDOWN TIMER 3 FLAG +SRTIMR = $022B ; 555 REPEAT TIMER +CDTMF4 = $022C ; 556 COUNTDOWN TIMER 4 FLAG +INTEMP = $022D ; 557 IAN'S TEMP (used by SETVBL routine) +CDTMF5 = $022E ; 558 COUNTDOWN TIMER FLAG 5 +SDMCTL = $022F ; 559 DMACTL SHADOW +SDLSTL = $0230 ; 560 DISPLAY LIST POINTER, LSB (shadow for DLISTL) +SDLSTH = $0231 ; 561 display list pointer, MSB (shadow for DLISTH) +SSKCTL = $0232 ; 562 SKCTL SHADOW +; $0233 ; 563 (800) UNLISTED (Mapping calls this SPARE) +XL_LCOUNT = $0233 ; 563 (XL) LOADER TEMP +LPENH = $0234 ; 564 LIGHT PEN HORIZONTAL (shadow for PENH) +LPENV = $0235 ; 565 LIGHT PEN VERTICAL (shadow for PENV) +; $0236 ; 566 2 SPARE BYTES on OS rev A +VBRKKY = $0236 ; 566 Break key interrupt vector (OS rev B and XL) +BRKKY = VBRKKY ; "OS rev 5" listing calls it this +; $0238 ; 568 (800) SPARE, 2 BYTES +;XL_RELADR = $0238 ; 568 (XL) relocatable loader relative addr, 1200XL only! +XL_VPIRQ = $0238 ; 568 (XL) PBI IRQ vector (not on 1200XL!) +CDEVIC = $023A ; 570 DEVICE COMMAND FRAME BUFFER +CAUX1 = $023C ; 572 DEVICE COMMAND AUX 1 +CAUX2 = $023D ; 573 DEVICE COMMAND AUX 2 +TEMP = $023E ; 574 TEMPORARY STORAGE +ERRFLG = $023F ; 575 DEVICE ERROR FLAG (EXCEPT TIMEOUT) +DFLAGS = $0240 ; 576 FLAGS FROM DISK SECTOR 1 +DBSECT = $0241 ; 577 NUMBER OF BOOT DISK SECTORS +BOOTAD = $0242 ; 578 BOOT LOAD ADDRESS POINTER +COLDST = $0244 ; 580 COLD START FLAG, 1 = COLD START IN PROGRESS +; $0245 ; 581 (800) SPARE +XL_RECLEN = $0245 ; 581 (XL) LOADER +DSKTIM = $0246 ; 582 (800) DISK TIME OUT REGISTER +; $0246 ; 582 (XL) RESERVED, 39 BYTES +LINBUF = $0247 ; 583 (800) CHARACTER LINE BUFFER, 40 BYTES + ; LINBUF was deleted from the XL OS and replaced with: + +; $0247 - $024D are "reserved" on the 1200XL. On other XL's they are: +XL_PDVMSK = $0247 ; 583 shadow for PBI device selection register @ $D1FF +XL_SHPDVS = $0248 ; 584 shadow for PBI register (where??) +XL_PDMSK = $0249 ; 585 PBI interrupt mask +XL_RELADR = $024A ; 586 (XL) LSB, relocatable loader relative addr (NOT 1200XL) +; $024B ; 587 MSB, XL_RELADR +XL_PPTMPA = $024C ; 588 temporaries for relocatable loader +XL_PPTMPX = $024D ; 589 " + +; $024E - $026A are "spare" on all XL/XE's + +; More XL stuff: +XL_CHSALT = $026B ; 619 (XL) CHARACTER SET POINTER (ctrl-F4 on 1200XL) +XL_VSFLAG = $026C ; 620 (XL) FINE SCROLL TEMPORARY +XL_KEYDIS = $026D ; 621 (XL) KEYBOARD DISABLE (ctrl-F1 on 1200XL) +XL_FINE = $026E ; 622 (XL) FINE SCROLL FLAG (POKE 622,255:GR.0) + +GPRIOR = $026F ; 623 P/M PRIORITY AND GTIA MODES (shadow for PRIOR) +;GTIA = $026F ; 623 ; 20070529 bkw: does anyone define this? + +; Game controller shadows (joysticks/paddles) +; Joystick directions and paddle triggers (buttons) are wired to the PIA. +; Joystick triggers (fire buttons) and the actual paddle potentiometers +; are wired to the GTIA. +; If this seems a little odd, that's because it is :) + +; Paddles (potentiometers): +PADDL0 = $0270 ; 624 (XL) 3 MORE PADDLES, (800) 7 MORE PADDLES +PADDL1 = $0271 ; 625 (these are read in BASIC with PADDLE(x) +PADDL2 = $0272 ; 626 (PADDL0-7 are shadows for POT0-7) +PADDL3 = $0273 ; 627 +PADDL4 = $0274 ; 628 (PADDL4-7 are copies of PADDL0-3 on the XL) +PADDL5 = $0275 ; 629 +PADDL6 = $0276 ; 630 +PADDL7 = $0277 ; 631 + +; Joysticks (directions only) +STICK0 = $0278 ; 632 (XL) 1 MORE STICK, (800) 3 MORE STICKS +STICK1 = $0279 ; 633 (these are read in BASIC with STICK(x) +STICK2 = $027A ; 634 (STICK0/1 are shadows for PORTA; STICK2/3 shadows PORTB) +STICK3 = $027B ; 635 +; STICK0 is a shadow for bits 4-7 of PORTA (shifted 4 bits right) +; STICK1 is a shadow for bits 0-3 of PORTA + +; On the 800: +; STICK2 is a shadow for bits 4-7 of PORTB (shifted 4 bits right) +; STICK3 is a shadow for bits 0-3 of PORTB + +; On the XL/XE series: +; STICK2 and STICK3 are copies of STICK0 and STICK1, respectively. + +; In the XL/XE machines, there are only 2 joystick ports, and PORTB +; (formerly joystick ports) is now used to control the MMU. + +; joystick directions are active low (1=not pressed) and decode as: + +; bit direction +; 0 or 4 up +; 1 or 5 down +; 2 or 6 left +; 3 or 7 right + +; A value of $0F in a STICKx register means no direction is being pressed. +; When a direction is pressed, its bit becomes a logic 0, so e.g. $0E means +; someone's moving the joystick up. + +; (bits 4-7 are only used when reading directly from the HW registers, +; PORTA and PORTB). + +; Paddle triggers (buttons) +PTRIG0 = $027C ; 636 (XL) 3 MORE PADDLE TRIGGERS, (800) 7 MORE +PTRIG1 = $027D ; 637 (these are read in BASIC with PTRIG(x)) +PTRIG2 = $027E ; 638 (PTRIG0-3 are shadows for PORTA) +PTRIG3 = $027F ; 639 +PTRIG4 = $0280 ; 640 (PTRIG4-7 are shadows for PORTB on the 800) +PTRIG5 = $0281 ; 641 (they are copies of PTRIG0-3 on the XL) +PTRIG6 = $0282 ; 642 +PTRIG7 = $0283 ; 643 +; In case someone doesn't already know this: The paddle triggers are wired +; to the same pins on the joystick port as the left/right joystick directions. +; Each pair of paddles uses left for the first paddle's trigger and right +; for the second (so PTRIG0/1 are also the left/right bits in STICK0, +; PTRIG2/3 are STICK1, etc). + +; Joystick triggers (buttons) +STRIG0 = $0284 ; 644 (XL) 1 MORE STICK TRIGGER, (800) 3 MORE +STRIG1 = $0285 ; 645 (these are read in BASIC with STRIG(x)) +STRIG2 = $0286 ; 646 (STRIG0-3 are shadows for TRIG0-3) +STRIG3 = $0287 ; 647 + +; C: handler variables: +CSTAT = $0288 ; 648 (800) Cassette status register +; note that CSTAT was deleted from the XL OS, and replaced with: +XL_HIBYTE = $0288 ; 648 (XL) used by relocatable loader +WMODE = $0289 ; 649 used by C: handler (0=read, 128-write) +BLIM = $028A ; 650 cassette buffer data record size +; $028B ; 651 (800) 5 SPARE BYTES (to $028F) +XL_IMASK = $028B ; 651 (XL) used by relocatable loader +XL_JVECK = $028C ; 652 (XL) (Mapping says it's unused) + ; 653 (XL) Presumably the MSB of JVECK (unused?) +XL_NEWADR = $028E ; 654 (XL) LOADER RAM (2 bytes) + +; Misc. S: and/or E: handler variables: +TXTROW = $0290 ; 656 +TXTCOL = $0291 ; 657 +TINDEX = $0293 ; 659 TEXT INDEX +TXTMSC = $0294 ; 660 +TXTOLD = $0296 ; 662 OLD ROW AND OLD COL FOR TEXT, 2 BYTES +; $0298 ; 664 4 SPARE BYTES +TMPX1 = $029C ; 668 (800) +; note that TMPX1 was deleted from the XL OS, and replaced with: +XL_CRETRY = $029C ; 668 (XL) NUMBER OF COMMAND FRAME RETRIES + ; (moved from CRETRY on 800) +SUBTMP = $029E ; 670 +HOLD2 = $029F ; 671 +DMASK = $02A0 ; 672 +TMPLBT = $02A1 ; 673 +ESCFLG = $02A2 ; 674 +TABMAP = $02A3 ; 675 15 BYTE BIT MAP FOR TAB SETTINGS +LOGMAP = $02B2 ; 690 4 BYTE LOGICAL LINE START BIT MAP +INVFLG = $02B6 ; 694 mask for inverse video ($80=inverse, 0=normal) +FILFLG = $02B7 ; 695 FILL DURING DRAW FLAG +TMPROW = $02B8 ; 696 +TMPCOL = $02B9 ; 697 +SCRFLG = $02BB ; 699 SCROLL FLAG +HOLD4 = $02BC ; 700 +HOLD5 = $02BD ; 701 (800) +; note that HOLD5 was deleted from the XL OS, and replaced with: +XL_DRETRY = $02BD ; 701 (XL) NUMBER OF DEVICE RETRIES + ; (moved from DRETRY on 800) +SHFLOC = $02BE ; 702 +BOTSCR = $02BF ; 703 24 NORM, 4 SPLIT + +; Color register shadows (HW registers are in GTIA) +PCOLR0 = $02C0 ; 704 3 MORE PLAYER COLOR REGISTERS (shadows for COLPM0-3) +PCOLR1 = $02C1 ; 705 (missiles use same color regs as same-numbered players!) +PCOLR2 = $02C2 ; 706 +PCOLR3 = $02C3 ; 707 +COLOR0 = $02C4 ; 708 4 MORE GRAPHICS COLOR REGISTERS (shadows for COLPF0-3) +COLOR1 = $02C5 ; 709 (text luminance in GR.0) +COLOR2 = $02C6 ; 710 (text background and chroma in GR.0) +COLOR3 = $02C7 ; 711 +COLOR4 = $02C8 ; 712 (background, shadow for COLBK) +; On boot, system reset, or any time S:/E: devices are opened: +; PCOLR0-3 are initialzed to 0 ($00, black) +; COLOR0 is initialized to 40 ($28, orange) +; COLOR1 is initialized to 202 ($CA, green) +; COLOR2 is initialized to 148 ($94, blue) +; COLOR3 is initialized to 70 ($46, red) +; COLOR4 is initialized to 0 ($00, black) + +; $02C9 713 (800) 23 SPARE BYTES +; XL relocatable handler and other variables: +XL_RUNADR = $02C9 ; 713 (XL) LOADER VECTOR +XL_HIUSED = $02CB ; 715 (XL) LOADER VECTOR +XL_ZHIUSE = $02CD ; 717 (XL) LOADER VECTOR +XL_GBYTEA = $02CF ; 719 (XL) LOADER VECTOR +XL_LOADAD = $02D1 ; 721 (XL) LOADER VECTOR +XL_ZLOADA = $02D3 ; 723 (XL) LOADER VECTOR +XL_DSCTLN = $02D5 ; 725 (XL) DISK SECTOR SIZ +XL_ACMISR = $02D7 ; 727 (XL) RESERVED +XL_KRPDER = $02D9 ; 729 (XL) KEY AUTO REPEAT DELAY +XL_KEYREP = $02DA ; 730 (XL) KEY AUTO REPEAT RATE +XL_NOCLIK = $02DB ; 731 (XL) KEY CLICK DISABLE (ctrl-F3 on 1200XL) +XL_HELPFG = $02DC ; 732 (XL) HELP KEY FLAG +XL_DMASAV = $02DD ; 733 (XL) SDMCTL (DMA) SAVE (ctrl-F2 on 1200XL) +XL_PBPNT = $02DE ; 734 (XL) PRINTER BUFFER POINTER (moved from PBPNT on 800) +XL_PBUFSZ = $02DF ; 735 (XL) PRINTER BUFFER SIZE (moved from PBUFSZ on 800) +; note that PTEMP was deleted from the XL OS + +; DOS/FMS variables: +GLBABS = $02E0 ; 736 GLOBAL VARIABLES, 4 SPARE BYTES (if DOS not loaded) + ; If DOS/FMS is loaded: +RUNAD = $02E0 ; 736 (DOS) Run address for binary file (LSB/MSB) +INITAD = $02E2 ; 736 (DOS) Init address for binary file (LSB/MSB) + +; SYSEQU.ASM defines these: +GOADR = RUNAD +INITADR = INITAD + +; OS variables: +RAMSIZ = $02E4 ; 740 PERMANENT START OF ROM POINTER +MEMTOP = $02E5 ; 741 END OF FREE RAM +MEMLO = $02E7 ; 743 LSB, points to bottom of free memory ($0700 if DOS + ; not booted). Not to be confused with BASIC's LOMEM! +; $02E8 ; 744 MSB of MEMLO + +; $02E9 ; 745 (800) SPARE +XL_HNDLOD = $02E9 ; 745 (XL) HANDLER LOADER FLAG + +DVSTAT = $02EA ; 746 DEVICE STATUS BUFFER, 4 BYTES +CBAUDL = $02EE ; 750 CASSETTE BAUD RATE, 2 BYTES +CRSINH = $02F0 ; 752 1 = INHIBIT CURSOR +KEYDEL = $02F1 ; 753 KEY DELAY AND RATE (aka debounce counter) +CH1 = $02F2 ; 754 prior keyboard character code +CHACT = $02F3 ; 755 (shadow for CHACTL) +CHBAS = $02F4 ; 756 CHARACTER SET POINTER (shadow for CHBASE) + +; These next 4 are located elsewhere on the 800 OS: +XL_NEWROW = $02F5 ; 757 (XL) DRAW DESTINATION +XL_NEWCOL = $02F6 ; 758 (XL) DRAW DESTINATION +XL_ROWINC = $02F8 ; 760 (XL) +XL_COLINC = $02F9 ; 761 (XL) +; $02F5 - $02F9 are "spare" on the 800. + +CHAR = $02FA ; 762 most recent character read/written (screen code) +ATACHR = $02FB ; 763 ATASCII CHARACTER FOR CIO +CH = $02FC ; 764 last key pressed (internal scan code) +FILDAT = $02FC ; 764 COLOR FOR SCREEN FILL +DSPFLG = $02FE ; 766 DISPLAY CONTROL CHARACTERS FLAG +SSFLAG = $02FF ; 767 DISPLAY START/STOP FLAFG + +; +; PAGE 3 +; +; +; RESIDENT DISK HANDLER/SIO INTERFACE +; +; The DCB is used for SIO (serial I/O). +DCB = $0300 ; 768 DEVICE CONTROL BLOCK +DDEVIC = $0300 ; 768 device ID ($31-$38 for D1:-D8:) +DUNIT = $0301 ; 769 disk/device unit numder +DCOMND = $0302 ; 770 device command +DSTATS = $0303 ; 771 status code (set by OS) +DBUFLO = $0304 ; 772 data buffer LSB (set by user) +DBUFHI = $0305 ; 773 data buffer MSB (set by user) +DTIMLO = $0306 ; 774 timeout (set by user, units of 60/64 seconds) +DUNUSE = $0307 ; 775 unused +DBYTLO = $0308 ; 776 number of bytes to transfer, LSB +DBYTHI = $0309 ; 777 number of bytes to transfer, MSB +DAUX1 = $030A ; 778 LSB of sector number (for disk) (set by user) +DAUX2 = $030B ; 779 MSB of sector number (for disk) +TIMER1 = $030C ; 780 INITIAL TIMER VALUE +ADDCOR = $030E ; 782 (800) ADDITION CORRECTION +; note that ADDCOR was deleted from the XL OS, and replaced with: +XL_JMPERS = $030E ; 782 (XL) OPTION JUMPERS +CASFLG = $030F ; 783 CASSETTE MODE WHEN SET +TIMER2 = $0310 ; 784 FINAL VALUE, TIMERS 1 & 2 DETERMINE BAUD RATE +TEMP1 = $0312 ; 786 +XL_TEMP2 = $0313 ; 787 (XL) +TEMP2 = $0314 ; 788 (800) +XL_PTIMOT = $0314 ; 788 (XL) PRINTER TIME OUT +TEMP3 = $0315 ; 789 +SAVIO = $0316 ; 790 SAVE SERIAL IN DATA PORT +TIMFLG = $0317 ; 791 TIME OUT FLAG FOR BAUD RATE CORRECTION +STACKP = $0318 ; 792 SIO STACK POINTER SAVE +TSTAT = $0319 ; 793 TEMPORARY STATUS HOLDER +HATABS = $031A ; 794 HANDLER ADDRESS TABLE, 38 BYTES +MAXDEV = $0321 ; 801 MAXIMUM HANDLER ADDRESS INDEX +XL_PUPBT1 = $033D ; 829 (XL) POWER-UP/RESET +XL_PUPBT2 = $033E ; 830 (XL) POWER-UP/RESET +XL_PUPBT3 = $033F ; 831 (XL) POWER-UP/RESET + +; IOCB's, 8 of them, 16 bytes each. +; Set X register to (IOCB number * 16), and use e.g. ICCOM,x +; +IOCB = $0340 ; 832 ; IOCB base address +ICHID = $0340 ; 832 ; Handler ID (set by OS) +ICDNO = $0341 ; 833 ; Device number (set by OS) +ICCOM = $0342 ; 834 ; Command byte (see C_* constants) (set by user) +ICCMD = ICCOM ; ; alternate name for ICCOM, according to Mapping. +ICSTA = $0343 ; 835 ; Status (set by OS) +ICBAL = $0344 ; 836 ; Buffer address, LSB (set by user) +ICBAH = $0345 ; 837 ; Buffer address, MSB (set by user) +ICPTL = $0346 ; 838 ; Put-one-byte address minus one, LSB (set by OS) +ICPTH = $0347 ; 839 ; Put-one-byte address minus one, MSB (set by OS) +ICBLL = $0348 ; 840 ; Buffer length, LSB (set by user) +ICBLH = $0349 ; 841 ; Buffer length, MSB (set by user) +ICAX1 = $034A ; 842 ; AUX1 byte (2nd param in BASIC OPEN) (set by user) +ICAX2 = $034B ; 843 ; AUX2 byte (4rd param in BASIC OPEN) (set by user) +ICAX3 = $034C ; 844 ; AUX3 byte (used by NOTE/POINT) (set by user) +ICAX4 = $034D ; 845 ; AUX4 byte (used by NOTE/POINT) (set by user) +ICAX5 = $034E ; 846 ; AUX5 byte (used by NOTE/POINT) (set by user) +ICAX6 = $034F ; 847 ; Spare aux byte +; OTHER IOCB's, 112 BYTES ($300 + $10 * channel) + +IOCBLEN = ICAX6-IOCB+1 ; length of one IOCB (from SYSEQU.ASM) + +; Alternative names for the above. I found these in SYSEQU.ASM, as +; distributed with the disk version of Mac65. +ICBADR = ICBAL +ICPUT = ICPTL +ICBLEN = ICBLL +ICAUX1 = ICAX1 +ICAUX2 = ICAX2 +ICAUX3 = ICAX3 +ICAUX4 = ICAX4 +ICAUX5 = ICAX5 +ICAUX6 = ICAX6 + +PRNBUF = $03C0 ; 960 PRINTER BUFFER, 40 BYTES +; $03E8 ; 1000 (800) 21 SPARE BYTES +XL_SUPERF = $03E8 ; 1000 (XL) SCREEN EDITOR +XL_CKEY = $03E9 ; 1001 (XL) START KEY FLAG +XL_CASSBT = $03EA ; 1002 (XL) CASSETTE BOOT FLAG +XL_CARTCK = $03EB ; 1003 (XL) CARTRIDGE CHECKSUM +XL_ACMVAR = $03ED ; 1005 (XL) RESERVED, 10 BYTES (to $03F7) +XL_BASICF = $03F8 ; 1006 (XL) 0 if ROM-BASIC enabled, 1 if not +XL_MINTLK = $03F9 ; 1017 (XL) RESERVED +XL_GINTLK = $03FA ; 1018 (XL) CARTRIDGE INTERLOCK +XL_CHLINK = $03FB ; 1019 (XL) HANDLER CHAIN, 2 BYTES +CASBUF = $03FD ; 1021 CASSETTE BUFFER, 131 BYTES TO $047F + +; Layout of the cassette buffer after a cassette block is read: + +; Baud correction ($55 $55) bytes are located at offsets 0 and 1 +; Control byte is at offset 2 ($03FF): +; Actual data (128 bytes) runs from offset 3 ($0400) to $047F. +; Each cassette frame has a 1 byte checksum after the 128 data bytes, but +; the checksum is NOT stored anywhere in the cassette buffer! + +; CONTROL BYTE VALUES +; Value Meaning +; 250 ($FA) Partial record follows. The actual number of bytes is stored +; in the last byte of the record (CASBUF+130, or $047F). +; 252 ($FC) Record full; 128 bytes follow. +; 254 ($FE) End of File (EOF) record; followed by 128 zero bytes. + +; Boot tapes normally don't have partial or EOF records, but BASIC +; CLOAD/LOAD/LIST and data file tapes do. + +; Mapping the Atari says the first disk boot sector is read into CASBUF also. + +; +; +; PAGE 4 +; +; +USAREA = $0480 ; 1152 128 SPARE BYTES (but used by BASIC) +; +; SEE APPENDIX C FOR PAGES 4 AND 5 USAGE + +; +; +; +; +; PAGE 5 +; +PAGE5 = $0500 ; 1280 127 FREE BYTES +; $057E 1406 129 FREE BYTES IF FLOATING POINT ROUTINES NOT USED +; +;FLOATING POINT NON-ZERO PAGE RAM, NEEDED ONLY IF FP IS USED +; (20070529 bkw: BASIC constantly uses FP! Also, it uses some of these +; addresses for its own purposes.) +; +LBPR1 = $057E ; 1406 LBUFF PREFIX 1 +LBPR2 = $05FE ; 1534 LBUFF PREFIX 2 +LBUFF = $0580 ; 1408 LINE BUFFER +PLYARG = $05E0 ; 1504 POLYNOMIAL ARGUMENTS +FPSCR = $05E6 ; 1510 PLYARG+FPREC +FPSCR1 = $05EC ; 1516 FPSCR+FPREC +FSCR = $05E6 ; 1510 =FPSCR +FSCR1 = $05EC ; 1516 =FPSCR1 +LBFEND = $05FF ; 1535 END OF LBUFF + +; +; PAGE 6 +; +; +PAGE6 = $0600 ; 1536 256 FREE BYTES + +; +; +; PAGE 7 +; +; +BOOTRG = $0700 ; 1792 PROGRAM AREA +; Boot disks (including DOS) are generally loaded here. Also, BASIC RAM +; (variables and program) starts here, if BASIC is booted without DOS. + +; Page 80 (XL): Self-test (aka diagnostic) ROM is mapped at $5000, +; if enabled with bit 7 of PORTB. Normally only happens if you boot without +; BASIC, cartridge, tape, or disk... or if the OS detects a memory error +; during boot. + +; +; +; UPPER ADDRESSES +; +; +RITCAR = $8000 ;32768 RAM IF NO CARTRIDGE (extends to $9FFF) +LFTCAR = $A000 ;40960 RAM IF NO CARTRIDGE (extends to $BFFF) + +; These 2 are from the Atari System Reference Manual, chapter 12: +CARTA = LFTCAR +CARTB = RITCAR + +CARTLOC = $BFFA ;49146 cartridge run address (from SYSEQU.ASM) + +; Carts were originally 8K only when the 400/800 were first released. +; There were plans to release 16K programs on two cartridges, but this +; never happened (the price of 16K ROMs came down, I guess). 16K cartridges +; go in the left slot, but they actually use the address space for both +; the right and left slots. + +; Mapping the Atari has this to say about cartridges: +;; Byte Purpose +;; Left (A) Right(B) +;; 49146 ($BFFA) 40954 ($9FFA) Cartridge start address (low byte) +;; +;; 49147 ($BFFB) 40955 ($9FFB) Cartridge start address (high byte) +;; +;; 49148 ($BFFC) 40956 ($9FFC) Reads zero if a cartridge is +;; inserted, non-zero when no cartridge is present. This information +;; is passed down to the page zero RAM: if the A cartridge is plugged +;; in, then location 6 will read one; if the B cartridge is plugged in, +;; then location 7 will read one; otherwise they will read zero. +;; +;; 49149 ($BFFD) 40957 ($9FFD) Option byte. If BIT 0 equals one, +;; then boot the disk (else there is no disk boot). If BIT 2 equals one, +;; then initialize and start the cartridge (else initialize but do not +;; start). If BIT 7 equals one, then the cartridge is a diagnostic +;; cartridge which will take control, but not initialize the OS (else +;; non-diagnostic cartridge). Diagnostic cartridges were used by +;; Atari in the development of the system and are not available to the +;; public. +;; +;; 49150 ($BFFE) 40958 ($9FFE) Cartridge initialization address +;; low byte. +;; +;; 49151 ($BFFF) 40959 ($9FFF) Cartridge initialization address +;; high byte. This is the address to which the OS will jump during all +;; powerup and RESETs. +;; +;; The OS makes temporary use of locations 36876 to 36896 ($900C to +;; $9020) to set up vectors for the interrupt handler. See the OS +;; listings pages 31 and 81. This code was only used in the +;; development system used to design the Atari. + + +; Page 192 + +C0PAGE = $C000 ;49152 (800) EMPTY, 4K BYTES + ; 20070529 bkw: unmapped address space. + ; Mapping the Atari erroneously lists this as "unused ROM". + ; There are upgrades to the 800 to give 4K of RAM here + ; (for a total of 52K of RAM), or ROM (Omnimon?). + ; Also, there is RAM here if you boot the Translator + ; disk on an XL. + +; (XL) $C000 also contains info about the ROM revision. From Mapping: + +;Bytes 49152-49163 ($C000-$C00B) are used to identify the computer +;and the ROM in the $C000-$DFFF block: +; +;Byte Use +;49152-3/C000-1 Checksum (LSB/MSB) of all the bytes +; in ROM except the checksum bytes +; themselves. +;49154/C002 Revision date, stored in the form +; DDMMYY. This is DD, day, usually $10. +;49155/C003 Revision date, month; usually $05. +;49156/C004 Revision date, year; usually $83. +;49157/C005 Reserved option byte; reads zero for +; the 1200, 800XL, and 130XE. +;49158/C006 Part number in the form AANNNNNN; +; AA is an ASCII character and +; NNNNNN is a four-bit BCD digit. This is +; byte A1. +;49159-62/C007-A Part number, bytes A2, N1-N6 (each +; byte has two N values of four bits +; each). +;49163/C00B Revision number. Mapping author's 800XL and 130XE say 2. + +;C0PAGE = $C000 ;49152 (XL) OS ROM, mostly interrupt handlers +; $C800 51200 (XL) START OF OS ROM +CHORG2 = $CC00 ;52224 (XL) INTERNATIONAL CHARACTER SET + + + +; +; +; HARDWARE REGISTERS +; +; +; SEE REGISTER LIST FOR MORE INFORMATION +; +; + +; GTIA +GTIA = $D000 +HPOSP0 = $D000 ;53248 (W) ; P/M positions (no shadows) +HPOSP1 = $D001 ;53249 (W) +HPOSP2 = $D002 ;53250 (W) +HPOSP3 = $D003 ;53251 (W) +HPOSM0 = $D004 ;53252 (W) +HPOSM1 = $D005 ;53253 (W) +HPOSM2 = $D006 ;53254 (W) +HPOSM3 = $D007 ;53255 (W) +SIZEP0 = $D008 ;53256 (W) ; P/M size regs (no shadows) +SIZEP1 = $D009 ;53257 (W) +SIZEP2 = $D00A ;53258 (W) +SIZEP3 = $D00B ;53259 (W) +SIZEM = $D00C ;53260 (W) +M0PF = $D000 ;53248 (R) ; collision regs (no shadows) +M1PF = $D001 ;53249 (R) +M2PF = $D002 ;53250 (R) +M3PF = $D003 ;53251 (R) +P0PF = $D004 ;53252 (R) +P1PF = $D005 ;53253 (R) +P2PF = $D006 ;53254 (R) +P3PF = $D007 ;53255 (R) +M0PL = $D008 ;53256 (R) +M1PL = $D009 ;53257 (R) +M2PL = $D00A ;53258 (R) +M3PL = $D00B ;53259 (R) +P0PL = $D00C ;53260 (R) +P1PL = $D00D ;53261 (R) +P2PL = $D00E ;53262 (R) +P3PL = $D00F ;53263 (R) +GRAFP0 = $D00D ;53261 (W) ; direct (non-DMA) P/M graphics regs (no shadows) +GRAFP1 = $D00E ;53262 (W) +GRAFP2 = $D00F ;53263 (W) +GRAFP3 = $D010 ;53264 (W) +GRAFM = $D011 ;53265 (W) +TRIG0 = $D010 ;53264 (R) ; Joystick triggers (shadows @ STRIG0-3) +TRIG1 = $D011 ;53265 (R) +TRIG2 = $D012 ;53266 (R) +TRIG3 = $D013 ;53267 (R) +PAL = $D014 ;53268 (R) ; PAL/NTSC detect (no shadow) + ; PAL supposedly moved to XL_PALNTS on XL; what was it + ; replaced with? +COLPM0 = $D012 ;53266 (W) ; P/M colors (shadows @ PCOLR0-3) +COLPM1 = $D013 ;53267 (W) +COLPM2 = $D014 ;53268 (W) +COLPM3 = $D015 ;53269 (W) +COLPF0 = $D016 ;53270 (W) ; Playfield colors (shadows @ COLOR0-3) +COLPF1 = $D017 ;53271 (W) +COLPF2 = $D018 ;53272 (W) +COLPF3 = $D019 ;53273 (W) +COLBK = $D01A ;53274 (W) ; Background color (shadow @ COLOR4) +PRIOR = $D01B ;53275 (W) ; GTIA priority (shadow @ GPRIOR) +GTIAR = $D01B ;53275 (R?) +VDELAY = $D01C ;53276 (W) +GRACTL = $D01D ;53277 (W) +HITCLR = $D01E ;53278 (W), latch +CONSOL = $D01F ;53279 (W=keyclick spkr, R=console keys) + +; $D020 - $D0FF are mirrors of GTIA address space +; $D100 - $D1FF are supposed to be unused (unmapped) on the 800 +; On the XL, $D100 - $D1FF is switched to device memory during PBI I/O + +; POKEY +POKEY = $D200 +; no shadows for AUDC/AUDF +AUDF1 = $D200 ;53760 (W) ; Audio frequency 1 +AUDC1 = $D201 ;53761 (W) ; Audio control 1 (distortion/volume) +AUDF2 = $D202 ;53762 (W) +AUDC2 = $D203 ;53763 (W) +AUDF3 = $D204 ;53764 (W) +AUDC3 = $D205 ;53765 (W) +AUDF4 = $D206 ;53766 (W) +AUDC4 = $D207 ;53767 (W) + +; POT0-7 shadows at PADDL0-7 +POT0 = $D200 ;53760 (R) ; Paddle positions +POT1 = $D201 ;53761 (R) +POT2 = $D202 ;53762 (R) +POT3 = $D203 ;53763 (R) +POT4 = $D204 ;53764 (R) ; pots 3-7 don't exist on XL/XE +POT5 = $D205 ;53765 (R) +POT6 = $D206 ;53766 (R) +POT7 = $D207 ;53767 (R) + +AUDCTL = $D208 ;53768 (W) ; Audio control (no shadow) +ALLPOT = $D208 ;53768 (R) (no shadow) +STIMER = $D209 ;53769 (W) (no shadow) +KBCODE = $D209 ;53769 (R) (shadow @ CH) +SKREST = $D20A ;53770 (W) (latch) +RANDOM = $D20A ;53770 (R) (no shadow) +POTGO = $D20B ;53771 (W) (latch) +; $D20C (53772) is unused +SEROUT = $D20D ;53773 (W) (no shadow) +SERIN = $D20D ;53773 (R) (no shadow) +IRQEN = $D20E ;53774 (W) (shadow @ POKMSK) +IRQST = $D20E ;53774 (R) +SKCTL = $D20F ;53775 (W) (shadow @ SSKCTL) +SKSTAT = $D20F ;53775 (R) + +; $D210 - $D2FF are mirrors of POKEY address space. The "stereo POKEY" +; modification adds a second POKEY chip, usually addressed at $D210. + +; PIA +; No shadow regs for PIA regs +PIA = $D300 +PORTA = $D300 ;54016 +PORTB = $D301 ;54017 +PACTL = $D302 ;54018 +PBCTL = $D303 ;54019 + +; $D304 - $D3FF are mirrors of PIA address space + +; ANTIC +ANTIC = $D400 +DMACTL = $D400 ;54272 (W) (shadow @ SDMCTL) +CHACTL = $D401 ;54273 (W) (shadow @ CHACT) +DLISTL = $D402 ;54274 (W) (shadow @ SDLSTL) +DLISTH = $D403 ;54275 (W) (shadow @ SDLSTH) +HSCROL = $D404 ;54276 (W) (no shadow) +VSCROL = $D405 ;54277 (W) (no shadow) +; $D406 (54278) is unused +PMBASE = $D407 ;54279 (W) (no shadow) +; $D408 (54280) is unused +CHBASE = $D409 ;54281 (W) (shadow @ CHBAS) +WSYNC = $D40A ;54282 (W), latch (data written doesn't matter) +VCOUNT = $D40B ;54283 (R) (no shadow) +PENH = $D40C ;54284 (R) (shadow @ LPENH) +PENV = $D40D ;54285 (R) (shadow @ LPENV) +NMIEN = $D40E ;54286 (W) (no shadow) +NMIRES = $D40F ;54287 (W), latch? +NMIST = $D40F ;54287 (R) (no shadow) + +; $D410 - $D4FF are mirrors of ANTIC address space + +CCNTL = $D500 ;54528 Cartridge control (sometimes used for bankswitching) +; $D500 - $D5FF is supposed to be all be mapped to CCNTL + +; $D600 - $D7FF is unmapped? used by PBI on XL? seems to read all $FF + +; +; FLOATING POINT MATH ROUTINES +; +; From Mapping: +; These entry points are the same on 400/800 and XL OS, though the +; routines themselves are different (bugfixed/optimized for XL) +; Also, on the XL, the $D800 area is bankswitched to PBI device ROM, +; during PBI I/O. Not sure if all of $D800 - $DFFF is switched out +; or just part of it. +AFP = $D800 ;55296 ASCII to Floating Point (FP) conversion. +FASC = $D8E6 ;55526 FP value to ASCII conversion. +IFP = $D9AA ;55722 Integer to FP conversion +FPI = $D9D2 ;55762 FP to Integer conversion +ZFR0 = $DA44 ;55876 Clear FR0 (set all bytes to 0) +ZF1 = $DA46 ;55878 Clear FR1 (set all bytes to 0) (aka AF1 (De Re)) +FSUB = $DA60 ;55904 FP subtract: FR0 = FR0 - FR1 +FADD = $DA66 ;55910 FP add: FR0 = FR0 + FR1 +FMUL = $DADB ;56027 FP multiply: FR0 = FR0 * FR1 +FDIV = $DB28 ;56104 FP divide: FR0 = FR0 / FR1 +PLYEVL = $DD40 ;56640 FP polynomial evaluation +FLD0R = $DD89 ;56713 Load FP number into FR0 from 6502 X/Y registers +FLD0P = $DD8D ;56717 Load FP number into FR0 from FLPTR +FLD1R = $DD98 ;56728 Load FP number into FR1 from 6502 X/Y registers +FLD1P = $DD9C ;56732 Load FP number into FR1 from FLPTR +FST0R = $DDA7 ;56743 Store FP number into 6502 X/Y regs from FR0 +FST0P = $DDAB ;56747 Store FP number from FR0, using FLPTR +FMOVE = $DDB6 ;56758 Move FP number from FR0 into FR1 (FR1 = FR0) +EXP = $DDC0 ;56768 FP base e exponentiation +EXP10 = $DDCC ;56780 FP base 10 exponentiation +LOG = $DECD ;57037 FP natural logarithm +LOG10 = $DED1 ;57041 FP base 10 logarithm + +; +; +; OPERATING SYSTEM +; +; +; MODULE ORIGIN TABLE +; +CHORG = $E000 ;57344 CHARACTER SET, 1K +VECTBL = $E400 ;58368 VECTOR TABLE +VCTABL = $E480 ;58496 RAM VECTOR INITIAL VALUE TABLE +CIOORG = $E4A6 ;58534 CIO HANDLER +INTORG = $E6D5 ;59093 INTERRUPT HANDLER +SIOORG = $E944 ;59716 SIO DRIVER +DSKORT = $EDEA ;60906 DISK HANDLER +PRNORG = $EE78 ;61048 PRINTER HANDLER +CASORG = $EE78 ;61048 CASSETTE HANDLER +MONORG = $F0E3 ;61667 MONITOR/POWER UP MODULE +KBDORG = $F3E4 ;62436 KEYBOARD/DISPLAY HANDLER +; +; +; VECTOR TABLE, CONTAINS ADDRESSES OF CIO ROUTINES IN THE +; FOLLOWING ORDER. THE ADDRESSES IN THE TABLE ARE TRUE ADDRESSES-1 +; +; ADDRESS + 0 OPEN +; + 2 CLOSE +; + 4 GET +; + 6 PUT +; + 8 STATUS +; + A SPECIAL +; + C JMP TO INITIALIZATION +; + F NOT USED +; +; + +; 20070529 bkw: why are they address minus one? because they are called +; via RTS: a JSR actually pushes the return address minus one, and RTS +; increments the address on the stack after popping it. The Atari OS +; "pretends" to have done a JSR by pushing the address-1 on the stack, +; then executes RTS, which "returns" to the correct address. + +EDITRV = $E400 ;58368 EDITOR +SCRENV = $E410 ;58384 SCREEN +KEYBDV = $E420 ;58400 KEYBOARD +PRINTV = $E430 ;58416 PRINTER +CASETV = $E440 ;58432 CASSETTE +; +; ROM VECTORS +; +; 20070529 bkw: These consist of a JMP xxxx instruction in the ROM. +DSKINV = $E453 ;58451 +CIOV = $E456 ;58454 ; Main CIO entry point! +SIOV = $E459 ;58457 ; Main SIO entry point! +SETVBV = $E45C ;58460 +SYSVBV = $E45F ;58463 +VBIVAL = $E460 ;58464 ADR AT VVBLKI (operand of JMP @ $E45F) +XITVBV = $E462 ;58466 EXIT VBI +VBIXVL = $E463 ;58467 ADR AT VVBLKD (operand of JMP @ $E462) +SIOINV = $E465 ;58469 +SENDEV = $E468 ;58472 +INTINV = $E46B ;58475 +CIOINV = $E46E ;58478 +BLKBDV = $E471 ;58481 MEMO PAD MODE (self-test in XL) +WARMSV = $E474 ;58484 ; warmstart (RESET key jumps here) +COLDSV = $E477 ;58487 ; coldstart (reboot) the Atari +RBLOKV = $E47A ;58490 +CSOPIV = $E47D ;58493 + +; SYSEQU.ASM defines this: +CIO = CIOV + +; XL-only entry points: +XL_SELFSV = BLKBDV ; self-test (same entry point as 800 memo pad) +XL_SELFTST = BLKBDV ; alt. name (Mapping) +XL_PUPDIV = $E480 ;58496 (XL) Power-up ATARI logo (1200XL only), or self-test +XL_SLFTSV = $E483 ;58499 (XL) Self-test vector (points to $5000) +XL_PENTV = $E486 ;58502 (XL) Entry to the handler uploaded from peripheral + ; or disk (is this for the PBI?) +XL_PHUNLV = $E489 ;58505 (XL) Entry to uploaded handler unlink (PBI?) +XL_PHINIV = $E48C ;58508 (XL) Entry to uploaded handler init (PBI?) +XL_GPDVV = $E48F ;58511 (XL) General-purpose parallel device handler + ; (copy to HATABS to use) + +;;;;; Here endeth the list of official mnemonics + +; Mapping has this to say about the XL ROMs: +;Byte Use +;65518/FFEE Revision date D1 and D2 (four-bit BCD) +;65519/FFEF Revision date M1 and M2 +;65520/FFF0 Revision date Y1 and Y2 +;65521/FFF1 Option byte; should read 1 for the +; 1200XL (Mapping author's 800XL reads 2) +;65522-26/FFF2-6 Part number in the form AANNNNNN +;65527/FFF7 Revision number (again, mine reads 2) +;65528-9/FFF8-9 Checksum, bytes (LSB/MSB) +; There don't seem to be any known mnemonics for the above... + +; 20061120 bkw: display list stuff. These are not official Atari mnemonics, +; but they *are* somewhat based on the "Checkers Demo" by Carol Shaw, +; in the Atari Hardware Manual (she didn't define all these, and she didn't +; use the "DL_" prefix, probably because her assembler was limited to +; 6-character labels and/or didn't support the underscore). + +; blank lines, 1-8 scanlines high +DL_BLANK1 = $00 +DL_BLANK2 = $10 +DL_BLANK3 = $20 +DL_BLANK4 = $30 +DL_BLANK5 = $40 +DL_BLANK6 = $50 +DL_BLANK7 = $60 +DL_BLANK8 = $70 + +; modifier bits.. +DL_VSCROLL = $10 +DL_HSCROLL = $20 +DL_LMS = $40 +DL_DLI = $80 + +; graphics modes (these are the BASIC modes) +; If you're more familiar with the ANTIC modes, nobody's forcing you +; to use these :) +DL_GR0 = $02 +DL_GR1 = $06 +DL_GR2 = $07 +DL_GR3 = $08 +DL_GR4 = $09 +DL_GR5 = $0A +DL_GR6 = $0B +DL_GR7 = $0D +DL_GR8 = $0F +DL_GR12 = $04 ; GR. 12-15 only supported by GRAPHICS command on XL/XE, +DL_GR13 = $05 ; but they exist on all ANTIC revisions +DL_GR14 = $0C +DL_GR15 = $0E ; AKA "graphics 7.5" +; No GRAPHICS mode for ANTIC $03 (true descender) mode + +; jump instructions +DL_JMP = $01 ; jump without vertical blank (used to skip over 1K boundary) +DL_JVB = $41 ; jump & wait for VBLANK (end of display list) + +; How to use the above: here's a sample display list for GR.0, with a DLI +; on screen line 10. + +; dlist: +; ; 4*8 = 32 blank lines at start of display +; byte DL_BLANK8, DL_BLANK8, DL_BLANK8, DL_BLANK8 +; +; byte DL_GR0 | DL_LMS ; display GR.0 line, and load screen memory address.. +; word screen_ram ; ...from our screen memory (declared elsewhere) +; +; ; 8 more GR.0 lines +; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0 +; +; byte DL_GR0 | DL_DLI ; another GR.0 line, with the DLI bit enabled +; +; ; lines 11-24 (14 more GR.0 bytes) +; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0 +; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0 +; +; ; that's 24 lines, so finish with a VBLANK +; byte DL_JVB ; jump (and wait), to... +; word dlist ; ...the beginning. diff --git a/src/col64/font4x5.inc b/src/col64/font4x5.inc new file mode 100644 index 0000000..739e85e --- /dev/null +++ b/src/col64/font4x5.inc @@ -0,0 +1,48 @@ + byte $04, $04, $04, $00, $04 ; [0] 32,33 ,! + byte $AA, $AF, $0A, $0F, $0A ; [5] 34,35 ",# + byte $70, $A9, $62, $54, $E9 ; [10] 36,37 $,% + byte $42, $A2, $44, $A0, $D0 ; [15] 38,39 &,' + byte $24, $42, $42, $42, $24 ; [20] 40,41 (,) + byte $A4, $44, $EE, $44, $A4 ; [25] 42,43 *,+ + byte $00, $00, $0F, $20, $40 ; [30] 44,45 ,,- + byte $02, $02, $04, $08, $48 ; [35] 46,47 .,/ + byte $64, $9C, $B4, $D4, $6E ; [40] 48,49 0,1 + byte $6E, $91, $26, $41, $FE ; [45] 50,51 2,3 + byte $2F, $68, $AE, $F1, $2E ; [50] 52,53 4,5 + byte $7F, $81, $E2, $94, $64 ; [55] 54,55 6,7 + byte $66, $99, $67, $91, $6E ; [60] 56,57 8,9 + byte $00, $42, $00, $02, $44 ; [65] 58,59 :,; + byte $20, $4F, $80, $4F, $20 ; [70] 60,61 <,= + byte $87, $49, $22, $40, $82 ; [75] 62,63 >,? + byte $66, $B9, $BF, $89, $69 ; [80] 64,65 @,A + byte $E6, $99, $E8, $99, $E6 ; [85] 66,67 B,C + byte $EF, $98, $9E, $98, $EF ; [90] 68,69 D,E + byte $F7, $88, $EB, $89, $86 ; [95] 70,71 F,G + byte $9E, $94, $F4, $94, $9E ; [100] 72,73 H,I + byte $39, $1A, $1C, $9A, $69 ; [105] 74,75 J,K + byte $8A, $8F, $8D, $89, $F9 ; [110] 76,77 L,M + byte $96, $D9, $B9, $99, $96 ; [115] 78,79 N,O + byte $E6, $99, $E9, $8A, $85 ; [120] 80,81 P,Q + byte $E7, $98, $E6, $A1, $9E ; [125] 82,83 R,S + byte $F9, $49, $49, $49, $46 ; [130] 84,85 T,U + byte $99, $99, $9D, $AF, $4A ; [135] 86,87 V,W + byte $99, $99, $66, $92, $94 ; [140] 88,89 X,Y + byte $F6, $24, $44, $84, $F6 ; [145] 90,91 Z,[ + byte $86, $82, $42, $22, $26 ; [150] 92,93 \,] + byte $40, $A0, $00, $00, $0F ; [155] 94,95 ^,_ + byte $40, $43, $25, $09, $07 ; [160] 96,97 `,a + byte $80, $87, $E8, $98, $E7 ; [165] 98,99 b,c + byte $10, $16, $79, $9A, $77 ; [170] 100,101 d,e + byte $67, $49, $E7, $41, $46 ; [175] 102,103 f,g + byte $84, $80, $EC, $94, $9E ; [180] 104,105 h,i + byte $28, $0A, $6C, $2A, $C9 ; [185] 106,107 j,k + byte $C0, $4A, $4F, $4D, $E9 ; [190] 108,109 l,m + byte $00, $E6, $99, $99, $96 ; [195] 110,111 n,o + byte $00, $E7, $99, $E7, $81 ; [200] 112,113 p,q + byte $00, $A7, $DC, $83, $8E ; [205] 114,115 r,s + byte $40, $E9, $49, $49, $26 ; [210] 116,117 t,u + byte $00, $99, $9D, $AF, $4A ; [215] 118,119 v,w + byte $00, $99, $66, $62, $9C ; [220] 120,121 x,y + byte $06, $F4, $28, $44, $F6 ; [225] 122,123 z,{ + byte $4C, $44, $42, $44, $4C ; [230] 124,125 |,} + byte $0B, $59, $A0, $09, $0D ; [235] 126,127 ~, diff --git a/src/col64/test.atr b/src/col64/test.atr new file mode 100644 index 0000000..5e5cd5a Binary files /dev/null and b/src/col64/test.atr differ diff --git a/src/col80_modified/Makefile b/src/col80_modified/Makefile new file mode 100644 index 0000000..4f3a9c6 --- /dev/null +++ b/src/col80_modified/Makefile @@ -0,0 +1,15 @@ + +all: col80_hacked.xex + +col80_hacked.xex: col80_hacked.dasm + dasm col80_hacked.dasm -ocol80_hacked.xex -f3 + binload -h col80_hacked.xex + +clean: + rm -f col80_hacked.xex + +test: + cp dos_20s.atr test.atr + cp col80_hacked.xex autorun.sys + axe -w autorun.sys test.atr + atari800 -nobasic test.atr diff --git a/src/col80_modified/autorun.sys b/src/col80_modified/autorun.sys new file mode 100644 index 0000000..bb432dd Binary files /dev/null and b/src/col80_modified/autorun.sys differ diff --git a/src/col80_modified/col80_hacked.dasm b/src/col80_modified/col80_hacked.dasm new file mode 100644 index 0000000..ef6c5ac --- /dev/null +++ b/src/col80_modified/col80_hacked.dasm @@ -0,0 +1,906 @@ +; THIS IS A MODIFIED VERSION, for use with FujiChat + +; COL80.COM, aka COL80E.COM, aka COL80HND.COM +; (and probably several other names) + +; Original author unknown +; License unknown +; Disassembly and comments by Urchlay + +; This is a widely-distributed software 80-column driver for the Atari +; 8-bit computers. It replaces the OS's E: driver, and uses GRAPHICS 8 +; for display, with 4x8 pixel character cells. + +; Disassembly was done with da65, with many iterations of "edit the +; .info file, disassemble again", and the results were tweaked by hand +; into something assemblable by dasm (and fairly compatible with other +; assemblers). + + + .processor 6502 + +START_ADDRESS = $9C2D +;START_ADDRESS = $7C28 ; works with BASIC + +; xex segment header #1 + .org START_ADDRESS-6 + .word $FFFF + .word START_ADDRESS + .word END_ADDRESS + + .org START_ADDRESS + +; ---------------------------------------------------------------------------- +; Zero page labels (OS equates) + +DOSINI = $000C +ICAX1Z = $002A +ICAX2Z = $002B +TMPCHR = $0050 +LMARGN = $0052 +ROWCRS = $0054 +COLCRS = $0055 +DINDEX = $0057 +SAVMSC = $0058 +BUFCNT = $006B + +; ---------------------------------------------------------------------------- +; Zero page labels (COL80 equates) + +screen_ptr_lo = $00CB +screen_ptr_hi = $00CC +font_ptr_lo = $00CD +font_ptr_hi = $00CE + +; ---------------------------------------------------------------------------- +; Non-zeropage RAM labels (OS equates) + +COLOR1 = $02C5 +COLOR2 = $02C6 +RUNAD = $02E0 +INITAD = $02E2 +MEMTOP = $02E5 +SSFLAG = $02FF +HATABS = $031A +ICCOM = $0342 +ICBAL = $0344 +ICBAH = $0345 + +; ---------------------------------------------------------------------------- +; Hardware (memory-mapped I/O, OS equates) + +CONSOL = $D01F +AUDF1 = $D200 +AUDC1 = $D201 + +; ---------------------------------------------------------------------------- +; OS ROM labels + +s_dev_open_lo = $E410 ; (not named in OS sources) +s_dev_open_hi = $E411 ; "" +k_dev_get_lo = $E424 ; "" +k_dev_get_hi = $E425 ; "" +CIOV = $E456 ; Central Input/Output entry point + +; ---------------------------------------------------------------------------- +; Start of COL80. The font is stored in packed form. Each group of 8 bytes +; defines two glyphs: the upper 4 bits of the 8 bytes, taken together, +; define the bitmap for the first glyph, and the lower 4 bits are the second. +; Note that the bits that make up a single character are spread across 8 +; bytes, so it's hard to visualize these even if you're used to reading hex +; dumps. + +; The first 2 characters look like: + +; .... .O.. ; $04 +; .... .O.. ; $04 +; O.O. .O.. ; $A4 +; OOO. .O.. ; $E4 +; OOO. .OOO ; $E7 +; .O.. .O.. ; $44 +; .... .O.. ; $04 +; .... .O.. ; $04 + +; These are the ATASCII heart symbol (character code 0) and the ATASCII +; control-A line-drawing symbol (code 1). + +; Note: unlike the ROM font, this font is stored in ATASCII order instead +; of the standard Atari character order imposed by the hardware. Like +; the ROM font, inverse characters are not stored here (the bitmaps get +; inverted by the driver) + +font_data: + .include "new_font.s" + ;.include "icetmod.s" + +right_margin: + ; Default value is 79 decimal. Unsure why the author didn't use RMARGN at $53 + .byte $4F + +; ---------------------------------------------------------------------------- +; Start of COL80 code. + +; Callback for CIO OPEN command. + +col80_open: + jsr init_graphics_8 + lda #$00 + sta ROWCRS + sta COLCRS + sta BUFCNT + lda #$4F + sta right_margin + rts + +; ---------------------------------------------------------------------------- +; Assembly version of GRAPHICS 8+16 command. + +init_graphics_8: + lda #$08 + sta ICAX2Z + lda #$0C + sta ICAX1Z + jsr open_s_dev + + ; Set COL80's default colors + lda #$08 + sta COLOR2 + lda #$00 + sta COLOR1 + + ; Protect ourselves from BASIC and the OS + lda #START_ADDRESS + sta MEMTOP+1 + rts + +; ---------------------------------------------------------------------------- +; Call the OPEN vector for the S: device, using the ROM vector table +; at $E410. The table stores address-minus-one of each routine, which is +; meant to actually be called via the RTS instruction (standard 6502 +; technique, but confusing the first time you encounter it) + +open_s_dev: + lda s_dev_open_hi + pha + lda s_dev_open_lo + pha + rts + +; ---------------------------------------------------------------------------- +; Callback for CIO CLOSE command. Note that the routine does nothing, really +; (the OS will mark the E: device as being closed, but COL80 doesn't do any +; cleanup). +; The SPECIAL and GET STATUS callbacks in col80_vector_tab also point here. + +col80_close: + jmp return_success + +; ---------------------------------------------------------------------------- +; Callback for the internal put-one-byte, used by the OS to implement the +; CIO PUT RECORD and PUT BYTES commands. This routine's one argument is +; the byte in the accumulator (the character to print). + +; First, the routine checks for the cursor control characters it supports. +; COL80 only handles the EOL and clear-screen codes; trying to print +; backspaces, arrows, deletes, inserts, etc just causes their ATASCII +; graphics character to print instead. + +col80_putbyte: + ; EOL (decimal 155)? + cmp #$9B +;;; bne check_clear + bne regular_char + lda right_margin + sta COLCRS + jmp skip_write + +;;;check_clear: +;;; .ifndef FUJICHAT ; save memory by not including clear_screen +;;; ; (also, this lets us print the } character) +;;; ; Clear (decimal 125)? +;;; cmp #$7D +;;; bne regular_char +;;; jmp clear_screen +;;; .endif +;;; + ; See if this is an inverse video char (code >= 128) +regular_char: + tax + bpl not_inverse + lda #$FF + sta inverse_mask + bne skip_ninv + +not_inverse: + lda #$00 + sta inverse_mask + +skip_ninv: + txa + and #$7F + ;.ifdef FUJICHAT ; mask out low ASCII + sec + sbc #$20 + bcs not_low_ascii + jmp return_success +not_low_ascii: + ;.endif + sta TMPCHR + lda DINDEX + cmp #$08 + beq graphics_ok + ; If we're not in GRAPHICS 8 mode, reinitialize ourselves + jsr col80_open + +graphics_ok: + ; Call the routines that actually print the character + jsr setup_font_ptr + jsr setup_screen_ptr + jsr write_font_data + +skip_write: + ; Move the cursor 1 space to the right. This will + ; advance us to the next line if we're at the margin, + ; and scroll the screen if needed + jsr advance_cursor + +check_ssflag: + ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla + ; any time the user presses ctrl-1 + ;lda SSFLAG + ;bne check_ssflag + jmp return_success + +; ---------------------------------------------------------------------------- +; Scroll the screen up one line (8 scanlines). This has to move almost 8K of +; data, so it's noticeably slower than scrolling the GR.0 text screen. + +scroll_screen: + lda SAVMSC + sta screen_ptr_lo + clc + adc #$40 + ; font_ptr_lo is actually being used here as a second pointer into + ; screen RAM, instead of its usual use as a pointer into the + ; font_data table + sta font_ptr_lo + lda SAVMSC+1 + sta screen_ptr_hi + adc #$01 + sta font_ptr_hi + ldx #$1D + ldy #$00 + +scroll_line_loop: + lda (font_ptr_lo),y + sta (screen_ptr_lo),y + dey + bne scroll_line_loop + inc font_ptr_hi + inc screen_ptr_hi + dex + bne scroll_line_loop + +blank_bottom_row: + lda SAVMSC + clc + adc #$C0 + sta screen_ptr_lo + lda SAVMSC+1 + adc #$1C + sta screen_ptr_hi + lda #$00 + tay + +blank_loop: + sta (screen_ptr_lo),y + dey + bne blank_loop + inc screen_ptr_hi + ldy #$40 + +blank_tail: + sta (screen_ptr_lo),y + dey + bpl blank_tail + rts + +; ---------------------------------------------------------------------------- +; Set up font_ptr_lo/hi to point to the font_data bitmap for the character in +; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the +; bitmap is in the upper or lower 4 bits of the bytes pointed to. + +setup_font_ptr: + lda #$00 + sta font_ptr_hi + sta lo_nybble_flag + lda TMPCHR + clc + ror + bcc font_hi_nybble + ldx #$FF + stx lo_nybble_flag + +font_hi_nybble: + clc + rol + rol + rol font_ptr_hi + rol + rol font_ptr_hi + adc #font_data + adc font_ptr_hi + sta font_ptr_hi + rts + +; ---------------------------------------------------------------------------- +; Move the cursor one space to the right (to the next line if at the margin, +; and scroll screen if on the last row) + +advance_cursor: + inc COLCRS + lda right_margin + cmp COLCRS + bcs same_line + lda LMARGN + sta COLCRS + lda ROWCRS + ; $17 is 25 decimal, one row below the lowest on the screen + cmp #$17 + bcc no_scroll + jsr scroll_screen + ; Move to row 24 after scrolling + lda #$16 + sta ROWCRS + +no_scroll: + inc ROWCRS + +same_line: + rts + +; ---------------------------------------------------------------------------- +; Clear the screen by setting all screen RAM bytes to zero. Slow, but not +; as slow as scrolling. + +;;; .ifndef FUJICHAT +;;;clear_screen: +;;; lda SAVMSC +;;; sta screen_ptr_lo +;;; lda SAVMSC+1 +;;; sta screen_ptr_hi +;;; ldy #$00 +;;; ldx #$1D +;;; lda #$00 +;;; +;;;cls_loop: +;;; sta (screen_ptr_lo),y +;;; dey +;;; bne cls_loop +;;; inc screen_ptr_hi +;;; dex +;;; bne cls_loop +;;; jsr blank_bottom_row +;;; lda LMARGN +;;; sta COLCRS +;;; lda #$00 +;;; sta ROWCRS +;;; ; redundant JMP +;;; jmp return_success +;;; .endif + +; ---------------------------------------------------------------------------- +; CIO expects the Y register to contain a status code. +; 1 means success (no error). Lots of COL80's routines +; jump here. + +return_success: + ldy #$01 + rts + +; ---------------------------------------------------------------------------- +; Set screen_ptr_lo/hi to point to the address of the first byte of graphics +; data at the current cursor position. + +setup_screen_ptr: + ldy ROWCRS + lda SAVMSC + clc + adc row_low_offset_tab,y + sta screen_ptr_lo + lda SAVMSC+1 + adc row_high_offset_tab,y + sta screen_ptr_hi + lda COLCRS + lsr + clc + adc screen_ptr_lo + bcc hi_byte_ok + inc screen_ptr_hi + +hi_byte_ok: + sta screen_ptr_lo + rts + +; ---------------------------------------------------------------------------- +; Tables of offsets for setup_screen_ptr, to avoid doing multiplication at +; runtime (the 6502 lacks a MUL instruction, so it's slow...) + +row_low_offset_tab: + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 + +row_high_offset_tab: + .byte $00,$01,$02,$03,$05,$06,$07,$08 + .byte $0A,$0B,$0C,$0D,$0F,$10,$11,$12 + .byte $14,$15,$16,$17,$19,$1A,$1B,$1C + +; ---------------------------------------------------------------------------- +; Copy pixel data from the font table to screen RAM. +; font_ptr_lo/hi must point to the correct character, and screen_ptr_lo/hi +; must point to the correct screen address for the current cursor position. +; This routine has separate execution paths for even- and odd-numbered +; cursor positions, since each byte of screen RAM holds data for two +; adjacent characters (and when printing to one of them, the other needs +; to be left undisturbed!) + +write_font_data: + lda COLCRS + clc + ror + bcc write_font_data_even + ldx #$00 + ldy #$00 + +get_font_nybble_odd: + lda (font_ptr_lo),y + bit lo_nybble_flag + bne lo_nybble_odd + ; glyph we want is stored in top 4 bits of font byte, + ; shift it down to the bottom 4 bits + lsr + lsr + lsr + lsr + +lo_nybble_odd: + eor inverse_mask + and #$0F + sta TMPCHR + ldy scanline_offset_tab,x + lda (screen_ptr_lo),y + and #$F0 + ora TMPCHR + sta (screen_ptr_lo),y + inx + cpx #$07 + bne screen_ptr_ok_odd + inc screen_ptr_hi + +screen_ptr_ok_odd: + cpx #$08 + beq write_font_done_odd + txa + tay + bne get_font_nybble_odd + +write_font_done_odd: + rts + +; ---------------------------------------------------------------------------- +; Write data to even-numbered columns, very similar to the above + +write_font_data_even: + ldx #$00 + ldy #$00 + +get_font_nybble_even: + lda (font_ptr_lo),y + bit lo_nybble_flag + beq hi_nybble_even + asl + asl + asl + asl + +hi_nybble_even: + eor inverse_mask + and #$F0 + sta TMPCHR + ldy scanline_offset_tab,x + lda (screen_ptr_lo),y + and #$0F + ora TMPCHR + sta (screen_ptr_lo),y + inx + cpx #$07 + bne screen_ptr_ok_even + inc screen_ptr_hi + +screen_ptr_ok_even: + cpx #$08 + beq write_font_done_even + txa + tay + bne get_font_nybble_even + +write_font_done_even: + rts + +; ---------------------------------------------------------------------------- + +scanline_offset_tab: + .byte $00,$28,$50,$78,$A0,$C8,$F0,$18 + +; ---------------------------------------------------------------------------- +; Callback for the internal get-one-byte, used by the OS to implement the +; CIO GET RECORD and GET BYTES commands. This routine takes no arguments, +; and returns the read byte in the accumulator. + +; Internally, COL80 maintains a line buffer. Each time col80_getbyte is +; called, it returns the next character in the buffer. If the buffer's +; empty (or if the last call returned the last character), a new line +; of input is read from the user (and the first character is returned). +; This is exactly how the OS E: device works. + +col80_getbyte: + lda BUFCNT + beq get_line + +get_next_byte: + ldx line_buffer_index + lda line_buffer,x + dec BUFCNT + inc line_buffer_index + jmp return_success + +; ---------------------------------------------------------------------------- +; Get a line of input from the user, terminated by the Return key. + +get_line: + lda #$00 + sta BUFCNT + sta line_buffer_index + +show_cursor: +; .ifdef FUJICHAT + lda #$00 +; .else +; lda #$20 +; .endif + sta TMPCHR + lda #$FF + sta inverse_mask + jsr setup_font_ptr + jsr setup_screen_ptr + jsr write_font_data + jsr get_keystroke + cpy #$01 + beq keystroke_ok +; .ifdef FUJICHAT + dey ; yes, we really care about 1-byte optimizations +; .else +; ldy #$00 +; .endif + sty line_buffer_index + sty BUFCNT + +keystroke_ok: +; .ifdef FUJICHAT + cmp #$20 + bcc show_cursor ; ignore low ASCII +; .endif + cmp #$9B + bne check_backs_key + jmp return_key_hit + +check_backs_key: + cmp #$7E + bne check_clear_key + jmp backs_key_hit + +check_clear_key: + cmp #$7D + bne normal_key_hit + jmp clear_key_hit + +normal_key_hit: + ldx BUFCNT + bpl buffer_character +; .ifdef FUJICHAT + jmp show_cursor +; .else +; jmp beep +; .endif + +buffer_character: + sta line_buffer,x + jsr col80_putbyte + inc BUFCNT + jmp show_cursor + +return_key_hit: + jsr print_space + lda #$9B + ldx BUFCNT + sta line_buffer,x + inc BUFCNT + jsr col80_putbyte + jmp get_next_byte + +clear_key_hit: +; .ifndef FUJICHAT +; jsr clear_screen +; .endif + lda #$00 + sta line_buffer_index + sta BUFCNT + jmp get_line + +backs_key_hit: + jsr print_space + lda BUFCNT + beq backs_key_done + dec COLCRS + lda COLCRS + clc + adc #$01 + cmp LMARGN + bne backs_same_line + lda right_margin + sta COLCRS + dec ROWCRS + +backs_same_line: + dec BUFCNT + +backs_key_done: + jmp show_cursor + +; ---------------------------------------------------------------------------- +; Ring the margin bell. COL80 doesn't implement the ctrl-2 bell (character +; 253), and instead of using the GTIA keyclick speaker, it uses POKEY to +; make a beep + +;;; .ifndef FUJICHAT +;;;beep: ldy #$00 +;;; ldx #$AF +;;; +;;;beep_delay_x: +;;; stx AUDF1 +;;; stx AUDC1 +;;; +;;;beep_delay_y: +;;; dey +;;; bne beep_delay_y +;;; dex +;;; cpx #$9F +;;; bne beep_delay_x +;;; jmp show_cursor +;;; .endif + +; ---------------------------------------------------------------------------- +; Print a space character at the current cursor position. Does not +; update the cursor position. +print_space: + lda #$00 + sta inverse_mask +;;; .ifndef FUJICHAT +;;; lda #$20 +;;; .endif + sta TMPCHR + jsr setup_font_ptr + jsr setup_screen_ptr + jsr write_font_data + rts + +; ---------------------------------------------------------------------------- +; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine +; (call by pushing address-minus-one then doing an RTS) +get_keystroke: + lda k_dev_get_hi + pha + lda k_dev_get_lo + pha + rts + +; ---------------------------------------------------------------------------- +; COL80 vector table, in the format required by the OS. Our HATABS entry +; will point to this table, and the OS will call the routines listed here +; via the "call by RTS" method (which is why they're address-minus-one). + +; See the entry on HATABS in "Mapping the Atari" or the OS manual. + +col80_vector_tab: + .word col80_open-1 + .word col80_close-1 + .word col80_getbyte-1 + .word col80_putbyte-1 + .word col80_close-1 + .word col80_close-1 + jmp col80_init + +END_ADDRESS = *-1 + +START_ADDRESS_2 = $03FD + +; xex segment header #2 + .word START_ADDRESS_2 + .word END_ADDRESS_2 + + .rorg START_ADDRESS_2 + +; ---------------------------------------------------------------------------- +; Various bits of runtime state here. It's unclear to me why the standard +; OS buffer location couldn't have been used instead (normally the top +; half of page 5), or why the other stuff couldn't have been stored in +; zero page, in locations used by the ROM E: handler (thus unused when +; it's replaced with COL80). line_buffer_index needs to be preserved +; across calls to col80_getbyte, but lo_nybble_flag and inverse_mask are +; freshly calculated every time they're used, so they could be almost +; anywhere. + +lo_nybble_flag: + .byte $00 + +inverse_mask: + .byte $00 + +line_buffer_index: + .byte $12 + + +; ---------------------------------------------------------------------------- +; Initialization callback. The OS will call this on coldstart (or would do, +; if the driver were in ROM), and also on warmstart (because we stole the +; DOSINI vector). +; This routine is also the first thing that gets called by the mainline +; init code. Its job is to install COL80 in the handler table at HATABS. +; Actually the handler is first installed as X:, then the main init code +; fixes this up to E: unless the user is holding down SELECT. This allows +; the user to toggle between the 40-column ROM E: and COL80 without doing +; a full reboot. No idea if this was a documented feature or something the +; author used for development/debugging. + +; .ifdef FUJICHAT +;col80_init = return_success +; .else +col80_init: + ldy #$00 + +next_hatab_slot: + lda HATABS,y + beq register_x_handler + iny + iny + iny + cpy #$20 + bcc next_hatab_slot + jmp return_success + +register_x_handler: + lda #$58 + sta HATABS,y + lda #col80_vector_tab + iny + sta HATABS,y + jmp return_success +; .endif + +; ---------------------------------------------------------------------------- +; The OS jumps here on warmstart (also, this is the run address in our +; binary load file) + +dosini_entry_point: +;;; .ifndef FUJICHAT +;;; nop +;;; nop +;;; nop +;;; .endif + +main_entry_point: +;;; .ifndef FUJICHAT + jsr col80_init +;;; lda CONSOL +;;; and #$04 +;;; beq no_e_handler +;;; .endif + lda #$0C + sta ICCOM + ldx #$00 + jsr CIOV +; .ifndef FUJICHAT ; note: will not work with BASIC! DOS/etc OK + lda #$58 + sta font_ptr_lo + lda #$03 + sta ICCOM + lda #font_ptr_lo + sta ICBAL + lda #$00 + sta ICBAH + ldx #$00 + jsr CIOV +; .endif + ldy #$07 + lda #col80_vector_tab + iny + sta HATABS,y +no_e_handler: + lda #START_ADDRESS + sta MEMTOP+1 + jmp return_success + +END_ADDRESS_2 = *-1 + +; xex segment header #3 + ;.word RUNAD + ;.word RUNAD+1 + .word INITAD + .word INITAD+1 + .word main_entry_point + +; ---------------------------------------------------------------------------- +; (when does this actually get called? da65 can't find any references +; to it, and it's not a run or init address in the binary load file) +;;; .ifndef FUJICHAT +;;; lda #dosini_entry_point +;;; sta DOSINI+1 +;;; jmp main_entry_point +;;; .endif + +; ---------------------------------------------------------------------------- +; There's absolutely no reason why this data needs to be included in the +; binary load file: the line buffer's initial contents are meaningless, they +; will be blown away the first time anything reads from the E: device. + +; Notice the author was running his debugger in COL80 when he built the +; binary (ASCII "S COL80 7A00 7F80" command still in the buffer). + + ;.ifdef FUJICHAT + +line_buffer = $0400 ; cassette buffer + + ;.else +;line_buffer: + ;.byte $53,$20,$43,$4F,$4C,$38,$30,$20 + ;.byte $37,$41,$30,$30,$20,$37,$46,$38 + ;.byte $30,$9B,$20,$20,$20,$20,$9B,$27 + ;.byte $40,$40,$40,$40,$28,$28,$28,$28 + ;.byte $40,$40,$40,$40,$40,$40,$40,$40 + ;.byte $40,$40,$40,$40,$40,$40,$40,$40 + ;.byte $9B,$FD,$FD,$FD,$FD,$9B + ;.endif + + +; I've found a variant (modified version?) of this code, that doesn't +; include the line_buffer in the file (no reason for it to be there), +; or the $0C segment, and that has another segment, loaded at $6000, +; with the run address changed to $6000. The code looks like: + +; .org $6000 +; jsr dosini_entry_point +; lda #$50 +; sta RMARGN +; lda #$00 +; sta COLOR2 + +; also, the default colors have been changed in init_graphics_8. + +; There are at least two binaries floating around that contain +; extra (garbage) bytes at the end, presumably from being transferred +; over XMODEM or similar. They are otherwise identical. + diff --git a/src/col80_modified/col80_hacked.xex b/src/col80_modified/col80_hacked.xex new file mode 100644 index 0000000..73ac7e3 Binary files /dev/null and b/src/col80_modified/col80_hacked.xex differ diff --git a/src/col80_modified/cruft/Makefile b/src/col80_modified/cruft/Makefile new file mode 100644 index 0000000..2152ced --- /dev/null +++ b/src/col80_modified/cruft/Makefile @@ -0,0 +1,45 @@ + +SRCFILES=col80_dosini_seg.s col80_header_seg.s col80_main.s \ + col80_runad_seg.s col80_startaddr.s + +all: cc65_hack + binload -h col80.xex + +cc65_hack: $(SRCFILES) col80.s + ca65 -t atari -DFUJICHAT col80.s + ld65 -C col80_cc65_hack.cfg -o col80_main.xex col80.o + ca65 -t atari -DFUJICHAT col80_startup.s + ld65 -o col80_startup.xex col80_startup.o + cat col80_main.xex col80_startup.xex > col80.xex + + +col80.xex: + $(MAKE) dasm_build || $(MAKE) ca65_build || $(MAKE) atasm_build + +dasm_build: $(SRCFILES) col80.dasm + dasm col80.dasm -f3 -ocol80.xex + +ca65_build: $(SRCFILES) col80.s + ca65 -t atari col80.s + ld65 -t atari -o col80.xex col80.o + +atasm_build: $(SRCFILES) col80.atasm + perl dasm2atasm col80_header_seg.s col80_header_seg.atasm + perl dasm2atasm col80_main.s col80_main.atasm + atasm -r -ocol80.xex col80.atasm + +check: col80.xex + @if cmp col80.xex col80_orig.xex; then \ + echo "OK: New binary is identical to original" ;\ + else \ + echo "BAD: New binary differs from original" ;\ + fi + +clean: + rm -f *.o col80_header_seg.atasm col80_main.atasm col80.xex + +test: + cp dos_20s.atr test.atr + cp col80.xex autorun.sys + axe -w autorun.sys test.atr + atari800 -nobasic test.atr diff --git a/src/col80_modified/cruft/README.txt b/src/col80_modified/cruft/README.txt new file mode 100644 index 0000000..720a1cc --- /dev/null +++ b/src/col80_modified/cruft/README.txt @@ -0,0 +1,89 @@ + +COL80 is a software 80-column driver for the Atari 8-bit computer. It +uses GRAPHICS 8 with 4x8 pixel character cells, and replaces the OS +ROM's E: handler. + +The file is found in various Atari archives, under various names such +as COL80.COM, COL80E.COM, COL80HND.COM. The original author and date of +publication are unknown. + +I've disassembled the binary and labelled/commented the source with +(hopefully) meaningful names. The resulting sources can be reassembled +with the DASM, ca65, or Atasm assemblers, which will result in a binary +that compares as identical to the original. + +If you have one of the supported assemblers available on your path, +plus a "make" utility (GNU, BSD, or probably Microsoft's nmake are OK), +you can use the provided Makefile to rebuild the binary (including your +own modified version, if you're into that sort of thing). + +File list: + +README.txt - you're reading it now + +Makefile - the usual + +col80_main.s - The actual source code for COL80 + +col80_dosini_seg.s, col80_header_seg.s, col80_runad_seg.s, and +col80_startaddr.s - Include files, used to build the multi-segment Atari +binary load format object file. + +col80.s, col80.dasm, col80.atasm - Top-level wrappers for the various +assemblers, which include the other files in the proper order and using +the proper syntax for the assembler being used. + +Modification Ideas: + +Implement the missing control character actions. COL80 only does EOL and +the clear-screen code (125), and the others (arrows, delete/insert/bell) +are just printed in their graphical form. + +The original COL80 loads the driver code at $7A00, so it'll be compatible +with BASIC, or other cartridge software. I've built a version org'ed at +$9A00, which works great with disk-only software and gives an extra 8K +of available RAM (change START_ADDR in col80_startaddr.s). + +It should be possible to use 4x7 or 4x6 character cells instead of +4x8. The font would of course need to be redesigned, and the characters +would be even smaller than they are now, but this would give you 27 or +32 rows of text on screen (or more, if you expand the display by a few +scanlines). With a good green or amber monitor and luma-only output, +this could be usable. + +Instead of inverse video for characters 128-255, could do an expanded +international character set (ISO Latin-1). Add a UTF-8 parser and you've +got Unicode on the Atari! + +Add a VT100/ANSI escape-sequence parser. Could render actual underlined +characters, and bold as inverse video. ANSI color codes we can't easily +do, but could at least strip them out. + +Squeeze the driver down to save RAM. Use the standard E: buffer in page 5, +move the code up so it ends just before the GR.8 display list, eliminate +the code that installs the handler as X: and checks for the SELECT key +being held down... get rid of the margin beep. Use RMARGN in zero page +instead of right_margin at $7C00, move the other COL80 variables to +page zero. Eliminate the lookup tables, if they can be replaced with +code that takes up less space and calculates the values on the fly. +The current driver code is 3 pages long; it might be possible to squish +it into 2 pages... like, say, page 6 and the cassette buffer, or make it +auto-relocate itself to MEMLO like Bob-Verter does. Using a 4x6 or 4x7 +font shrinks the font table, too... another thing to do would be to get +rid of the clear_screen routine (replace with a call to init_graphics_8) + +For XL/XE machines, turn COL80 into an OS patch. For modified 400/800 +machines with RAM at $C000-CFFF, move COL80 there. For 130XEs, use an +extended RAM bank for the driver, and another bank for the screen RAM +(separate ANTIC/CPU access mode, won't work on most upgraded 800XLs). Just +keep a tiny stub driver in main RAM, that switches in the driver's bank +and jumps to it. + +Make a COL64 driver (like the SpartaDOS X CON64.SYS). Use 5x8 characters +for 64 columns (or 5x6 for 64x32). Probably this would count more as +a rewrite than a modification. The font would have to be stored one +character per 8 bytes (take up twice as much space), and lots of shifting +would have to happen when writing to the screen (slow)... Could also +do 56 columns (7 pixel wide), and actually use the ROM font (just cut +off the high bit, and for 56x27 also cut off the bottom scanline). + diff --git a/src/col80_modified/cruft/autorun.sys b/src/col80_modified/cruft/autorun.sys new file mode 100644 index 0000000..e62d76d Binary files /dev/null and b/src/col80_modified/cruft/autorun.sys differ diff --git a/src/col80_modified/cruft/col80.atasm b/src/col80_modified/cruft/col80.atasm new file mode 100644 index 0000000..3fdd27a --- /dev/null +++ b/src/col80_modified/cruft/col80.atasm @@ -0,0 +1,6 @@ + + .include "col80_startaddr.s" + .include "col80_header_seg.atasm" + .include "col80_main.atasm" + .include "col80_dosini_seg.s" + .include "col80_runad_seg.s" diff --git a/src/col80_modified/cruft/col80.dasm b/src/col80_modified/cruft/col80.dasm new file mode 100644 index 0000000..b3a1de2 --- /dev/null +++ b/src/col80_modified/cruft/col80.dasm @@ -0,0 +1,10 @@ + + processor 6502 ; dasm + + .include col80_startaddr.s + .include col80_header_seg.s + .include col80_main.s + .include col80_dosini_seg.s + + .include col80_runad_seg.s + diff --git a/src/col80_modified/cruft/col80.info b/src/col80_modified/cruft/col80.info new file mode 100644 index 0000000..ad821a4 --- /dev/null +++ b/src/col80_modified/cruft/col80.info @@ -0,0 +1,152 @@ +global { + comments 4; + inputname "col80e.raw"; + outputname "col80e.dasm"; + startaddr $7A00; +}; + +range { + start $7A00; + end $7BFF; + type bytetable; +}; + +range { + start $7F48; + end $7F80; + type bytetable; +}; + +range { + start $7D52; + end $7D81; + type bytetable; +}; + +range { + start $7DEA; + end $7DF0; + type bytetable; +}; + +range { + start $7EE5; + end $7EF0; + type addrtable; +}; + +LABEL { NAME "s_dev_open_lo"; ADDR $E410; }; +LABEL { NAME "s_dev_open_hi"; ADDR $E411; }; + +LABEL { NAME "k_dev_get_lo"; ADDR $E424; }; +LABEL { NAME "k_dev_get_hi"; ADDR $E425; }; + +LABEL { NAME "DOSINI"; ADDR $0C; }; +LABEL { NAME "DOSINI+1"; ADDR $0D; }; +LABEL { NAME "TMPCHR"; ADDR $50; }; +LABEL { NAME "LMARGN"; ADDR $52; }; +LABEL { NAME "DINDEX"; ADDR $57; }; +LABEL { NAME "SAVMSC"; ADDR $58; }; +LABEL { NAME "SAVMSC+1"; ADDR $59; }; +LABEL { NAME "ICAX1Z"; ADDR $2A; }; +LABEL { NAME "ICAX2Z"; ADDR $2B; }; +LABEL { NAME "ROWCRS"; ADDR $54; }; +LABEL { NAME "COLCRS"; ADDR $55; }; +LABEL { NAME "BUFCNT"; ADDR $6B; }; +LABEL { NAME "SSFLAG"; ADDR $02FF; }; +LABEL { NAME "HATABS"; ADDR $031A; }; +LABEL { NAME "CIOV"; ADDR $E456; }; +LABEL { NAME "CONSOL"; ADDR $D01F; }; +LABEL { NAME "AUDF1"; ADDR $D200; }; +LABEL { NAME "AUDC1"; ADDR $D201; }; +LABEL { NAME "ICCOM"; ADDR $0342; }; +LABEL { NAME "ICBAL"; ADDR $0344; }; +LABEL { NAME "ICBAH"; ADDR $0345; }; +LABEL { NAME "COLOR1"; ADDR $02C5; }; +LABEL { NAME "COLOR2"; ADDR $02C6; }; +LABEL { NAME "MEMTOP"; ADDR $02E5; }; +LABEL { NAME "MEMTOP+1"; ADDR $02E6; }; + +LABEL { NAME "col80e_vector_tab"; ADDR $7EE5; }; +LABEL { NAME "col80e_open-1"; ADDR $7C00; }; +LABEL { NAME "col80e_open"; ADDR $7C01; }; +LABEL { NAME "col80e_close-1"; ADDR $7C3F; }; +LABEL { NAME "col80e_close"; ADDR $7C40; }; +LABEL { NAME "col80e_getbyte-1"; ADDR $7DF1; }; +LABEL { NAME "col80e_getbyte"; ADDR $7DF2; }; +LABEL { NAME "col80e_putbyte-1"; ADDR $7C42; }; +LABEL { NAME "col80e_putbyte"; ADDR $7C43; }; +LABEL { NAME "col80e_init"; ADDR $7EC0; }; + +LABEL { NAME "screen_ptr_lo"; ADDR $CB; }; +LABEL { NAME "screen_ptr_hi"; ADDR $CC; }; +LABEL { NAME "font_ptr_lo"; ADDR $CD; }; +LABEL { NAME "font_ptr_hi"; ADDR $CE; }; + +LABEL { NAME "font_data"; ADDR $7A00; }; +LABEL { NAME "lo_nybble_flag"; ADDR $7F48; }; + +LABEL { NAME "clear_screen"; ADDR $7D0B; }; +LABEL { NAME "regular_char"; ADDR $7C56; }; +LABEL { NAME "check_ssflag"; ADDR $7C7F; }; +LABEL { NAME "dosini_entry_point"; ADDR $7EF4; }; +LABEL { NAME "main_entry_point"; ADDR $7EF7; }; +LABEL { NAME "get_keystroke"; ADDR $7EB7; }; +LABEL { NAME "return_success"; ADDR $7D31; }; +LABEL { NAME "inverse_mask"; ADDR $7F49; }; +LABEL { NAME "not_inverse"; ADDR $7C60; }; +LABEL { NAME "open_s_dev"; ADDR $7C37; }; +LABEL { NAME "init_graphics_8"; ADDR $7C14; }; +LABEL { NAME "not_eol"; ADDR $7C4F; }; +LABEL { NAME "graphics_ok"; ADDR $7C73; }; +LABEL { NAME "setup_screen_ptr"; ADDR $7D34; }; +LABEL { NAME "setup_font_ptr"; ADDR $7CC9; }; +LABEL { NAME "hi_byte_ok"; ADDR $7D4F; }; +LABEL { NAME "row_low_offset_tab"; ADDR $7D52; }; +LABEL { NAME "row_high_offset_tab"; ADDR $7D6A; }; +LABEL { NAME "cls_loop"; ADDR $7D19; }; +LABEL { NAME "write_font_data_odd"; ADDR $7D82; }; +LABEL { NAME "write_font_data_even"; ADDR $7DB9; }; +LABEL { NAME "scroll_screen"; ADDR $7C87; }; +LABEL { NAME "advance_cursor"; ADDR $7CEE; }; +LABEL { NAME "skip_write"; ADDR $7C7C; }; +LABEL { NAME "skip_ninv"; ADDR $7C65; }; +LABEL { NAME "lo_nybble_odd"; ADDR $7D97; }; +LABEL { NAME "hi_nybble_even"; ADDR $7DC8; }; +LABEL { NAME "write_font_done_odd"; ADDR $7DB8; }; +LABEL { NAME "get_font_nybble_odd"; ADDR $7D8C; }; +LABEL { NAME "get_font_nybble_even"; ADDR $7DBD; }; +LABEL { NAME "screen_ptr_ok_odd"; ADDR $7DB0; }; +LABEL { NAME "screen_ptr_ok_even"; ADDR $7DE1; }; +LABEL { NAME "write_font_done_even"; ADDR $7DE9; }; +LABEL { NAME "scanline_offset_tab"; ADDR $7DEA; }; +LABEL { NAME "get_line"; ADDR $7E04; }; +LABEL { NAME "line_buffer_index"; ADDR $7F4A; }; +LABEL { NAME "line_buffer"; ADDR $7F4B; }; +LABEL { NAME "get_next_byte"; ADDR $7DF6; }; +LABEL { NAME "show_cursor"; ADDR $7E0B; }; +LABEL { NAME "keystroke_ok"; ADDR $7E2B; }; +LABEL { NAME "return_key_hit"; ADDR $7E52; }; +LABEL { NAME "check_backs_key"; ADDR $7E32; }; +LABEL { NAME "backs_key_hit"; ADDR $7E71; }; +LABEL { NAME "check_clear_key"; ADDR $7E39; }; +LABEL { NAME "clear_key_hit"; ADDR $7E64; }; +LABEL { NAME "normal_key_hit"; ADDR $7E40; }; +LABEL { NAME "beep"; ADDR $7E8F; }; +LABEL { NAME "beep_delay_x"; ADDR $7E93; }; +LABEL { NAME "beep_delay_y"; ADDR $7E99; }; +LABEL { NAME "buffer_character"; ADDR $7E47; }; +LABEL { NAME "print_space"; ADDR $7EA4; }; +LABEL { NAME "backs_key_done"; ADDR $7E8C; }; +LABEL { NAME "same_line"; ADDR $7E8A; }; +LABEL { NAME "next_hatab_slot"; ADDR $7EC2; }; +LABEL { NAME "register_x_handler"; ADDR $7ED1; }; +LABEL { NAME "no_e_handler"; ADDR $7F30; }; +LABEL { NAME "no_scroll"; ADDR $7D08; }; +LABEL { NAME "next_line"; ADDR $7D0A; }; +LABEL { NAME "font_hi_nybble"; ADDR $7CDB; }; +LABEL { NAME "scroll_line_loop"; ADDR $7C9C; }; +LABEL { NAME "blank_bottom_row"; ADDR $7CAA; }; +LABEL { NAME "blank_loop"; ADDR $7CBA; }; +LABEL { NAME "blank_tail"; ADDR $7CC3; }; + diff --git a/src/col80_modified/cruft/col80.s b/src/col80_modified/cruft/col80.s new file mode 100644 index 0000000..334082a --- /dev/null +++ b/src/col80_modified/cruft/col80.s @@ -0,0 +1,21 @@ + +; ca65 wrapper for building col80 + + .setcpu "6502" + + .segment "EXEHDR" + .include "col80_startaddr.s" + .include "col80_header_seg.s" + + .segment "CODE" + .include "col80_main.s" + + .ifndef FUJICHAT + .include "col80_dosini_seg.s" + + .segment "AUTOSTRT" + .include "col80_runad_seg.s" + .endif + + .segment "ZPSAVE" + ; nothing to see here, just shutting up ld65's warning diff --git a/src/col80_modified/cruft/col80.xex b/src/col80_modified/cruft/col80.xex new file mode 100644 index 0000000..5872c7f Binary files /dev/null and b/src/col80_modified/cruft/col80.xex differ diff --git a/src/col80_modified/cruft/col80_cc65_hack.cfg b/src/col80_modified/cruft/col80_cc65_hack.cfg new file mode 100644 index 0000000..82b2c25 --- /dev/null +++ b/src/col80_modified/cruft/col80_cc65_hack.cfg @@ -0,0 +1,41 @@ +FEATURES { + STARTADDRESS: default = $2E00; +} +SYMBOLS { + __STACKSIZE__ = $800; # 2K stack + __RESERVED_MEMORY__: value = $0, weak = yes; +} +MEMORY { + ZP: start = $0082, size = $007E, type = rw, define = yes; + HEADER: start = $0000, size = $0006, file = %O; + RAM: start = %S, size = $BC20 - __STACKSIZE__ - %S, file = %O; + TRAILER: start = $0000, size = $0006, file = %O; +} +SEGMENTS { + EXEHDR: load = HEADER, type = ro; + LOWCODE: load = RAM, type = ro, define = yes, optional = yes; + INIT: load = RAM, type = ro, optional = yes; + CODE: load = RAM, type = ro, define = yes; + RODATA: load = RAM, type = ro; + DATA: load = RAM, type = rw; + ZPSAVE: load = RAM, type = bss, define = yes; + BSS: load = RAM, type = bss, define = yes; + HEAP: load = RAM, type = bss, optional = yes; # must sit just below stack + ZEROPAGE: load = ZP, type = zp, optional = yes; + EXTZP: load = ZP, type = zp, optional = yes; + AUTOSTRT: load = TRAILER, type = ro, optional = yes; +} +FEATURES { + CONDES: segment = INIT, + type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__; + CONDES: segment = RODATA, + type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__; + CONDES: type = interruptor, + segment = RODATA, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__; +} diff --git a/src/col80_modified/cruft/col80_dosini_seg.s b/src/col80_modified/cruft/col80_dosini_seg.s new file mode 100644 index 0000000..d92e7ed --- /dev/null +++ b/src/col80_modified/cruft/col80_dosini_seg.s @@ -0,0 +1,12 @@ + +; Second segment of the file loads at $0C (aka DOSINI), and just contains +; the address of dosini_entry_point + + .ifndef FUJICHAT + .word $FFFF ; unnecessary, though the original file had it + .endif + + .word $000C ; DOSINI + .word $000D + .word dosini_entry_point + diff --git a/src/col80_modified/cruft/col80_entry.s b/src/col80_modified/cruft/col80_entry.s new file mode 100644 index 0000000..edf0d96 --- /dev/null +++ b/src/col80_modified/cruft/col80_entry.s @@ -0,0 +1,61 @@ +; ---------------------------------------------------------------------------- +; The OS jumps here on warmstart (also, this is the run address in our +; binary load file) + +dosini_entry_point: + .ifndef FUJICHAT + nop + nop + nop + .endif + +main_entry_point: + jsr col80_init + .ifndef FUJICHAT + lda CONSOL + and #$04 + beq no_e_handler + .endif + lda #$0C + sta ICCOM + ldx #$00 + jsr CIOV + lda #$58 + sta font_ptr_lo + lda #$03 + sta ICCOM + lda #font_ptr_lo + sta ICBAL + lda #$00 + sta ICBAH + ldx #$00 + jsr CIOV + ldy #$07 + lda #col80_vector_tab + iny + sta HATABS,y +no_e_handler: + lda #START_ADDRESS + sta MEMTOP+1 + .ifdef FUJICHAT + ldy #$01 + rts + .else + jmp return_success + .endif + +; ---------------------------------------------------------------------------- +; (when does this actually get called? da65 can't find any references +; to it, and it's not a run or init address in the binary load file) + .ifndef FUJICHAT + lda #dosini_entry_point + sta DOSINI+1 + jmp main_entry_point + .endif + diff --git a/src/col80_modified/cruft/col80_header_seg.s b/src/col80_modified/cruft/col80_header_seg.s new file mode 100644 index 0000000..2f96ad9 --- /dev/null +++ b/src/col80_modified/cruft/col80_header_seg.s @@ -0,0 +1,6 @@ + + .org START_ADDRESS-6 + .word $FFFF + .word START_ADDRESS + .word END_ADDRESS + diff --git a/src/col80_modified/cruft/col80_include.s b/src/col80_modified/cruft/col80_include.s new file mode 100644 index 0000000..943c579 --- /dev/null +++ b/src/col80_modified/cruft/col80_include.s @@ -0,0 +1,50 @@ +; ---------------------------------------------------------------------------- +; Zero page labels (OS equates) + +DOSINI = $000C +ICAX1Z = $002A +ICAX2Z = $002B +TMPCHR = $0050 +LMARGN = $0052 +ROWCRS = $0054 +COLCRS = $0055 +DINDEX = $0057 +SAVMSC = $0058 +BUFCNT = $006B + +; ---------------------------------------------------------------------------- +; Zero page labels (COL80 equates) + +screen_ptr_lo = $00CB +screen_ptr_hi = $00CC +font_ptr_lo = $00CD +font_ptr_hi = $00CE + +; ---------------------------------------------------------------------------- +; Non-zeropage RAM labels (OS equates) + +COLOR1 = $02C5 +COLOR2 = $02C6 +RUNAD = $02E0 +MEMTOP = $02E5 +SSFLAG = $02FF +HATABS = $031A +ICCOM = $0342 +ICBAL = $0344 +ICBAH = $0345 + +; ---------------------------------------------------------------------------- +; Hardware (memory-mapped I/O, OS equates) + +CONSOL = $D01F +AUDF1 = $D200 +AUDC1 = $D201 + +; ---------------------------------------------------------------------------- +; OS ROM labels + +s_dev_open_lo = $E410 ; (not named in OS sources) +s_dev_open_hi = $E411 ; "" +k_dev_get_lo = $E424 ; "" +k_dev_get_hi = $E425 ; "" +CIOV = $E456 ; Central Input/Output entry point diff --git a/src/col80_modified/cruft/col80_init.s b/src/col80_modified/cruft/col80_init.s new file mode 100644 index 0000000..89ccf75 --- /dev/null +++ b/src/col80_modified/cruft/col80_init.s @@ -0,0 +1,35 @@ +; ---------------------------------------------------------------------------- +; Initialization callback. The OS will call this on coldstart (or would do, +; if the driver were in ROM), and also on warmstart (because we stole the +; DOSINI vector). +; This routine is also the first thing that gets called by the mainline +; init code. Its job is to install COL80 in the handler table at HATABS. +; Actually the handler is first installed as X:, then the main init code +; fixes this up to E: unless the user is holding down SELECT. This allows +; the user to toggle between the 40-column ROM E: and COL80 without doing +; a full reboot. No idea if this was a documented feature or something the +; author used for development/debugging. + +col80_init: + ldy #$00 + +next_hatab_slot: + lda HATABS,y + beq register_x_handler + iny + iny + iny + cpy #$20 + bcc next_hatab_slot + jmp return_success + +register_x_handler: + lda #$58 + sta HATABS,y + lda #col80_vector_tab + iny + sta HATABS,y + jmp return_success diff --git a/src/col80_modified/cruft/col80_main.s b/src/col80_modified/cruft/col80_main.s new file mode 100644 index 0000000..0ced210 --- /dev/null +++ b/src/col80_modified/cruft/col80_main.s @@ -0,0 +1,824 @@ +; THIS IS A MODIFIED VERSION, for use with FujiChat + +; COL80.COM, aka COL80E.COM, aka COL80HND.COM +; (and probably several other names) + +; Original author unknown +; License unknown +; Disassembly and comments by Urchlay + +; This is a widely-distributed software 80-column driver for the Atari +; 8-bit computers. It replaces the OS's E: driver, and uses GRAPHICS 8 +; for display, with 4x8 pixel character cells. + +; Disassembly was done with da65, with many iterations of "edit the +; .info file, disassemble again", and the results were tweaked by hand +; into something assemblable by dasm (and fairly compatible with other +; assemblers). + + + .include "col80_include.s" + +; START_ADDRESS is defined in col80_startaddr.s + .org START_ADDRESS + +; ---------------------------------------------------------------------------- +; Start of COL80. The font is stored in packed form. Each group of 8 bytes +; defines two glyphs: the upper 4 bits of the 8 bytes, taken together, +; define the bitmap for the first glyph, and the lower 4 bits are the second. +; Note that the bits that make up a single character are spread across 8 +; bytes, so it's hard to visualize these even if you're used to reading hex +; dumps. + +; The first 2 characters look like: + +; .... .O.. ; $04 +; .... .O.. ; $04 +; O.O. .O.. ; $A4 +; OOO. .O.. ; $E4 +; OOO. .OOO ; $E7 +; .O.. .O.. ; $44 +; .... .O.. ; $04 +; .... .O.. ; $04 + +; These are the ATASCII heart symbol (character code 0) and the ATASCII +; control-A line-drawing symbol (code 1). + +; Note: unlike the ROM font, this font is stored in ATASCII order instead +; of the standard Atari character order imposed by the hardware. Like +; the ROM font, inverse characters are not stored here (the bitmaps get +; inverted by the driver) + +font_data: + .ifdef FUJICHAT + .include "new_font.s" + .else + ; Low ATASCII graphics symbols (code 0-31) + .byte $04,$04,$A4,$E4,$E7,$44,$04,$04 + .byte $14,$14,$14,$14,$1C,$10,$10,$10 + .byte $40,$40,$40,$40,$CC,$44,$44,$44 + .byte $18,$18,$24,$24,$42,$42,$81,$81 + .byte $10,$10,$30,$30,$73,$73,$F3,$F3 + .byte $83,$83,$C3,$C3,$E0,$E0,$F0,$F0 + .byte $CF,$CF,$C0,$C0,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$0C,$0C,$FC,$FC + .byte $00,$00,$00,$40,$A7,$44,$E4,$04 + .byte $04,$04,$04,$04,$FF,$04,$04,$04 + .byte $00,$00,$60,$F0,$FF,$6F,$0F,$0F + .byte $80,$80,$80,$80,$8F,$84,$84,$84 + .byte $4C,$4C,$4C,$4C,$FC,$0C,$0C,$0C + .byte $40,$4C,$48,$4C,$78,$0C,$06,$00 + .byte $00,$44,$E4,$44,$4E,$44,$00,$00 + .byte $00,$24,$42,$FF,$42,$24,$00,$00 + + ; Space ! " # etc (codes 32-63) + .byte $00,$04,$04,$04,$04,$00,$04,$00 + .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00 + .byte $00,$40,$68,$82,$44,$28,$C2,$40 + .byte $00,$C4,$64,$E4,$60,$C0,$40,$00 + .byte $00,$44,$82,$82,$82,$82,$82,$44 + .byte $00,$04,$A4,$4E,$E4,$44,$A0,$00 + .byte $00,$00,$00,$0E,$00,$40,$40,$80 + .byte $00,$02,$02,$04,$04,$08,$48,$00 + .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00 + .byte $00,$EE,$22,$22,$EE,$82,$EE,$00 + .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00 + .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00 + .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00 + .byte $00,$00,$00,$44,$00,$44,$04,$08 + .byte $00,$20,$4E,$80,$4E,$20,$00,$00 + .byte $00,$8C,$42,$22,$44,$80,$04,$00 + + ; @ A B C etc (codes 64-95) + .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00 + .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00 + .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00 + .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00 + .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00 + .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00 + .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00 + .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00 + .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03 + .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00 + .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00 + .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00 + .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00 + .byte $00,$EE,$28,$48,$88,$88,$E8,$0E + .byte $00,$8E,$82,$42,$42,$22,$22,$0E + .byte $00,$00,$40,$A0,$00,$00,$00,$0F + + ; diamond, lowercase letters, control codes (codes 96-127) + .byte $00,$00,$00,$46,$E2,$4E,$0E,$00 + .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00 + .byte $00,$20,$20,$6E,$AE,$A8,$6E,$00 + .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C + .byte $00,$80,$84,$80,$C4,$A4,$A4,$00 + .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0 + .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00 + .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00 + .byte $00,$00,$00,$C6,$AA,$C6,$82,$82 + .byte $00,$00,$00,$6E,$88,$86,$8E,$00 + .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00 + .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00 + .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C + .byte $00,$00,$04,$EE,$4E,$84,$EE,$00 + .byte $40,$4E,$4C,$4E,$4A,$42,$42,$40 + .byte $00,$28,$6C,$EE,$6C,$28,$00,$00 + .endif + +right_margin: + ; Default value is 79 decimal. Unsure why the author didn't use RMARGN at $53 + .byte $4F + +; ---------------------------------------------------------------------------- +; Start of COL80 code. + +; Callback for CIO OPEN command. + +col80_open: + jsr init_graphics_8 + lda #$00 + sta ROWCRS + sta COLCRS + .ifndef FUJICHAT + nop + nop + .endif + sta BUFCNT + lda #$4F + sta right_margin + rts + +; ---------------------------------------------------------------------------- +; Assembly version of GRAPHICS 8+16 command. + +init_graphics_8: + lda #$08 + sta ICAX2Z + lda #$0C + sta ICAX1Z + jsr open_s_dev + + ; Set COL80's default colors + lda #$08 + sta COLOR2 + .ifndef FUJICHAT + nop + nop + nop + .endif + lda #$00 + sta COLOR1 + + ; Protect ourselves from BASIC and the OS + lda #START_ADDRESS + sta MEMTOP+1 + rts + +; ---------------------------------------------------------------------------- +; Call the OPEN vector for the S: device, using the ROM vector table +; at $E410. The table stores address-minus-one of each routine, which is +; meant to actually be called via the RTS instruction (standard 6502 +; technique, but confusing the first time you encounter it) + +open_s_dev: + lda s_dev_open_hi + pha + lda s_dev_open_lo + pha + rts + +; ---------------------------------------------------------------------------- +; Callback for CIO CLOSE command. Note that the routine does nothing, really +; (the OS will mark the E: device as being closed, but COL80 doesn't do any +; cleanup). +; The SPECIAL and GET STATUS callbacks in col80_vector_tab also point here. + +col80_close: + jmp return_success + +; ---------------------------------------------------------------------------- +; Callback for the internal put-one-byte, used by the OS to implement the +; CIO PUT RECORD and PUT BYTES commands. This routine's one argument is +; the byte in the accumulator (the character to print). + +; First, the routine checks for the cursor control characters it supports. +; COL80 only handles the EOL and clear-screen codes; trying to print +; backspaces, arrows, deletes, inserts, etc just causes their ATASCII +; graphics character to print instead. + +col80_putbyte: + ; EOL (decimal 155)? + cmp #$9B + bne check_clear + lda right_margin + sta COLCRS + jmp skip_write + +check_clear: + .ifndef FUJICHAT ; save memory by not including clear_screen + ; (also, this lets us print the } character) + ; Clear (decimal 125)? + cmp #$7D + bne regular_char + jmp clear_screen + .endif + + ; See if this is an inverse video char (code >= 128) +regular_char: + tax + bpl not_inverse + lda #$FF + sta inverse_mask + bne skip_ninv + +not_inverse: + lda #$00 + sta inverse_mask + +skip_ninv: + txa + and #$7F + .ifdef FUJICHAT ; mask out low ASCII + sec + sbc #$20 + bcs not_low_ascii + jmp return_success +not_low_ascii: + .endif + sta TMPCHR + lda DINDEX + cmp #$08 + beq graphics_ok + ; If we're not in GRAPHICS 8 mode, reinitialize ourselves + jsr col80_open + +graphics_ok: + ; Call the routines that actually print the character + jsr setup_font_ptr + jsr setup_screen_ptr + jsr write_font_data + +skip_write: + ; Move the cursor 1 space to the right. This will + ; advance us to the next line if we're at the margin, + ; and scroll the screen if needed + jsr advance_cursor + +check_ssflag: + ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla + ; any time the user presses ctrl-1 + lda SSFLAG + bne check_ssflag + jmp return_success + +; ---------------------------------------------------------------------------- +; Scroll the screen up one line (8 scanlines). This has to move almost 8K of +; data, so it's noticeably slower than scrolling the GR.0 text screen. + +scroll_screen: + lda SAVMSC + sta screen_ptr_lo + clc + adc #$40 + ; font_ptr_lo is actually being used here as a second pointer into + ; screen RAM, instead of its usual use as a pointer into the + ; font_data table + sta font_ptr_lo + lda SAVMSC+1 + sta screen_ptr_hi + adc #$01 + sta font_ptr_hi + ldx #$1D + ldy #$00 + +scroll_line_loop: + lda (font_ptr_lo),y + sta (screen_ptr_lo),y + dey + bne scroll_line_loop + inc font_ptr_hi + inc screen_ptr_hi + dex + bne scroll_line_loop + +blank_bottom_row: + lda SAVMSC + clc + adc #$C0 + sta screen_ptr_lo + lda SAVMSC+1 + adc #$1C + sta screen_ptr_hi + lda #$00 + tay + +blank_loop: + sta (screen_ptr_lo),y + dey + bne blank_loop + inc screen_ptr_hi + ldy #$40 + +blank_tail: + sta (screen_ptr_lo),y + dey + bpl blank_tail + rts + +; ---------------------------------------------------------------------------- +; Set up font_ptr_lo/hi to point to the font_data bitmap for the character in +; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the +; bitmap is in the upper or lower 4 bits of the bytes pointed to. + +setup_font_ptr: + lda #$00 + sta font_ptr_hi + sta lo_nybble_flag + lda TMPCHR + clc + ror + bcc font_hi_nybble + ldx #$FF + stx lo_nybble_flag + +font_hi_nybble: + clc + rol + rol + rol font_ptr_hi + rol + rol font_ptr_hi + adc #font_data + adc font_ptr_hi + sta font_ptr_hi + rts + +; ---------------------------------------------------------------------------- +; Move the cursor one space to the right (to the next line if at the margin, +; and scroll screen if on the last row) + +advance_cursor: + inc COLCRS + lda right_margin + cmp COLCRS + bcs same_line + lda LMARGN + sta COLCRS + lda ROWCRS + ; $17 is 25 decimal, one row below the lowest on the screen + cmp #$17 + bcc no_scroll + jsr scroll_screen + ; Move to row 24 after scrolling + lda #$16 + sta ROWCRS + +no_scroll: + inc ROWCRS + +same_line: + rts + +; ---------------------------------------------------------------------------- +; Clear the screen by setting all screen RAM bytes to zero. Slow, but not +; as slow as scrolling. + + .ifndef FUJICHAT +clear_screen: + lda SAVMSC + sta screen_ptr_lo + lda SAVMSC+1 + sta screen_ptr_hi + ldy #$00 + ldx #$1D + lda #$00 + +cls_loop: + sta (screen_ptr_lo),y + dey + bne cls_loop + inc screen_ptr_hi + dex + bne cls_loop + jsr blank_bottom_row + lda LMARGN + sta COLCRS + lda #$00 + sta ROWCRS + ; redundant JMP + jmp return_success + .endif + +; ---------------------------------------------------------------------------- +; CIO expects the Y register to contain a status code. +; 1 means success (no error). Lots of COL80's routines +; jump here. + +return_success: + ldy #$01 + rts + +; ---------------------------------------------------------------------------- +; Set screen_ptr_lo/hi to point to the address of the first byte of graphics +; data at the current cursor position. + +setup_screen_ptr: + ldy ROWCRS + lda SAVMSC + clc + adc row_low_offset_tab,y + sta screen_ptr_lo + lda SAVMSC+1 + adc row_high_offset_tab,y + sta screen_ptr_hi + lda COLCRS + lsr + clc + adc screen_ptr_lo + bcc hi_byte_ok + inc screen_ptr_hi + +hi_byte_ok: + sta screen_ptr_lo + rts + +; ---------------------------------------------------------------------------- +; Tables of offsets for setup_screen_ptr, to avoid doing multiplication at +; runtime (the 6502 lacks a MUL instruction, so it's slow...) + +row_low_offset_tab: + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 + +row_high_offset_tab: + .byte $00,$01,$02,$03,$05,$06,$07,$08 + .byte $0A,$0B,$0C,$0D,$0F,$10,$11,$12 + .byte $14,$15,$16,$17,$19,$1A,$1B,$1C + +; ---------------------------------------------------------------------------- +; Copy pixel data from the font table to screen RAM. +; font_ptr_lo/hi must point to the correct character, and screen_ptr_lo/hi +; must point to the correct screen address for the current cursor position. +; This routine has separate execution paths for even- and odd-numbered +; cursor positions, since each byte of screen RAM holds data for two +; adjacent characters (and when printing to one of them, the other needs +; to be left undisturbed!) + +write_font_data: + lda COLCRS + clc + ror + bcc write_font_data_even + ldx #$00 + ldy #$00 + +get_font_nybble_odd: + lda (font_ptr_lo),y + bit lo_nybble_flag + bne lo_nybble_odd + ; glyph we want is stored in top 4 bits of font byte, + ; shift it down to the bottom 4 bits + lsr + lsr + lsr + lsr + +lo_nybble_odd: + eor inverse_mask + and #$0F + sta TMPCHR + ldy scanline_offset_tab,x + lda (screen_ptr_lo),y + and #$F0 + ora TMPCHR + sta (screen_ptr_lo),y + inx + cpx #$07 + bne screen_ptr_ok_odd + inc screen_ptr_hi + +screen_ptr_ok_odd: + cpx #$08 + beq write_font_done_odd + txa + tay + bne get_font_nybble_odd + +write_font_done_odd: + rts + +; ---------------------------------------------------------------------------- +; Write data to even-numbered columns, very similar to the above + +write_font_data_even: + ldx #$00 + ldy #$00 + +get_font_nybble_even: + lda (font_ptr_lo),y + bit lo_nybble_flag + beq hi_nybble_even + asl + asl + asl + asl + +hi_nybble_even: + eor inverse_mask + and #$F0 + sta TMPCHR + ldy scanline_offset_tab,x + lda (screen_ptr_lo),y + and #$0F + ora TMPCHR + sta (screen_ptr_lo),y + inx + cpx #$07 + bne screen_ptr_ok_even + inc screen_ptr_hi + +screen_ptr_ok_even: + cpx #$08 + beq write_font_done_even + txa + tay + bne get_font_nybble_even + +write_font_done_even: + rts + +; ---------------------------------------------------------------------------- + +scanline_offset_tab: + .byte $00,$28,$50,$78,$A0,$C8,$F0,$18 + +; ---------------------------------------------------------------------------- +; Callback for the internal get-one-byte, used by the OS to implement the +; CIO GET RECORD and GET BYTES commands. This routine takes no arguments, +; and returns the read byte in the accumulator. + +; Internally, COL80 maintains a line buffer. Each time col80_getbyte is +; called, it returns the next character in the buffer. If the buffer's +; empty (or if the last call returned the last character), a new line +; of input is read from the user (and the first character is returned). +; This is exactly how the OS E: device works. + +col80_getbyte: + lda BUFCNT + beq get_line + +get_next_byte: + ldx line_buffer_index + lda line_buffer,x + dec BUFCNT + inc line_buffer_index + jmp return_success + +; ---------------------------------------------------------------------------- +; Get a line of input from the user, terminated by the Return key. + +get_line: + lda #$00 + sta BUFCNT + sta line_buffer_index + +show_cursor: + .ifdef FUJICHAT + lda #$00 + .else + lda #$20 + .endif + sta TMPCHR + lda #$FF + sta inverse_mask + jsr setup_font_ptr + jsr setup_screen_ptr + jsr write_font_data + jsr get_keystroke + cpy #$01 + beq keystroke_ok + .ifdef FUJICHAT + dey ; yes, we really care about 1-byte optimizations + .else + ldy #$00 + .endif + sty line_buffer_index + sty BUFCNT + +keystroke_ok: + .ifdef FUJICHAT + cmp #$20 + bcc show_cursor ; ignore low ASCII + .endif + cmp #$9B + bne check_backs_key + jmp return_key_hit + +check_backs_key: + cmp #$7E + bne check_clear_key + jmp backs_key_hit + +check_clear_key: + cmp #$7D + bne normal_key_hit + jmp clear_key_hit + +normal_key_hit: + ldx BUFCNT + bpl buffer_character + .ifdef FUJICHAT + jmp show_cursor + .else + jmp beep + .endif + +buffer_character: + sta line_buffer,x + jsr col80_putbyte + inc BUFCNT + jmp show_cursor + +return_key_hit: + jsr print_space + lda #$9B + ldx BUFCNT + sta line_buffer,x + inc BUFCNT + jsr col80_putbyte + jmp get_next_byte + +clear_key_hit: + .ifndef FUJICHAT + jsr clear_screen + .endif + lda #$00 + sta line_buffer_index + sta BUFCNT + jmp get_line + +backs_key_hit: + jsr print_space + lda BUFCNT + beq backs_key_done + dec COLCRS + lda COLCRS + clc + adc #$01 + cmp LMARGN + bne backs_same_line + lda right_margin + sta COLCRS + dec ROWCRS + +backs_same_line: + dec BUFCNT + +backs_key_done: + jmp show_cursor + +; ---------------------------------------------------------------------------- +; Ring the margin bell. COL80 doesn't implement the ctrl-2 bell (character +; 253), and instead of using the GTIA keyclick speaker, it uses POKEY to +; make a beep + + .ifndef FUJICHAT +beep: ldy #$00 + ldx #$AF + +beep_delay_x: + stx AUDF1 + stx AUDC1 + +beep_delay_y: + dey + bne beep_delay_y + dex + cpx #$9F + bne beep_delay_x + jmp show_cursor + .endif + +; ---------------------------------------------------------------------------- +; Print a space character at the current cursor position. Does not +; update the cursor position. +print_space: + lda #$00 + sta inverse_mask + .ifndef FUJICHAT + lda #$20 + .endif + sta TMPCHR + jsr setup_font_ptr + jsr setup_screen_ptr + jsr write_font_data + rts + +; ---------------------------------------------------------------------------- +; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine +; (call by pushing address-minus-one then doing an RTS) +get_keystroke: + lda k_dev_get_hi + pha + lda k_dev_get_lo + pha + rts + + .ifndef FUJICHAT + .include "col80_init.s" + .endif + +; ---------------------------------------------------------------------------- +; COL80 vector table, in the format required by the OS. Our HATABS entry +; will point to this table, and the OS will call the routines listed here +; via the "call by RTS" method (which is why they're address-minus-one). + +; See the entry on HATABS in "Mapping the Atari" or the OS manual. + +col80_vector_tab: + .word col80_open-1 + .word col80_close-1 + .word col80_getbyte-1 + .word col80_putbyte-1 + .word col80_close-1 + .word col80_close-1 + .ifdef FUJICHAT + .byte 0, 0, 0 ; heh. + .else + jmp col80_init + .endif + + .ifndef FUJICHAT + .include "col80_entry.s" + .endif + +; ---------------------------------------------------------------------------- +; Various bits of runtime state here. It's unclear to me why the standard +; OS buffer location couldn't have been used instead (normally the top +; half of page 5), or why the other stuff couldn't have been stored in +; zero page, in locations used by the ROM E: handler (thus unused when +; it's replaced with COL80). line_buffer_index needs to be preserved +; across calls to col80_getbyte, but lo_nybble_flag and inverse_mask are +; freshly calculated every time they're used, so they could be almost +; anywhere. + + .ifdef FUJICHAT + .segment "CODE" + .endif + +lo_nybble_flag: + .byte $00 + +inverse_mask: + .byte $00 + +line_buffer_index: + .byte $12 + +; ---------------------------------------------------------------------------- +; There's absolutely no reason why this data needs to be included in the +; binary load file: the line buffer's initial contents are meaningless, they +; will be blown away the first time anything reads from the E: device. + +; Notice the author was running his debugger in COL80 when he built the +; binary (ASCII "S COL80 7A00 7F80" command still in the buffer). + + .ifdef FUJICHAT +line_buffer = $03FD ; cassette buffer + .else +line_buffer: + .byte $53,$20,$43,$4F,$4C,$38,$30,$20 + .byte $37,$41,$30,$30,$20,$37,$46,$38 + .byte $30,$9B,$20,$20,$20,$20,$9B,$27 + .byte $40,$40,$40,$40,$28,$28,$28,$28 + .byte $40,$40,$40,$40,$40,$40,$40,$40 + .byte $40,$40,$40,$40,$40,$40,$40,$40 + .byte $9B,$FD,$FD,$FD,$FD,$9B + .endif + +END_ADDRESS = *-1 + +; I've found a variant (modified version?) of this code, that doesn't +; include the line_buffer in the file (no reason for it to be there), +; or the $0C segment, and that has another segment, loaded at $6000, +; with the run address changed to $6000. The code looks like: + +; .org $6000 +; jsr dosini_entry_point +; lda #$50 +; sta RMARGN +; lda #$00 +; sta COLOR2 + +; also, the default colors have been changed in init_graphics_8. + +; There are at least two binaries floating around that contain +; extra (garbage) bytes at the end, presumably from being transferred +; over XMODEM or similar. They are otherwise identical. + diff --git a/src/col80_modified/cruft/col80_main.s.orig b/src/col80_modified/cruft/col80_main.s.orig new file mode 100644 index 0000000..0b56ee3 --- /dev/null +++ b/src/col80_modified/cruft/col80_main.s.orig @@ -0,0 +1,895 @@ +; COL80.COM, aka COL80E.COM, aka COL80HND.COM +; (and probably several other names) + +; Original author unknown +; License unknown +; Disassembly and comments by Urchlay + +; This is a widely-distributed software 80-column driver for the Atari +; 8-bit computers. It replaces the OS's E: driver, and uses GRAPHICS 8 +; for display, with 4x8 pixel character cells. + +; Disassembly was done with da65, with many iterations of "edit the +; .info file, disassemble again", and the results were tweaked by hand +; into something assemblable by dasm (and fairly compatible with other +; assemblers). + + +; START_ADDRESS is defined in col80_startaddr.s + .org START_ADDRESS + +; ---------------------------------------------------------------------------- +; Zero page labels (OS equates) + +DOSINI = $000C +ICAX1Z = $002A +ICAX2Z = $002B +TMPCHR = $0050 +LMARGN = $0052 +ROWCRS = $0054 +COLCRS = $0055 +DINDEX = $0057 +SAVMSC = $0058 +BUFCNT = $006B + +; ---------------------------------------------------------------------------- +; Zero page labels (COL80 equates) + +screen_ptr_lo = $00CB +screen_ptr_hi = $00CC +font_ptr_lo = $00CD +font_ptr_hi = $00CE + +; ---------------------------------------------------------------------------- +; Non-zeropage RAM labels (OS equates) + +COLOR1 = $02C5 +COLOR2 = $02C6 +RUNAD = $02E0 +MEMTOP = $02E5 +SSFLAG = $02FF +HATABS = $031A +ICCOM = $0342 +ICBAL = $0344 +ICBAH = $0345 + +; ---------------------------------------------------------------------------- +; Hardware (memory-mapped I/O, OS equates) + +CONSOL = $D01F +AUDF1 = $D200 +AUDC1 = $D201 + +; ---------------------------------------------------------------------------- +; OS ROM labels + +s_dev_open_lo = $E410 ; (not named in OS sources) +s_dev_open_hi = $E411 ; "" +k_dev_get_lo = $E424 ; "" +k_dev_get_hi = $E425 ; "" +CIOV = $E456 ; Central Input/Output entry point + +; ---------------------------------------------------------------------------- +; Start of COL80. The font is stored in packed form. Each group of 8 bytes +; defines two glyphs: the upper 4 bits of the 8 bytes, taken together, +; define the bitmap for the first glyph, and the lower 4 bits are the second. +; Note that the bits that make up a single character are spread across 8 +; bytes, so it's hard to visualize these even if you're used to reading hex +; dumps. + +; The first 2 characters look like: + +; .... .O.. ; $04 +; .... .O.. ; $04 +; O.O. .O.. ; $A4 +; OOO. .O.. ; $E4 +; OOO. .OOO ; $E7 +; .O.. .O.. ; $44 +; .... .O.. ; $04 +; .... .O.. ; $04 + +; These are the ATASCII heart symbol (character code 0) and the ATASCII +; control-A line-drawing symbol (code 1). + +; Note: unlike the ROM font, this font is stored in ATASCII order instead +; of the standard Atari character order imposed by the hardware. Like +; the ROM font, inverse characters are not stored here (the bitmaps get +; inverted by the driver) + +font_data: + ; Low ATASCII graphics symbols (code 0-31) + .byte $04,$04,$A4,$E4,$E7,$44,$04,$04 ; 7A00 + .byte $14,$14,$14,$14,$1C,$10,$10,$10 ; 7A08 + .byte $40,$40,$40,$40,$CC,$44,$44,$44 ; 7A10 + .byte $18,$18,$24,$24,$42,$42,$81,$81 ; 7A18 + .byte $10,$10,$30,$30,$73,$73,$F3,$F3 ; 7A20 + .byte $83,$83,$C3,$C3,$E0,$E0,$F0,$F0 ; 7A28 + .byte $CF,$CF,$C0,$C0,$00,$00,$00,$00 ; 7A30 + .byte $00,$00,$00,$00,$0C,$0C,$FC,$FC ; 7A38 + .byte $00,$00,$00,$40,$A7,$44,$E4,$04 ; 7A40 + .byte $04,$04,$04,$04,$FF,$04,$04,$04 ; 7A48 + .byte $00,$00,$60,$F0,$FF,$6F,$0F,$0F ; 7A50 + .byte $80,$80,$80,$80,$8F,$84,$84,$84 ; 7A58 + .byte $4C,$4C,$4C,$4C,$FC,$0C,$0C,$0C ; 7A60 + .byte $40,$4C,$48,$4C,$78,$0C,$06,$00 ; 7A68 + .byte $00,$44,$E4,$44,$4E,$44,$00,$00 ; 7A70 + .byte $00,$24,$42,$FF,$42,$24,$00,$00 ; 7A78 + + ; Space ! " # etc (codes 32-63) + .byte $00,$04,$04,$04,$04,$00,$04,$00 ; 7A80 + .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00 ; 7A88 + .byte $00,$40,$68,$82,$44,$28,$C2,$40 ; 7A90 + .byte $00,$C4,$64,$E4,$60,$C0,$40,$00 ; 7A98 + .byte $00,$44,$82,$82,$82,$82,$82,$44 ; 7AA0 + .byte $00,$04,$A4,$4E,$E4,$44,$A0,$00 ; 7AA8 + .byte $00,$00,$00,$0E,$00,$40,$40,$80 ; 7AB0 + .byte $00,$02,$02,$04,$04,$08,$48,$00 ; 7AB8 + .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00 ; 7AC0 + .byte $00,$EE,$22,$22,$EE,$82,$EE,$00 ; 7AC8 + .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00 ; 7AD0 + .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00 ; 7AD8 + .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00 ; 7AE0 + .byte $00,$00,$00,$44,$00,$44,$04,$08 ; 7AE8 + .byte $00,$20,$4E,$80,$4E,$20,$00,$00 ; 7AF0 + .byte $00,$8C,$42,$22,$44,$80,$04,$00 ; 7AF8 + + ; @ A B C etc (codes 64-95) + .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00 ; 7B00 + .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00 ; 7B08 + .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00 ; 7B10 + .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00 ; 7B18 + .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00 ; 7B20 + .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00 ; 7B28 + .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00 ; 7B30 + .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00 ; 7B38 + .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03 ; 7B40 + .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00 ; 7B48 + .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00 ; 7B50 + .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00 ; 7B58 + .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00 ; 7B60 + .byte $00,$EE,$28,$48,$88,$88,$E8,$0E ; 7B68 + .byte $00,$8E,$82,$42,$42,$22,$22,$0E ; 7B70 + .byte $00,$00,$40,$A0,$00,$00,$00,$0F ; 7B78 + + ; diamond, lowercase letters, control codes (codes 96-127) + .byte $00,$00,$00,$46,$E2,$4E,$0E,$00 ; 7B80 + .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00 ; 7B88 + .byte $00,$20,$20,$6E,$AE,$A8,$6E,$00 ; 7B90 + .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C ; 7B98 + .byte $00,$80,$84,$80,$C4,$A4,$A4,$00 ; 7BA0 + .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0 ; 7BA8 + .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00 ; 7BB0 + .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00 ; 7BB8 + .byte $00,$00,$00,$C6,$AA,$C6,$82,$82 ; 7BC0 + .byte $00,$00,$00,$6E,$88,$86,$8E,$00 ; 7BC8 + .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00 ; 7BD0 + .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00 ; 7BD8 + .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C ; 7BE0 + .byte $00,$00,$04,$EE,$4E,$84,$EE,$00 ; 7BE8 + .byte $40,$4E,$4C,$4E,$4A,$42,$42,$40 ; 7BF0 + .byte $00,$28,$6C,$EE,$6C,$28,$00,$00 ; 7BF8 + +right_margin: + ; Default value is 79 decimal. Unsure why the author didn't use RMARGN at $53 + .byte $4F ; 7C00 4F + +; ---------------------------------------------------------------------------- +; Start of COL80 code. + +; Callback for CIO OPEN command. + +col80_open: + jsr init_graphics_8 ; 7C01 20 14 7C + lda #$00 ; 7C04 A9 00 + sta ROWCRS ; 7C06 85 54 + sta COLCRS ; 7C08 85 55 + nop ; 7C0A EA + nop ; 7C0B EA + sta BUFCNT ; 7C0C 85 6B + lda #$4F ; 7C0E A9 4F + sta right_margin ; 7C10 8D 00 7C + rts ; 7C13 60 + +; ---------------------------------------------------------------------------- +; Assembly version of GRAPHICS 8+16 command. + +init_graphics_8: + lda #$08 ; 7C14 A9 08 + sta ICAX2Z ; 7C16 85 2B + lda #$0C ; 7C18 A9 0C + sta ICAX1Z ; 7C1A 85 2A + jsr open_s_dev ; 7C1C 20 37 7C + + ; Set COL80's default colors + lda #$08 ; 7C1F A9 08 + sta COLOR2 ; 7C21 8D C6 02 + nop ; 7C24 EA + nop ; 7C25 EA + nop ; 7C26 EA + lda #$00 ; 7C27 A9 00 + sta COLOR1 ; 7C29 8D C5 02 + + ; Protect ourselves from BASIC and the OS + lda #START_ADDRESS ; 7C31 A9 7A + sta MEMTOP+1 ; 7C33 8D E6 02 + rts ; 7C36 60 + +; ---------------------------------------------------------------------------- +; Call the OPEN vector for the S: device, using the ROM vector table +; at $E410. The table stores address-minus-one of each routine, which is +; meant to actually be called via the RTS instruction (standard 6502 +; technique, but confusing the first time you encounter it) + +open_s_dev: + lda s_dev_open_hi ; 7C37 AD 11 E4 + pha ; 7C3A 48 + lda s_dev_open_lo ; 7C3B AD 10 E4 + pha ; 7C3E 48 + rts ; 7C3F 60 + +; ---------------------------------------------------------------------------- +; Callback for CIO CLOSE command. Note that the routine does nothing, really +; (the OS will mark the E: device as being closed, but COL80 doesn't do any +; cleanup). +; The SPECIAL and GET STATUS callbacks in col80_vector_tab also point here. + +col80_close: + jmp return_success + +; ---------------------------------------------------------------------------- +; Callback for the internal put-one-byte, used by the OS to implement the +; CIO PUT RECORD and PUT BYTES commands. This routine's one argument is +; the byte in the accumulator (the character to print). + +; First, the routine checks for the cursor control characters it supports. +; COL80 only handles the EOL and clear-screen codes; trying to print +; backspaces, arrows, deletes, inserts, etc just causes their ATASCII +; graphics character to print instead. + +col80_putbyte: + ; EOL (decimal 155)? + cmp #$9B ; 7C43 C9 9B + bne check_clear ; 7C45 D0 08 + lda right_margin ; 7C47 AD 00 7C + sta COLCRS ; 7C4A 85 55 + jmp skip_write ; 7C4C 4C 7C 7C + +check_clear: + ; Clear (decimal 125)? + cmp #$7D ; 7C4F C9 7D + bne regular_char ; 7C51 D0 03 + jmp clear_screen ; 7C53 4C 0B 7D + + ; See if this is an inverse video char (code >= 128) +regular_char: + tax ; 7C56 AA + bpl not_inverse ; 7C57 10 07 + lda #$FF ; 7C59 A9 FF + sta inverse_mask ; 7C5B 8D 49 7F + bne skip_ninv ; 7C5E D0 05 + +not_inverse: + lda #$00 ; 7C60 A9 00 + sta inverse_mask ; 7C62 8D 49 7F + +skip_ninv: + txa ; 7C65 8A + and #$7F ; 7C66 29 7F + sta TMPCHR ; 7C68 85 50 + lda DINDEX ; 7C6A A5 57 + cmp #$08 ; 7C6C C9 08 + beq graphics_ok ; 7C6E F0 03 + ; If we're not in GRAPHICS 8 mode, reinitialize ourselves + jsr col80_open ; 7C70 20 01 7C + +graphics_ok: + ; Call the routines that actually print the character + jsr setup_font_ptr ; 7C73 20 C9 7C + jsr setup_screen_ptr ; 7C76 20 34 7D + jsr write_font_data ; 7C79 20 82 7D + +skip_write: + ; Move the cursor 1 space to the right. This will + ; advance us to the next line if we're at the margin, + ; and scroll the screen if needed + jsr advance_cursor ; 7C7C 20 EE 7C + +check_ssflag: + ; The OS keyboard interrupt handler will toggle SSFLAG (start/stop fla + ; any time the user presses ctrl-1 + lda SSFLAG ; 7C7F AD FF 02 + bne check_ssflag ; 7C82 D0 FB + jmp return_success ; 7C84 4C 31 7D + +; ---------------------------------------------------------------------------- +; Scroll the screen up one line (8 scanlines). This has to move almost 8K of +; data, so it's noticeably slower than scrolling the GR.0 text screen. + +scroll_screen: + lda SAVMSC ; 7C87 A5 58 + sta screen_ptr_lo ; 7C89 85 CB + clc ; 7C8B 18 + adc #$40 ; 7C8C 69 40 + ; font_ptr_lo is actually being used here as a second pointer into + ; screen RAM, instead of its usual use as a pointer into the + ; font_data table + sta font_ptr_lo ; 7C8E 85 CD + lda SAVMSC+1 ; 7C90 A5 59 + sta screen_ptr_hi ; 7C92 85 CC + adc #$01 ; 7C94 69 01 + sta font_ptr_hi ; 7C96 85 CE + ldx #$1D ; 7C98 A2 1D + ldy #$00 ; 7C9A A0 00 + +scroll_line_loop: + lda (font_ptr_lo),y ; 7C9C B1 CD + sta (screen_ptr_lo),y ; 7C9E 91 CB + dey ; 7CA0 88 + bne scroll_line_loop ; 7CA1 D0 F9 + inc font_ptr_hi ; 7CA3 E6 CE + inc screen_ptr_hi ; 7CA5 E6 CC + dex ; 7CA7 CA + bne scroll_line_loop ; 7CA8 D0 F2 + +blank_bottom_row: + lda SAVMSC ; 7CAA A5 58 + clc ; 7CAC 18 + adc #$C0 ; 7CAD 69 C0 + sta screen_ptr_lo ; 7CAF 85 CB + lda SAVMSC+1 ; 7CB1 A5 59 + adc #$1C ; 7CB3 69 1C + sta screen_ptr_hi ; 7CB5 85 CC + lda #$00 ; 7CB7 A9 00 + tay ; 7CB9 A8 + +blank_loop: + sta (screen_ptr_lo),y ; 7CBA 91 CB + dey ; 7CBC 88 + bne blank_loop ; 7CBD D0 FB + inc screen_ptr_hi ; 7CBF E6 CC + ldy #$40 ; 7CC1 A0 40 + +blank_tail: + sta (screen_ptr_lo),y ; 7CC3 91 CB + dey ; 7CC5 88 + bpl blank_tail ; 7CC6 10 FB + rts ; 7CC8 60 + +; ---------------------------------------------------------------------------- +; Set up font_ptr_lo/hi to point to the font_data bitmap for the character in +; TMPCHR. Also sets lo_nybble_flag to let the caller know whether the +; bitmap is in the upper or lower 4 bits of the bytes pointed to. + +setup_font_ptr: + lda #$00 ; 7CC9 A9 00 + sta font_ptr_hi ; 7CCB 85 CE + sta lo_nybble_flag ; 7CCD 8D 48 7F + lda TMPCHR ; 7CD0 A5 50 + clc ; 7CD2 18 + ror ; 7CD3 6A + bcc font_hi_nybble ; 7CD4 90 05 + ldx #$FF ; 7CD6 A2 FF + stx lo_nybble_flag ; 7CD8 8E 48 7F + +font_hi_nybble: + clc ; 7CDB 18 + rol ; 7CDC 2A + rol ; 7CDD 2A + rol font_ptr_hi ; 7CDE 26 CE + rol ; 7CE0 2A + rol font_ptr_hi ; 7CE1 26 CE + adc #font_data ; 7CE7 A9 7A + adc font_ptr_hi ; 7CE9 65 CE + sta font_ptr_hi ; 7CEB 85 CE + rts ; 7CED 60 + +; ---------------------------------------------------------------------------- +; Move the cursor one space to the right (to the next line if at the margin, +; and scroll screen if on the last row) + +advance_cursor: + inc COLCRS ; 7CEE E6 55 + lda right_margin ; 7CF0 AD 00 7C + cmp COLCRS ; 7CF3 C5 55 + bcs same_line ; 7CF5 B0 13 + lda LMARGN ; 7CF7 A5 52 + sta COLCRS ; 7CF9 85 55 + lda ROWCRS ; 7CFB A5 54 + ; $17 is 25 decimal, one row below the lowest on the screen + cmp #$17 ; 7CFD C9 17 + bcc no_scroll ; 7CFF 90 07 + jsr scroll_screen ; 7D01 20 87 7C + ; Move to row 24 after scrolling + lda #$16 ; 7D04 A9 16 + sta ROWCRS ; 7D06 85 54 + +no_scroll: + inc ROWCRS ; 7D08 E6 54 + +same_line: + rts ; 7D0A 60 + +; ---------------------------------------------------------------------------- +; Clear the screen by setting all screen RAM bytes to zero. Slow, but not +; as slow as scrolling. + +clear_screen: + lda SAVMSC ; 7D0B A5 58 + sta screen_ptr_lo ; 7D0D 85 CB + lda SAVMSC+1 ; 7D0F A5 59 + sta screen_ptr_hi ; 7D11 85 CC + ldy #$00 ; 7D13 A0 00 + ldx #$1D ; 7D15 A2 1D + lda #$00 ; 7D17 A9 00 + +cls_loop: + sta (screen_ptr_lo),y ; 7D19 91 CB + dey ; 7D1B 88 + bne cls_loop ; 7D1C D0 FB + inc screen_ptr_hi ; 7D1E E6 CC + dex ; 7D20 CA + bne cls_loop ; 7D21 D0 F6 + jsr blank_bottom_row ; 7D23 20 AA 7C + lda LMARGN ; 7D26 A5 52 + sta COLCRS ; 7D28 85 55 + lda #$00 ; 7D2A A9 00 + sta ROWCRS ; 7D2C 85 54 + ; redundant JMP + jmp return_success ; 7D2E 4C 31 7D + +; ---------------------------------------------------------------------------- +; CIO expects the Y register to contain a status code. +; 1 means success (no error). Lots of COL80's routines +; jump here. + +return_success: + ldy #$01 ; 7D31 A0 01 + rts ; 7D33 60 + +; ---------------------------------------------------------------------------- +; Set screen_ptr_lo/hi to point to the address of the first byte of graphics +; data at the current cursor position. + +setup_screen_ptr: + ldy ROWCRS ; 7D34 A4 54 + lda SAVMSC ; 7D36 A5 58 + clc ; 7D38 18 + adc row_low_offset_tab,y ; 7D39 79 52 7D + sta screen_ptr_lo ; 7D3C 85 CB + lda SAVMSC+1 ; 7D3E A5 59 + adc row_high_offset_tab,y ; 7D40 79 6A 7D + sta screen_ptr_hi ; 7D43 85 CC + lda COLCRS ; 7D45 A5 55 + lsr ; 7D47 4A + clc ; 7D48 18 + adc screen_ptr_lo ; 7D49 65 CB + bcc hi_byte_ok ; 7D4B 90 02 + inc screen_ptr_hi ; 7D4D E6 CC + +hi_byte_ok: + sta screen_ptr_lo ; 7D4F 85 CB + rts ; 7D51 60 + +; ---------------------------------------------------------------------------- +; Tables of offsets for setup_screen_ptr, to avoid doing multiplication at +; runtime (the 6502 lacks a MUL instruction, so it's slow...) + +row_low_offset_tab: + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 ; 7D52 + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 ; 7D5A + .byte $00,$40,$80,$C0,$00,$40,$80,$C0 ; 7D62 + +row_high_offset_tab: + .byte $00,$01,$02,$03,$05,$06,$07,$08 ; 7D6A + .byte $0A,$0B,$0C,$0D,$0F,$10,$11,$12 ; 7D72 + .byte $14,$15,$16,$17,$19,$1A,$1B,$1C ; 7D7A + +; ---------------------------------------------------------------------------- +; Copy pixel data from the font table to screen RAM. +; font_ptr_lo/hi must point to the correct character, and screen_ptr_lo/hi +; must point to the correct screen address for the current cursor position. +; This routine has separate execution paths for even- and odd-numbered +; cursor positions, since each byte of screen RAM holds data for two +; adjacent characters (and when printing to one of them, the other needs +; to be left undisturbed!) + +write_font_data: + lda COLCRS ; 7D82 A5 55 + clc ; 7D84 18 + ror ; 7D85 6A + bcc write_font_data_even ; 7D86 90 31 + ldx #$00 ; 7D88 A2 00 + ldy #$00 ; 7D8A A0 00 + +get_font_nybble_odd: + lda (font_ptr_lo),y ; 7D8C B1 CD + bit lo_nybble_flag ; 7D8E 2C 48 7F + bne lo_nybble_odd ; 7D91 D0 04 + ; glyph we want is stored in top 4 bits of font byte, + ; shift it down to the bottom 4 bits + lsr ; 7D93 4A + lsr ; 7D94 4A + lsr ; 7D95 4A + lsr ; 7D96 4A + +lo_nybble_odd: + eor inverse_mask ; 7D97 4D 49 7F + and #$0F ; 7D9A 29 0F + sta TMPCHR ; 7D9C 85 50 + ldy scanline_offset_tab,x ; 7D9E BC EA 7D + lda (screen_ptr_lo),y ; 7DA1 B1 CB + and #$F0 ; 7DA3 29 F0 + ora TMPCHR ; 7DA5 05 50 + sta (screen_ptr_lo),y ; 7DA7 91 CB + inx ; 7DA9 E8 + cpx #$07 ; 7DAA E0 07 + bne screen_ptr_ok_odd ; 7DAC D0 02 + inc screen_ptr_hi ; 7DAE E6 CC + +screen_ptr_ok_odd: + cpx #$08 ; 7DB0 E0 08 + beq write_font_done_odd ; 7DB2 F0 04 + txa ; 7DB4 8A + tay ; 7DB5 A8 + bne get_font_nybble_odd ; 7DB6 D0 D4 + +write_font_done_odd: + rts ; 7DB8 60 + +; ---------------------------------------------------------------------------- +; Write data to even-numbered columns, very similar to the above + +write_font_data_even: + ldx #$00 ; 7DB9 A2 00 + ldy #$00 ; 7DBB A0 00 + +get_font_nybble_even: + lda (font_ptr_lo),y ; 7DBD B1 CD + bit lo_nybble_flag ; 7DBF 2C 48 7F + beq hi_nybble_even ; 7DC2 F0 04 + asl ; 7DC4 0A + asl ; 7DC5 0A + asl ; 7DC6 0A + asl ; 7DC7 0A + +hi_nybble_even: + eor inverse_mask ; 7DC8 4D 49 7F + and #$F0 ; 7DCB 29 F0 + sta TMPCHR ; 7DCD 85 50 + ldy scanline_offset_tab,x ; 7DCF BC EA 7D + lda (screen_ptr_lo),y ; 7DD2 B1 CB + and #$0F ; 7DD4 29 0F + ora TMPCHR ; 7DD6 05 50 + sta (screen_ptr_lo),y ; 7DD8 91 CB + inx ; 7DDA E8 + cpx #$07 ; 7DDB E0 07 + bne screen_ptr_ok_even ; 7DDD D0 02 + inc screen_ptr_hi ; 7DDF E6 CC + +screen_ptr_ok_even: + cpx #$08 ; 7DE1 E0 08 + beq write_font_done_even ; 7DE3 F0 04 + txa ; 7DE5 8A + tay ; 7DE6 A8 + bne get_font_nybble_even ; 7DE7 D0 D4 + +write_font_done_even: + rts ; 7DE9 60 + +; ---------------------------------------------------------------------------- + +scanline_offset_tab: + .byte $00,$28,$50,$78,$A0,$C8,$F0,$18 ; 7DEA + +; ---------------------------------------------------------------------------- +; Callback for the internal get-one-byte, used by the OS to implement the +; CIO GET RECORD and GET BYTES commands. This routine takes no arguments, +; and returns the read byte in the accumulator. + +; Internally, COL80 maintains a line buffer. Each time col80_getbyte is +; called, it returns the next character in the buffer. If the buffer's +; empty (or if the last call returned the last character), a new line +; of input is read from the user (and the first character is returned). +; This is exactly how the OS E: device works. + +col80_getbyte: + lda BUFCNT ; 7DF2 A5 6B + beq get_line ; 7DF4 F0 0E + +get_next_byte: + ldx line_buffer_index ; 7DF6 AE 4A 7F + lda line_buffer,x ; 7DF9 BD 4B 7F + dec BUFCNT ; 7DFC C6 6B + inc line_buffer_index ; 7DFE EE 4A 7F + jmp return_success ; 7E01 4C 31 7D + +; ---------------------------------------------------------------------------- +; Get a line of input from the user, terminated by the Return key. + +get_line: + lda #$00 ; 7E04 A9 00 + sta BUFCNT ; 7E06 85 6B + sta line_buffer_index ; 7E08 8D 4A 7F + +show_cursor: + lda #$20 ; 7E0B A9 20 + sta TMPCHR ; 7E0D 85 50 + lda #$FF ; 7E0F A9 FF + sta inverse_mask ; 7E11 8D 49 7F + jsr setup_font_ptr ; 7E14 20 C9 7C + jsr setup_screen_ptr ; 7E17 20 34 7D + jsr write_font_data ; 7E1A 20 82 7D + jsr get_keystroke ; 7E1D 20 B7 7E + cpy #$01 ; 7E20 C0 01 + beq keystroke_ok ; 7E22 F0 07 + ldy #$00 ; 7E24 A0 00 + sty line_buffer_index ; 7E26 8C 4A 7F + sty BUFCNT ; 7E29 84 6B + +keystroke_ok: + cmp #$9B ; 7E2B C9 9B + bne check_backs_key ; 7E2D D0 03 + jmp return_key_hit ; 7E2F 4C 52 7E + +check_backs_key: + cmp #$7E ; 7E32 C9 7E + bne check_clear_key ; 7E34 D0 03 + jmp backs_key_hit ; 7E36 4C 71 7E + +check_clear_key: + cmp #$7D ; 7E39 C9 7D + bne normal_key_hit ; 7E3B D0 03 + jmp clear_key_hit ; 7E3D 4C 64 7E + +normal_key_hit: + ldx BUFCNT ; 7E40 A6 6B + bpl buffer_character ; 7E42 10 03 + jmp beep ; 7E44 4C 8F 7E + +buffer_character: + sta line_buffer,x ; 7E47 9D 4B 7F + jsr col80_putbyte ; 7E4A 20 43 7C + inc BUFCNT ; 7E4D E6 6B + jmp show_cursor ; 7E4F 4C 0B 7E + +return_key_hit: + jsr print_space ; 7E52 20 A4 7E + lda #$9B ; 7E55 A9 9B + ldx BUFCNT ; 7E57 A6 6B + sta line_buffer,x ; 7E59 9D 4B 7F + inc BUFCNT ; 7E5C E6 6B + jsr col80_putbyte ; 7E5E 20 43 7C + jmp get_next_byte ; 7E61 4C F6 7D + +clear_key_hit: + jsr clear_screen ; 7E64 20 0B 7D + lda #$00 ; 7E67 A9 00 + sta line_buffer_index ; 7E69 8D 4A 7F + sta BUFCNT ; 7E6C 85 6B + jmp get_line ; 7E6E 4C 04 7E + +backs_key_hit: + jsr print_space ; 7E71 20 A4 7E + lda BUFCNT ; 7E74 A5 6B + beq backs_key_done ; 7E76 F0 14 + dec COLCRS ; 7E78 C6 55 + lda COLCRS ; 7E7A A5 55 + clc ; 7E7C 18 + adc #$01 ; 7E7D 69 01 + cmp LMARGN ; 7E7F C5 52 + bne backs_same_line ; 7E81 D0 07 + lda right_margin ; 7E83 AD 00 7C + sta COLCRS ; 7E86 85 55 + dec ROWCRS ; 7E88 C6 54 + +backs_same_line: + dec BUFCNT ; 7E8A C6 6B + +backs_key_done: + jmp show_cursor ; 7E8C 4C 0B 7E + +; ---------------------------------------------------------------------------- +; Ring the margin bell. COL80 doesn't implement the ctrl-2 bell (character +; 253), and instead of using the GTIA keyclick speaker, it uses POKEY to +; make a beep + +beep: ldy #$00 ; 7E8F A0 00 + ldx #$AF ; 7E91 A2 AF + +beep_delay_x: + stx AUDF1 ; 7E93 8E 00 D2 + stx AUDC1 ; 7E96 8E 01 D2 + +beep_delay_y: + dey ; 7E99 88 + bne beep_delay_y ; 7E9A D0 FD + dex ; 7E9C CA + cpx #$9F ; 7E9D E0 9F + bne beep_delay_x ; 7E9F D0 F2 + jmp show_cursor ; 7EA1 4C 0B 7E + +; ---------------------------------------------------------------------------- +; Print a space character at the current cursor position. Does not +; update the cursor position. +print_space: + lda #$00 ; 7EA4 A9 00 + sta inverse_mask ; 7EA6 8D 49 7F + lda #$20 ; 7EA9 A9 20 + sta TMPCHR ; 7EAB 85 50 + jsr setup_font_ptr ; 7EAD 20 C9 7C + jsr setup_screen_ptr ; 7EB0 20 34 7D + jsr write_font_data ; 7EB3 20 82 7D + rts ; 7EB6 60 + +; ---------------------------------------------------------------------------- +; Get a keystroke (blocking). Just calls the OS K: get-one-byte routine +; (call by pushing address-minus-one then doing an RTS) +get_keystroke: + lda k_dev_get_hi ; 7EB7 AD 25 E4 + pha ; 7EBA 48 + lda k_dev_get_lo ; 7EBB AD 24 E4 + pha ; 7EBE 48 + rts ; 7EBF 60 + +; ---------------------------------------------------------------------------- +; Initialization callback. The OS will call this on coldstart (or would do, +; if the driver were in ROM), and also on warmstart (because we stole the +; DOSINI vector). +; This routine is also the first thing that gets called by the mainline +; init code. Its job is to install COL80 in the handler table at HATABS. +; Actually the handler is first installed as X:, then the main init code +; fixes this up to E: unless the user is holding down SELECT. This allows +; the user to toggle between the 40-column ROM E: and COL80 without doing +; a full reboot. No idea if this was a documented feature or something the +; author used for development/debugging. + +col80_init: + ldy #$00 ; 7EC0 A0 00 + +next_hatab_slot: + lda HATABS,y ; 7EC2 B9 1A 03 + beq register_x_handler ; 7EC5 F0 0A + iny ; 7EC7 C8 + iny ; 7EC8 C8 + iny ; 7EC9 C8 + cpy #$20 ; 7ECA C0 20 + bcc next_hatab_slot ; 7ECC 90 F4 + jmp return_success ; 7ECE 4C 31 7D + +register_x_handler: + lda #$58 ; 7ED1 A9 58 + sta HATABS,y ; 7ED3 99 1A 03 + lda #col80_vector_tab ; 7EDC A9 7E + iny ; 7EDE C8 + sta HATABS,y ; 7EDF 99 1A 03 + jmp return_success ; 7EE2 4C 31 7D + +; ---------------------------------------------------------------------------- +; COL80 vector table, in the format required by the OS. Our HATABS entry +; will point to this table, and the OS will call the routines listed here +; via the "call by RTS" method (which is why they're address-minus-one). + +; See the entry on HATABS in "Mapping the Atari" or the OS manual. + +col80_vector_tab: + .word col80_open-1 ; 7EE5 00 7C + .word col80_close-1 ; 7EE7 3F 7C + .word col80_getbyte-1 ; 7EE9 F1 7D + .word col80_putbyte-1 ; 7EEB 42 7C + .word col80_close-1 ; 7EED 3F 7C + .word col80_close-1 ; 7EEF 3F 7C + jmp col80_init ; 7EF1 4C C0 7E + +; ---------------------------------------------------------------------------- +; The OS jumps here on warmstart (also, this is the run address in our +; binary load file) + +dosini_entry_point: + nop ; 7EF4 EA + nop ; 7EF5 EA + nop ; 7EF6 EA + +main_entry_point: + jsr col80_init ; 7EF7 20 C0 7E + lda CONSOL ; 7EFA AD 1F D0 + and #$04 ; 7EFD 29 04 + beq no_e_handler ; 7EFF F0 2F + lda #$0C ; 7F01 A9 0C + sta ICCOM ; 7F03 8D 42 03 + ldx #$00 ; 7F06 A2 00 + jsr CIOV ; 7F08 20 56 E4 + lda #$58 ; 7F0B A9 58 + sta font_ptr_lo ; 7F0D 85 CD + lda #$03 ; 7F0F A9 03 + sta ICCOM ; 7F11 8D 42 03 + lda #$CD ; 7F14 A9 CD + sta ICBAL ; 7F16 8D 44 03 + lda #$00 ; 7F19 A9 00 + sta ICBAH ; 7F1B 8D 45 03 + ldx #$00 ; 7F1E A2 00 + jsr CIOV ; 7F20 20 56 E4 + ldy #$07 ; 7F23 A0 07 + lda #col80_vector_tab ; 7F2A A9 7E + iny ; 7F2C C8 + sta HATABS,y ; 7F2D 99 1A 03 +no_e_handler: + lda #START_ADDRESS ; 7F35 A9 7A + sta MEMTOP+1 ; 7F37 8D E6 02 + jmp return_success ; 7F3A 4C 31 7D + +; ---------------------------------------------------------------------------- +; (when does this actually get called? da65 can't find any references +; to it, and it's not a run or init address in the binary load file) + lda #dosini_entry_point ; 7F41 A9 7E + sta DOSINI+1 ; 7F43 85 0D + jmp main_entry_point ; 7F45 4C F7 7E + +; ---------------------------------------------------------------------------- +; Various bits of runtime state here. It's unclear to me why the standard +; OS buffer location couldn't have been used instead (normally the top +; half of page 5), or why the other stuff couldn't have been stored in +; zero page, in locations used by the ROM E: handler (thus unused when +; it's replaced with COL80). line_buffer_index needs to be preserved +; across calls to col80_getbyte, but lo_nybble_flag and inverse_mask are +; freshly calculated every time they're used, so they could be almost +; anywhere. + +lo_nybble_flag: + .byte $00 ; 7F48 00 + +inverse_mask: + .byte $00 ; 7F49 00 + +line_buffer_index: + .byte $12 ; 7F4A 12 + +; ---------------------------------------------------------------------------- +; There's absolutely no reason why this data needs to be included in the +; binary load file: the line buffer's initial contents are meaningless, they +; will be blown away the first time anything reads from the E: device. + +; Notice the author was running his debugger in COL80 when he built the +; binary (ASCII "S COL80 7A00 7F80" command still in the buffer). + +line_buffer: + .byte $53,$20,$43,$4F,$4C,$38,$30,$20 ; 7F4B + .byte $37,$41,$30,$30,$20,$37,$46,$38 ; 7F53 + .byte $30,$9B,$20,$20,$20,$20,$9B,$27 ; 7F5B + .byte $40,$40,$40,$40,$28,$28,$28,$28 ; 7F63 + .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 7F6B + .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 7F73 + .byte $9B,$FD,$FD,$FD,$FD,$9B ; 7F7B + +END_ADDRESS = *-1 + +; I've found a variant (modified version?) of this code, that doesn't +; include the line_buffer in the file (no reason for it to be there), +; or the $0C segment, and that has another segment, loaded at $6000, +; with the run address changed to $6000. The code looks like: + +; .org $6000 +; jsr dosini_entry_point +; lda #$50 +; sta RMARGN +; lda #$00 +; sta COLOR2 + +; also, the default colors have been changed in init_graphics_8. + +; There are at least two binaries floating around that contain +; extra (garbage) bytes at the end, presumably from being transferred +; over XMODEM or similar. They are otherwise identical. + diff --git a/src/col80_modified/cruft/col80_main.xex b/src/col80_modified/cruft/col80_main.xex new file mode 100644 index 0000000..90208c3 Binary files /dev/null and b/src/col80_modified/cruft/col80_main.xex differ diff --git a/src/col80_modified/cruft/col80_orig.xex b/src/col80_modified/cruft/col80_orig.xex new file mode 100644 index 0000000..f5f9548 Binary files /dev/null and b/src/col80_modified/cruft/col80_orig.xex differ diff --git a/src/col80_modified/cruft/col80_runad_seg.s b/src/col80_modified/cruft/col80_runad_seg.s new file mode 100644 index 0000000..234d621 --- /dev/null +++ b/src/col80_modified/cruft/col80_runad_seg.s @@ -0,0 +1,13 @@ + +; Third segment is the run address + +;.ifdef FUJICHAT +;INITAD = $02E2 +; .word INITAD +; .word INITAD+1 +; .word dosini_entry_point +;.else + .word RUNAD + .word RUNAD+1 + .word dosini_entry_point +;.endif diff --git a/src/col80_modified/cruft/col80_startaddr.s b/src/col80_modified/cruft/col80_startaddr.s new file mode 100644 index 0000000..d88203b --- /dev/null +++ b/src/col80_modified/cruft/col80_startaddr.s @@ -0,0 +1,7 @@ + + .ifdef FUJICHAT +START_ADDRESS = $9C01 ; subtract $0800 (2048) if using BASIC or other cart +;START_ADDRESS = $7A00 + .else +START_ADDRESS = $7A00 + .endif diff --git a/src/col80_modified/cruft/col80_startup.s b/src/col80_modified/cruft/col80_startup.s new file mode 100644 index 0000000..b170a3c --- /dev/null +++ b/src/col80_modified/cruft/col80_startup.s @@ -0,0 +1,4 @@ + + .include "col80_include.s" + .include "col80_init.s" + .include "col80_entry.s" diff --git a/src/col80_modified/cruft/dasm2atasm b/src/col80_modified/cruft/dasm2atasm new file mode 100755 index 0000000..b7ebe66 --- /dev/null +++ b/src/col80_modified/cruft/dasm2atasm @@ -0,0 +1,362 @@ +#!/usr/bin/perl -w + +=head1 NAME + +dasm2atasm - converts 6502 assembly in DASM syntax to ATASM (or MAC/65) format. + +=head1 SYNOPSIS + + dasm2atasm mycode.asm + +Writes output to I + + dasm2atasm stuff.asm other.m65 + +Reads from I, writes to I + +=head1 DESCRIPTION + +B tries its best to convert DASM's syntax into something +that B can use. Since B's syntax is 99% compatible with +that of B, B can be used for that as well. + +=head1 CAVEATS + +There are a few B directives that aren't quite supported by +B. + +=over 4 + +=item echo + +In B syntax, I can interpolate values, like so: + + echo $100-*, " bytes of zero page left" + +B's closest equivalent to I is I<.warn>, but it doesn't +allow multiple arguments or interpolation. For now, B just +comments out the line with the I directive. + +=item seg and seg.u + +B just plain doesn't support segments. These directives will +just be commented out. This I have any effect on the +object code. + +=item sta.w, sty.w, stx.w + +B doesn't provide a way to force word addressing, when the operand +of a store instruction will allow zero page addressing to be used. You'll +run into this a lot in Atari 2600 code, or any other 6502 code that has to +maintain sync with an external piece of hardware (using word addressing +causes the 6502 to use an extra CPU cycle, which is the only way to cause +a 1-cycle delay). + +For now, we're just converting any I instructions to the appropriate +I<.byte> directives, like so: + + ;;;;; dasm2atasm: was `sta.w COLUPF', using .byte to generate opcode + .byte $8d, COLUPF, $00 + +This works fine if I is a zero-page label. It's possible, though +unlikely, that you'll run across code where the programmer has used I +with a label that would already cause absolute word addressing to be used, +in which case the extra I<$00> will break our code (literally: I<$00> is +the I instruction!) + +This isn't likely to be fixed by I. The correct fix will be to +support I and friends in B itself, which may happen in the +future. + +=item . (dot) + +B allows the use of I<.> or I<*> to represent the current program counter +in expressions. B only allows I<*>, and unless I want to include a +full expression-parser in B, I can't reliably translate this. + +For now, you'll have to fix this yourself. Future versions will at least +make an attempt, but this one doesn't. + +=back + +=head1 AUTHOR + +B. Watson I<< >>. Comments & constructive criticism +welcome, or just a friendly `hello'. Spam will be redirected to /dev/null +and so will the spammer's entire domain. + +=cut + +sub usage { + print </g; # inequality + + s/^(\s+)\.?echo(.*)/;;;;;$1.warn$2/i && + do { warn "$in, line $.:\n\t`.warn' not fully compatible with dasm's `echo', commented out\n" } + && next; + + # This is supposed to change e.g. `bpl .label' to `bpl @label' + s/^(\s+)([a-z]{3})(\s+)\.(\w+)/$1$2$3\@$4/i + && next; + + + s/{(\d)}/%$1/g; # macro arg (gotta do this *after* bin. constants!) + +# atasm doesn't support shifts, emulate with multiply/divide + s/\s*<<\s*(\d+)/"*" . 2**$1/eg; + s/\s*>>\s*(\d+)/"\/" . 2**$1/eg; + +# atasm chokes sometimes when there's whitespace around an operator +# unfortunately, a construct like `bne *-1' can't afford to lose the +# space before the *... why, oh why, does * have to be both multiply and +# program counter? *sigh* + +# s/\s*([-!|\/+*&])\s*/$1/g; + +# ARGH. Why does dasm allow `byte #1, #2, #3'... and why do people *use* it?! + s/^(\s+)\.?byte(\s+)/$1.byte$2/i && do { s/#//g } && next; + s/^(\s+)\.?word(\s+)/$1.word$2/i && do { s/#//g } && next; + s/^(\s+)\.?dc\.w(\s+)/$1.word$2/i && do { s/#//g } && next; + s/^(\s+)\.?dc(?:\.b)?(\s+)/$1.byte$2/i && do { s/#//g } && next; + +# 20070529 bkw: turn ".DS foo" into ".DC foo 0" + s/^(\s+)\.?ds(\s+)(\S+)/$1.dc $3 0 /i && do { s/#//g } && next; + +# I really want to add `hex' to atasm. 'til then though, fake with .byte + s/^(\s+)\.?hex\s+(.*)/$1 . '.byte ' . + unhex($2)/ie && next; + + s/^(\s+)\.?subroutine(.*)/$1.local$2/i && next; + s/^(\s+)\.?include(\s+)(.*)/$1 . '.include' . $2 . fix_include($3)/gie + && next; + s/^(\s+)\.?equ\b/$1=/i && next; + s/^(\s+)\.?repeat\b/$1.rept/i && next; + s/^(\s+)\.?repend\b/$1.endr/i && next; + s/^(\s+)\.?endm\b/$1.endm/i && next; + s/^(\s+)\.?org(\s+)([^,]*).*$/$1*=$2$3/i && next; + s/^(\s+)\.?incbin\b/$1\.incbin/i && next; + s/^(\s+)\.?err(.*)/$1.error$2/i && next; # TODO: see if atasm allows `.error' with no message. + s/^(\s+)\.?ifconst\s+(.*)/$1.if .def $2/i + && next; # TODO: test this! + s/^(\s+)\.?else/$1.else/i && next; + s/^(\s+)\.?endif/$1.endif/i && next; + s/^(\s+)\.?if\s+(.*)/$1.if $2/i && next; + + # stuff that doesn't work: + s/^(\s+)(\.?seg(\..)?\s.*)/;;;;; dasm2atasm: `seg' not supported by atasm\n;;;;;$1$2/i + && next; + s/^(\s+)(\.?processor\s.*)/;;;;; dasm2atasm: `processor' not supported by atasm\n;;;;;$1$2/i + && next; + + s/^(\s+)sta\.w(\s+)(.*)/;;;;; dasm2atasm: was `sta.w $3', using .byte to generate opcode\n$1.byte \$8d, <$3, >$3/i + && next; + + s/^(\s+)stx\.w(\s+)(.*)/;;;;; dasm2atasm: was `stx.w $3', using .byte to generate opcode\n$1.byte \$8e, <$3, >$3/i + && next; + + s/^(\s+)sta\.w(\s+)(.*)/;;;;; dasm2atasm: was `sty.w $3', using .byte to generate opcode\n$1.byte \$8c, <$3, >$3/i + && next; + + # atasm lacks `align', so make up for it with a macro + if(s/(\s)\.?align(\s+)(.*)/$1ALIGN$2$3/i) { + if(!$align_defined) { # only gotta define it if not already defined. + for($align_macro) { + $_ =~ s/^/($linenum += 10) . " "/gme if $linenum; + $_ =~ s/\n/\x9b/g if $a8eol; + } + + print OUT $align_macro; # no, I wouldn't use these globals in a CS class assignment. + $align_defined++; + } + next; + } + + # macros. This is by far the biggest pain in the ass yet. + s/(\s)\.?mac\b/$1.macro/i; + if(/(\s)\.macro(\s+)(\w+)/) { + $mac_regex .= "|\\b$3\\b"; + $mac_sub = get_mac_sub($mac_regex); + } + + if(ref $mac_sub) { # if we've found at least one macro so far... + &$mac_sub; # CAPITALIZE everything matching a macro name + } # note: this code assumes macros are *always* defined before they're + # used. atasm requires this, but does dasm? + + } + return $line; +} + +## main() ## + +$ca65 = 0; +$a8eol = 0; +$linenum = 0; +$recursive = 0; + +$cmd = $0; + +while($ARGV[0] =~ /^-/i) { + my $opt = shift; + $cmd .= " $opt"; + + if($opt eq "-c") { + $ca65++; + } elsif($opt eq "-a") { + $a8eol++; + } elsif($opt eq "-l") { + $linenum = 1000; + } elsif($opt eq "-m") { + $a8eol++; + $linenum = 1000; + } elsif($opt eq "-r") { + $recursive++; + } elsif($opt eq "--") { + last; + } else { + warn "Unknown option '$opt'\n"; + usage; + } +} + +if($ca65 && ($linenum || $a8eol)) { + die "Can't use line numbers and/or Atari EOLs with ca65 output\n"; +} + +$align_macro = <$out" or die "Can't write to $out: $!\n"; + +$hdr = <) { + chomp; + s/\r//; # you might not want this on dos/win, not sure if it matters. + $label = ""; + + if(/^(\w+)\s*=\s*\1/i) { + print OUT ";;;;; dasm2atasm: labels are case-insensitive in atasm\n"; + $line = ";;;;; $_ ; This assignment is an error in atasm"; + next; + } + +# do this before we split out the label: + s/^\./\@/; # local label (dot in dasm, @ in atasm) + + if(s/^([^:;\s]*):?(\s+)/$2/) { + $label = $1; + } + + ($line, $comment) = split /;/, $_, 2; + next unless $line; + + $line = do_subs($line); + +} continue { + if($linenum) { + print OUT "$linenum "; + $linenum += 10; + } + + print OUT $label if $label; + print OUT $line if $line; + print OUT ";$comment" if $comment; + print OUT ($a8eol ? "\x9b" : "\n"); +} diff --git a/src/col80_modified/cruft/dos_20s.atr b/src/col80_modified/cruft/dos_20s.atr new file mode 100755 index 0000000..8016b73 Binary files /dev/null and b/src/col80_modified/cruft/dos_20s.atr differ diff --git a/src/col80_modified/cruft/font.bin b/src/col80_modified/cruft/font.bin new file mode 100644 index 0000000..d2fd3d4 Binary files /dev/null and b/src/col80_modified/cruft/font.bin differ diff --git a/src/col80_modified/cruft/font.s b/src/col80_modified/cruft/font.s new file mode 100644 index 0000000..78266ea --- /dev/null +++ b/src/col80_modified/cruft/font.s @@ -0,0 +1,54 @@ + .org 1000 + ; Space ! " # etc (codes 32-63) + .byte $00,$04,$04,$04,$04,$00,$04,$00 + .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00 + .byte $00,$40,$68,$82,$44,$28,$C2,$40 + .byte $00,$C4,$64,$E4,$60,$C0,$40,$00 + .byte $00,$44,$82,$82,$82,$82,$82,$44 + .byte $00,$04,$A4,$4E,$E4,$44,$A0,$00 + .byte $00,$00,$00,$0E,$00,$40,$40,$80 + .byte $00,$02,$02,$04,$04,$08,$48,$00 + .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00 + .byte $00,$EE,$22,$22,$EE,$82,$EE,$00 + .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00 + .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00 + .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00 + .byte $00,$00,$00,$44,$00,$44,$04,$08 + .byte $00,$20,$4E,$80,$4E,$20,$00,$00 + .byte $00,$8C,$42,$22,$44,$80,$04,$00 + + ; @ A B C etc (codes 64-95) + .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00 + .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00 + .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00 + .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00 + .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00 + .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00 + .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00 + .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00 + .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03 + .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00 + .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00 + .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00 + .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00 + .byte $00,$EE,$28,$48,$88,$88,$E8,$0E + .byte $00,$8E,$82,$42,$42,$22,$22,$0E + .byte $00,$00,$40,$A0,$00,$00,$00,$0F + + ; diamond, lowercase letters, control codes (codes 96-127) + .byte $00,$00,$00,$46,$E2,$4E,$0E,$00 + .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00 + .byte $00,$20,$20,$6E,$AE,$A8,$6E,$00 + .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C + .byte $00,$80,$84,$80,$C4,$A4,$A4,$00 + .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0 + .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00 + .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00 + .byte $00,$00,$00,$C6,$AA,$C6,$82,$82 + .byte $00,$00,$00,$6E,$88,$86,$8E,$00 + .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00 + .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00 + .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C + .byte $00,$00,$04,$EE,$4E,$84,$EE,$00 + .byte $40,$4E,$4C,$4E,$4A,$42,$42,$40 + .byte $00,$28,$6C,$EE,$6C,$28,$00,$00 diff --git a/src/col80_modified/cruft/font2xbm.pl b/src/col80_modified/cruft/font2xbm.pl new file mode 100644 index 0000000..3337139 --- /dev/null +++ b/src/col80_modified/cruft/font2xbm.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use bytes; + +$name = "xbm"; +$width = 8; +$height = 384; +$cwidth = $width / 8; +$cheight = $height / 8; + +print <; +@inbytes = split ""; + +# reverse bits, print 12 bytes/line + +$c = 0; +for($i=0; $i<@inbytes; $i++) { + $byte = ord $inbytes[$i]; + if(!$c) { + print " "; + } + + printf "0x%02x", reverse_bits($byte); + if($i != $#inbytes) { + if($c == 12) { + print ",\n"; + $c = 0; + } else { + print ", "; + $c++; + } + } +} + +print " };\n"; + +sub reverse_bits { + my $bitstr = reverse sprintf("%08b", $_[0]); + return eval "0b$bitstr"; +} diff --git a/src/col80_modified/cruft/new_font.s b/src/col80_modified/cruft/new_font.s new file mode 100644 index 0000000..f70ae8b --- /dev/null +++ b/src/col80_modified/cruft/new_font.s @@ -0,0 +1,48 @@ + .byte $00,$04,$04,$04,$04,$00,$04,$00 + .byte $00,$A0,$AA,$AE,$0A,$0E,$0A,$00 + .byte $00,$40,$68,$82,$44,$28,$C2,$40 + .byte $00,$44,$E4,$84,$60,$80,$E0,$40 + .byte $00,$44,$82,$82,$82,$82,$82,$44 + .byte $00,$00,$A4,$44,$EE,$44,$A4,$00 + .byte $00,$00,$00,$0E,$00,$40,$40,$80 + .byte $00,$02,$02,$04,$04,$08,$48,$00 + .byte $00,$E4,$AC,$A4,$A4,$A4,$EE,$00 + .byte $00,$EE,$22,$22,$EE,$82,$EE,$00 + .byte $00,$AE,$A8,$AE,$E2,$22,$2E,$00 + .byte $00,$EE,$82,$E2,$A4,$A4,$E4,$00 + .byte $00,$EE,$AA,$EA,$AE,$A2,$EE,$00 + .byte $00,$00,$00,$44,$00,$44,$04,$08 + .byte $00,$20,$4E,$80,$4E,$20,$00,$00 + .byte $00,$8C,$42,$22,$44,$80,$04,$00 + .byte $00,$6E,$9A,$BA,$BE,$8A,$6A,$00 + .byte $00,$C6,$A8,$C8,$A8,$A8,$C6,$00 + .byte $00,$CE,$A8,$AC,$A8,$A8,$CE,$00 + .byte $00,$E6,$88,$C8,$8A,$8A,$86,$00 + .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00 + .byte $00,$2A,$2A,$2C,$2A,$2A,$CA,$00 + .byte $00,$8A,$8E,$8E,$8A,$8A,$EA,$00 + .byte $00,$C4,$AA,$AA,$AA,$AA,$A4,$00 + .byte $00,$EE,$AA,$EA,$8A,$8A,$8E,$03 + .byte $00,$C6,$A8,$AC,$C2,$A2,$AC,$00 + .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00 + .byte $00,$AA,$AA,$AA,$AE,$AE,$4A,$00 + .byte $00,$AA,$4A,$4E,$44,$44,$A4,$00 + .byte $00,$EE,$28,$48,$88,$88,$E8,$0E + .byte $00,$8E,$82,$42,$42,$22,$22,$0E + .byte $00,$00,$40,$A0,$00,$00,$00,$0F + .byte $00,$00,$0C,$42,$E6,$4A,$0E,$00 + .byte $00,$80,$80,$C6,$A8,$A8,$C6,$00 + .byte $00,$20,$26,$6A,$AE,$A8,$6E,$00 + .byte $00,$00,$C0,$86,$CA,$8E,$82,$0C + .byte $00,$80,$84,$80,$C4,$A4,$A4,$00 + .byte $00,$08,$28,$0A,$2C,$2A,$2A,$C0 + .byte $00,$40,$40,$4A,$4E,$4A,$4A,$00 + .byte $00,$00,$00,$CE,$AA,$AA,$AE,$00 + .byte $00,$00,$00,$C6,$AA,$C6,$82,$83 + .byte $00,$00,$00,$6E,$88,$86,$8E,$00 + .byte $00,$00,$40,$EA,$4A,$4A,$6E,$00 + .byte $00,$00,$00,$AA,$AA,$AE,$4A,$00 + .byte $00,$00,$00,$AA,$4A,$A6,$A2,$0C + .byte $00,$06,$04,$E4,$48,$84,$E4,$06 + .byte $40,$4C,$44,$44,$42,$44,$44,$4C + .byte $00,$08,$5C,$AE,$0C,$08,$00,$00 diff --git a/src/col80_modified/cruft/new_font.xbm b/src/col80_modified/cruft/new_font.xbm new file mode 100644 index 0000000..a7fab38 --- /dev/null +++ b/src/col80_modified/cruft/new_font.xbm @@ -0,0 +1,35 @@ +#define font_width 8 +#define font_height 384 +static unsigned char font_bits[] = { + 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, 0x05, 0x55, 0x75, + 0x50, 0x70, 0x50, 0x00, 0x00, 0x02, 0x16, 0x41, 0x22, 0x14, 0x43, 0x02, + 0x00, 0x22, 0x27, 0x21, 0x06, 0x01, 0x07, 0x02, 0x00, 0x22, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x22, 0x00, 0x00, 0x25, 0x22, 0x77, 0x22, 0x25, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, 0x02, 0x01, 0x00, 0x40, 0x40, 0x20, + 0x20, 0x10, 0x12, 0x00, 0x00, 0x27, 0x35, 0x25, 0x25, 0x25, 0x77, 0x00, + 0x00, 0x77, 0x44, 0x44, 0x77, 0x41, 0x77, 0x00, 0x00, 0x75, 0x15, 0x75, + 0x47, 0x44, 0x74, 0x00, 0x00, 0x77, 0x41, 0x47, 0x25, 0x25, 0x27, 0x00, + 0x00, 0x77, 0x55, 0x57, 0x75, 0x45, 0x77, 0x00, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x22, 0x20, 0x10, 0x00, 0x04, 0x72, 0x01, 0x72, 0x04, 0x00, 0x00, + 0x00, 0x31, 0x42, 0x44, 0x22, 0x01, 0x20, 0x00, 0x00, 0x76, 0x59, 0x5d, + 0x7d, 0x51, 0x56, 0x00, 0x00, 0x63, 0x15, 0x13, 0x15, 0x15, 0x63, 0x00, + 0x00, 0x73, 0x15, 0x35, 0x15, 0x15, 0x73, 0x00, 0x00, 0x67, 0x11, 0x13, + 0x51, 0x51, 0x61, 0x00, 0x00, 0x75, 0x25, 0x27, 0x25, 0x25, 0x75, 0x00, + 0x00, 0x54, 0x54, 0x34, 0x54, 0x54, 0x53, 0x00, 0x00, 0x51, 0x71, 0x71, + 0x51, 0x51, 0x57, 0x00, 0x00, 0x23, 0x55, 0x55, 0x55, 0x55, 0x25, 0x00, + 0x00, 0x77, 0x55, 0x57, 0x51, 0x51, 0x71, 0xc0, 0x00, 0x63, 0x15, 0x35, + 0x43, 0x45, 0x35, 0x00, 0x00, 0x57, 0x52, 0x52, 0x52, 0x52, 0x72, 0x00, + 0x00, 0x55, 0x55, 0x55, 0x75, 0x75, 0x52, 0x00, 0x00, 0x55, 0x52, 0x72, + 0x22, 0x22, 0x25, 0x00, 0x00, 0x77, 0x14, 0x12, 0x11, 0x11, 0x17, 0x70, + 0x00, 0x71, 0x41, 0x42, 0x42, 0x44, 0x44, 0x70, 0x00, 0x00, 0x02, 0x05, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x30, 0x42, 0x67, 0x52, 0x70, 0x00, + 0x00, 0x01, 0x01, 0x63, 0x15, 0x15, 0x63, 0x00, 0x00, 0x04, 0x64, 0x56, + 0x75, 0x15, 0x76, 0x00, 0x00, 0x00, 0x03, 0x61, 0x53, 0x71, 0x41, 0x30, + 0x00, 0x01, 0x21, 0x01, 0x23, 0x25, 0x25, 0x00, 0x00, 0x10, 0x14, 0x50, + 0x34, 0x54, 0x54, 0x03, 0x00, 0x02, 0x02, 0x52, 0x72, 0x52, 0x52, 0x00, + 0x00, 0x00, 0x00, 0x73, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x63, + 0x55, 0x63, 0x41, 0xc1, 0x00, 0x00, 0x00, 0x76, 0x11, 0x61, 0x71, 0x00, + 0x00, 0x00, 0x02, 0x57, 0x52, 0x52, 0x76, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x55, 0x75, 0x52, 0x00, 0x00, 0x00, 0x00, 0x55, 0x52, 0x65, 0x45, 0x30, + 0x00, 0x60, 0x20, 0x27, 0x12, 0x21, 0x27, 0x60, 0x02, 0x32, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x32, 0x00, 0x10, 0x3a, 0x75, 0x30, 0x10, 0x00, 0x00 }; diff --git a/src/col80_modified/cruft/test.atr b/src/col80_modified/cruft/test.atr new file mode 100755 index 0000000..0127b33 Binary files /dev/null and b/src/col80_modified/cruft/test.atr differ diff --git a/src/col80_modified/cruft/xbm2font.pl b/src/col80_modified/cruft/xbm2font.pl new file mode 100644 index 0000000..758d57e --- /dev/null +++ b/src/col80_modified/cruft/xbm2font.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +use bytes; + +$c = 0; + +while(<>) { + next unless @bytes = (/0x([0-9a-fA-F]{2})/g); + for(@bytes) { + if(!($c % 8)) { + print " .byte "; + } + + printf "\$%02X", reverse_bits(hex $_); + + if(($c % 8 == 7) || ($c == $#bytes)) { + print "\n"; + $c = 0; + } else { + print ","; + $c++; + } + } +} + +sub reverse_bits { + my $bitstr = reverse sprintf("%08b", $_[0]); + return eval "0b$bitstr"; +} diff --git a/src/col80_modified/dos_20s.atr b/src/col80_modified/dos_20s.atr new file mode 100755 index 0000000..8016b73 Binary files /dev/null and b/src/col80_modified/dos_20s.atr differ diff --git a/src/col80_modified/font2xbm.pl b/src/col80_modified/font2xbm.pl new file mode 100644 index 0000000..c0ec3be --- /dev/null +++ b/src/col80_modified/font2xbm.pl @@ -0,0 +1,48 @@ +#!/usr/bin/perl -w + +use bytes; + +$name = "xbm"; +$width = 8; +$height = 384; +#$height = 512; +$cwidth = $width / 8; +$cheight = $height / 8; + +print <; +@inbytes = split ""; + +# reverse bits, print 12 bytes/line + +$c = 0; +for($i=0; $i<@inbytes; $i++) { + $byte = ord $inbytes[$i]; + if(!$c) { + print " "; + } + + printf "0x%02x", reverse_bits($byte); + if($i != $#inbytes) { + if($c == 12) { + print ",\n"; + $c = 0; + } else { + print ", "; + $c++; + } + } +} + +print " };\n"; + +sub reverse_bits { + my $bitstr = reverse sprintf("%08b", $_[0]); + return eval "0b$bitstr"; +} diff --git a/src/col80_modified/icet.xbm b/src/col80_modified/icet.xbm new file mode 100644 index 0000000..946753b --- /dev/null +++ b/src/col80_modified/icet.xbm @@ -0,0 +1,43 @@ +#define xbm_width 8 +#define xbm_height 512 +static unsigned char xbm_bits[] = { + 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, 0x55, 0x75, 0x50, 0x70, + 0x50, 0x00, 0x00, 0x02, 0x16, 0x41, 0x22, 0x14, 0x43, 0x02, 0x00, 0x00, 0x42, + 0x25, 0x02, 0x05, 0x02, 0x04, 0x00, 0x00, 0x14, 0x22, 0x22, 0x22, 0x22, 0x14, + 0x00, 0x00, 0x25, 0x22, 0x77, 0x22, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x02, 0x01, 0x00, 0x40, 0x40, 0x20, 0x20, 0x12, 0x12, 0x00, 0x00, + 0x22, 0x35, 0x25, 0x25, 0x25, 0x72, 0x00, 0x00, 0x32, 0x45, 0x34, 0x42, 0x41, + 0x37, 0x00, 0x00, 0x75, 0x15, 0x35, 0x46, 0x44, 0x34, 0x00, 0x00, 0x72, 0x41, + 0x23, 0x25, 0x15, 0x12, 0x00, 0x00, 0x22, 0x55, 0x52, 0x65, 0x45, 0x22, 0x00, + 0x00, 0x00, 0x22, 0x00, 0x20, 0x22, 0x10, 0x00, 0x00, 0x04, 0x72, 0x01, 0x72, + 0x04, 0x00, 0x00, 0x00, 0x21, 0x52, 0x44, 0x22, 0x01, 0x20, 0x00, 0x00, 0x22, + 0x57, 0x57, 0x75, 0x51, 0x56, 0x00, 0x00, 0x63, 0x15, 0x13, 0x15, 0x15, 0x67, + 0x00, 0x00, 0x73, 0x15, 0x75, 0x15, 0x15, 0x73, 0x00, 0x00, 0x67, 0x11, 0x17, + 0x51, 0x51, 0x61, 0x00, 0x00, 0x75, 0x25, 0x27, 0x25, 0x25, 0x75, 0x00, 0x00, + 0x56, 0x54, 0x34, 0x54, 0x55, 0x52, 0x00, 0x00, 0x51, 0x71, 0x51, 0x51, 0x51, + 0x57, 0x00, 0x00, 0x74, 0x55, 0x57, 0x57, 0x55, 0x71, 0x00, 0x00, 0x73, 0x55, + 0x55, 0x53, 0x71, 0x41, 0x00, 0x00, 0x63, 0x15, 0x23, 0x45, 0x45, 0x35, 0x00, + 0x00, 0x57, 0x52, 0x52, 0x52, 0x52, 0x72, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, + 0x72, 0x52, 0x00, 0x00, 0x55, 0x55, 0x52, 0x22, 0x25, 0x25, 0x00, 0x00, 0x67, + 0x24, 0x22, 0x21, 0x21, 0x67, 0x00, 0x00, 0x31, 0x21, 0x22, 0x22, 0x24, 0x34, + 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x70, 0x00, 0x25, 0x2a, 0x25, 0xea, + 0x25, 0x2a, 0x25, 0x2a, 0x28, 0x28, 0x28, 0x38, 0x08, 0x08, 0x08, 0x08, 0x02, + 0x02, 0x02, 0x33, 0x22, 0x22, 0x22, 0x22, 0x00, 0x22, 0x52, 0x27, 0x07, 0x02, + 0x02, 0x00, 0x00, 0x42, 0x27, 0x12, 0x20, 0x47, 0x70, 0x00, 0x00, 0x01, 0xf2, + 0x54, 0x52, 0x51, 0x57, 0x00, 0x00, 0x24, 0x37, 0x22, 0x77, 0x21, 0x70, 0x00, + 0xf0, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe0, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x00, 0x01, 0x01, 0x01, 0xf1, 0x21, 0x21, 0x21, + 0x21, 0x02, 0x02, 0x02, 0x0f, 0x00, 0x00, 0x00, 0xf0, 0xa2, 0xd2, 0xf2, 0xde, + 0x00, 0x10, 0x10, 0x50, 0x00, 0x00, 0x18, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x08, 0x4c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x40, 0x70, 0x50, + 0x70, 0x00, 0x00, 0x01, 0x61, 0x13, 0x15, 0x15, 0x63, 0x00, 0x00, 0x04, 0x24, + 0x56, 0x75, 0x15, 0x66, 0x00, 0x00, 0x06, 0x61, 0x57, 0x51, 0x61, 0x41, 0x30, + 0x00, 0x21, 0x01, 0x33, 0x25, 0x25, 0x65, 0x00, 0x00, 0x14, 0x10, 0x54, 0x34, + 0x54, 0x54, 0x03, 0x00, 0x03, 0x52, 0x72, 0x52, 0x52, 0x56, 0x00, 0x00, 0x00, + 0x23, 0x55, 0x55, 0x55, 0x25, 0x00, 0x00, 0x00, 0x63, 0x55, 0x55, 0x63, 0x41, + 0x41, 0x00, 0x00, 0x66, 0x11, 0x21, 0x41, 0x31, 0x00, 0x00, 0x02, 0x57, 0x52, + 0x52, 0x52, 0x76, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x72, 0x52, 0x00, 0x00, + 0x00, 0x55, 0x55, 0x52, 0x65, 0x45, 0x30, 0x00, 0x60, 0x27, 0x14, 0x22, 0x21, + 0x67, 0x00, 0x02, 0x32, 0x22, 0x42, 0x22, 0x22, 0x32, 0x02, 0x0f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x0f }; diff --git a/src/col80_modified/icet_packed.fnt b/src/col80_modified/icet_packed.fnt new file mode 100644 index 0000000..2b599b8 Binary files /dev/null and b/src/col80_modified/icet_packed.fnt differ diff --git a/src/col80_modified/icet_to_col80 b/src/col80_modified/icet_to_col80 new file mode 100755 index 0000000..9dac02c Binary files /dev/null and b/src/col80_modified/icet_to_col80 differ diff --git a/src/col80_modified/icet_to_col80.c b/src/col80_modified/icet_to_col80.c new file mode 100644 index 0000000..aa07223 --- /dev/null +++ b/src/col80_modified/icet_to_col80.c @@ -0,0 +1,26 @@ +#include + +int main(int argc, char **argv) { + int c, d, byte = 0; + char out[8]; + + do { + c = getchar(); + if(byte == 16) { + for(byte = 0; byte < 8; ++byte) + putchar(out[byte]); + + byte = 0; + } + + if(c != EOF) { + if(byte < 8) { + out[byte] = (c & 0xf0); + ++byte; + } else if(byte < 16) { + out[byte - 8] |= (c & 0x0f); + ++byte; + } + } + } while(c != EOF); +} diff --git a/src/col80_modified/icet_vt.fnt b/src/col80_modified/icet_vt.fnt new file mode 100644 index 0000000..7c29cd1 Binary files /dev/null and b/src/col80_modified/icet_vt.fnt differ diff --git a/src/col80_modified/icetmod.raw b/src/col80_modified/icetmod.raw new file mode 100644 index 0000000..59e1331 Binary files /dev/null and b/src/col80_modified/icetmod.raw differ diff --git a/src/col80_modified/icetmod.s b/src/col80_modified/icetmod.s new file mode 100644 index 0000000..0c11274 --- /dev/null +++ b/src/col80_modified/icetmod.s @@ -0,0 +1,48 @@ + .byte $00,$02,$02,$02,$02,$00,$02,$00 + .byte $00,$55,$57,$05,$07,$05,$00,$00 + .byte $20,$34,$41,$22,$14,$61,$20,$00 + .byte $20,$31,$42,$30,$40,$30,$20,$00 + .byte $00,$14,$22,$22,$22,$22,$14,$00 + .byte $00,$52,$22,$77,$22,$52,$00,$00 + .byte $00,$00,$00,$07,$00,$20,$20,$40 + .byte $00,$01,$01,$02,$02,$24,$24,$00 + .byte $00,$22,$56,$52,$52,$52,$27,$00 + .byte $00,$26,$51,$16,$21,$41,$76,$00 + .byte $00,$57,$54,$56,$31,$11,$16,$00 + .byte $00,$27,$41,$62,$52,$54,$24,$00 + .byte $00,$22,$55,$25,$53,$51,$22,$00 + .byte $00,$00,$22,$00,$02,$22,$04,$00 + .byte $00,$10,$27,$40,$27,$10,$00,$00 + .byte $00,$42,$25,$11,$22,$40,$02,$00 + .byte $00,$22,$75,$75,$57,$45,$35,$00 + .byte $00,$63,$54,$64,$54,$54,$73,$00 + .byte $00,$67,$54,$57,$54,$54,$67,$00 + .byte $00,$73,$44,$74,$45,$45,$43,$00 + .byte $00,$57,$52,$72,$52,$52,$57,$00 + .byte $00,$35,$15,$16,$15,$55,$25,$00 + .byte $00,$4A,$4F,$4F,$49,$49,$79,$00 + .byte $00,$67,$55,$55,$55,$55,$57,$00 + .byte $00,$67,$55,$55,$65,$47,$41,$00 + .byte $00,$63,$54,$62,$51,$51,$56,$00 + .byte $00,$75,$25,$25,$25,$25,$27,$00 + .byte $00,$59,$59,$59,$5F,$2F,$2A,$00 + .byte $00,$55,$55,$25,$22,$52,$52,$00 + .byte $00,$73,$12,$22,$42,$42,$73,$00 + .byte $00,$46,$42,$22,$22,$12,$16,$00 + .byte $00,$20,$50,$00,$00,$00,$07,$00 + .byte $00,$20,$16,$01,$07,$05,$07,$00 + .byte $00,$40,$43,$64,$54,$54,$63,$00 + .byte $00,$10,$12,$35,$57,$54,$33,$00 + .byte $00,$30,$43,$75,$45,$43,$41,$06 + .byte $00,$42,$40,$66,$52,$52,$53,$00 + .byte $00,$14,$04,$15,$16,$15,$15,$60 + .byte $00,$60,$25,$27,$25,$25,$35,$00 + .byte $00,$00,$62,$55,$55,$55,$52,$00 + .byte $00,$00,$63,$55,$55,$63,$41,$41 + .byte $00,$00,$33,$44,$42,$41,$46,$00 + .byte $00,$20,$75,$25,$25,$25,$37,$00 + .byte $00,$00,$55,$55,$55,$27,$25,$00 + .byte $00,$00,$55,$55,$25,$53,$51,$06 + .byte $00,$03,$72,$14,$22,$42,$73,$00 + .byte $20,$26,$22,$21,$22,$22,$26,$20 + .byte $07,$01,$54,$A1,$04,$01,$04,$07 diff --git a/src/col80_modified/icetmod.xbm b/src/col80_modified/icetmod.xbm new file mode 100644 index 0000000..fb61a13 --- /dev/null +++ b/src/col80_modified/icetmod.xbm @@ -0,0 +1,35 @@ +#define icetmod_width 8 +#define icetmod_height 384 +static unsigned char icetmod_bits[] = { + 0x00, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, 0x00, 0xaa, 0xea, 0xa0, + 0xe0, 0xa0, 0x00, 0x00, 0x04, 0x2c, 0x82, 0x44, 0x28, 0x86, 0x04, 0x00, + 0x04, 0x8c, 0x42, 0x0c, 0x02, 0x0c, 0x04, 0x00, 0x00, 0x28, 0x44, 0x44, + 0x44, 0x44, 0x28, 0x00, 0x00, 0x4a, 0x44, 0xee, 0x44, 0x4a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x04, 0x04, 0x02, 0x00, 0x80, 0x80, 0x40, + 0x40, 0x24, 0x24, 0x00, 0x00, 0x44, 0x6a, 0x4a, 0x4a, 0x4a, 0xe4, 0x00, + 0x00, 0x64, 0x8a, 0x68, 0x84, 0x82, 0x6e, 0x00, 0x00, 0xea, 0x2a, 0x6a, + 0x8c, 0x88, 0x68, 0x00, 0x00, 0xe4, 0x82, 0x46, 0x4a, 0x2a, 0x24, 0x00, + 0x00, 0x44, 0xaa, 0xa4, 0xca, 0x8a, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x40, 0x44, 0x20, 0x00, 0x00, 0x08, 0xe4, 0x02, 0xe4, 0x08, 0x00, 0x00, + 0x00, 0x42, 0xa4, 0x88, 0x44, 0x02, 0x40, 0x00, 0x00, 0x44, 0xae, 0xae, + 0xea, 0xa2, 0xac, 0x00, 0x00, 0xc6, 0x2a, 0x26, 0x2a, 0x2a, 0xce, 0x00, + 0x00, 0xe6, 0x2a, 0xea, 0x2a, 0x2a, 0xe6, 0x00, 0x00, 0xce, 0x22, 0x2e, + 0xa2, 0xa2, 0xc2, 0x00, 0x00, 0xea, 0x4a, 0x4e, 0x4a, 0x4a, 0xea, 0x00, + 0x00, 0xac, 0xa8, 0x68, 0xa8, 0xaa, 0xa4, 0x00, 0x00, 0x52, 0xf2, 0xf2, + 0x92, 0x92, 0x9e, 0x00, 0x00, 0xe6, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x00, + 0x00, 0xe6, 0xaa, 0xaa, 0xa6, 0xe2, 0x82, 0x00, 0x00, 0xc6, 0x2a, 0x46, + 0x8a, 0x8a, 0x6a, 0x00, 0x00, 0xae, 0xa4, 0xa4, 0xa4, 0xa4, 0xe4, 0x00, + 0x00, 0x9a, 0x9a, 0x9a, 0xfa, 0xf4, 0x54, 0x00, 0x00, 0xaa, 0xaa, 0xa4, + 0x44, 0x4a, 0x4a, 0x00, 0x00, 0xce, 0x48, 0x44, 0x42, 0x42, 0xce, 0x00, + 0x00, 0x62, 0x42, 0x44, 0x44, 0x48, 0x68, 0x00, 0x00, 0x04, 0x0a, 0x00, + 0x00, 0x00, 0xe0, 0x00, 0x00, 0x04, 0x68, 0x80, 0xe0, 0xa0, 0xe0, 0x00, + 0x00, 0x02, 0xc2, 0x26, 0x2a, 0x2a, 0xc6, 0x00, 0x00, 0x08, 0x48, 0xac, + 0xea, 0x2a, 0xcc, 0x00, 0x00, 0x0c, 0xc2, 0xae, 0xa2, 0xc2, 0x82, 0x60, + 0x00, 0x42, 0x02, 0x66, 0x4a, 0x4a, 0xca, 0x00, 0x00, 0x28, 0x20, 0xa8, + 0x68, 0xa8, 0xa8, 0x06, 0x00, 0x06, 0xa4, 0xe4, 0xa4, 0xa4, 0xac, 0x00, + 0x00, 0x00, 0x46, 0xaa, 0xaa, 0xaa, 0x4a, 0x00, 0x00, 0x00, 0xc6, 0xaa, + 0xaa, 0xc6, 0x82, 0x82, 0x00, 0x00, 0xcc, 0x22, 0x42, 0x82, 0x62, 0x00, + 0x00, 0x04, 0xae, 0xa4, 0xa4, 0xa4, 0xec, 0x00, 0x00, 0x00, 0xaa, 0xaa, + 0xaa, 0xe4, 0xa4, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xa4, 0xca, 0x8a, 0x60, + 0x00, 0xc0, 0x4e, 0x28, 0x44, 0x42, 0xce, 0x00, 0x04, 0x64, 0x44, 0x84, + 0x44, 0x44, 0x64, 0x04, 0xe0, 0x80, 0x2a, 0x85, 0x20, 0x80, 0x20, 0xe0 }; diff --git a/src/col80_modified/icetmod_maybe.xbm b/src/col80_modified/icetmod_maybe.xbm new file mode 100644 index 0000000..60bc84c --- /dev/null +++ b/src/col80_modified/icetmod_maybe.xbm @@ -0,0 +1,35 @@ +#define icetmod_width 8 +#define icetmod_height 384 +static unsigned char icetmod_bits[] = { + 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, 0x55, 0x75, 0x50, + 0x70, 0x50, 0x00, 0x00, 0x02, 0x16, 0x41, 0x22, 0x14, 0x43, 0x02, 0x00, + 0x02, 0x46, 0x21, 0x06, 0x01, 0x06, 0x02, 0x00, 0x00, 0x14, 0x22, 0x22, + 0x22, 0x22, 0x14, 0x00, 0x00, 0x25, 0x22, 0x77, 0x22, 0x25, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, 0x02, 0x01, 0x00, 0x40, 0x40, 0x20, + 0x20, 0x12, 0x12, 0x00, 0x00, 0x22, 0x35, 0x25, 0x25, 0x25, 0x72, 0x00, + 0x00, 0x32, 0x45, 0x34, 0x42, 0x41, 0x37, 0x00, 0x00, 0x75, 0x15, 0x35, + 0x46, 0x44, 0x34, 0x00, 0x00, 0x72, 0x41, 0x23, 0x25, 0x15, 0x12, 0x00, + 0x00, 0x22, 0x55, 0x52, 0x65, 0x45, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x20, 0x22, 0x10, 0x00, 0x00, 0x04, 0x72, 0x01, 0x72, 0x04, 0x00, 0x00, + 0x00, 0x21, 0x52, 0x44, 0x22, 0x01, 0x20, 0x00, 0x00, 0x22, 0x57, 0x57, + 0x75, 0x51, 0x56, 0x00, 0x00, 0x63, 0x15, 0x13, 0x15, 0x15, 0x67, 0x00, + 0x00, 0x73, 0x15, 0x75, 0x15, 0x15, 0x73, 0x00, 0x00, 0x67, 0x11, 0x17, + 0x51, 0x51, 0x61, 0x00, 0x00, 0x75, 0x25, 0x27, 0x25, 0x25, 0x75, 0x00, + 0x00, 0x56, 0x54, 0x34, 0x54, 0x55, 0x52, 0x00, 0x00, 0x51, 0x71, 0x51, + 0x51, 0x51, 0x57, 0x00, 0x00, 0x73, 0x55, 0x55, 0x55, 0x55, 0x75, 0x00, + 0x00, 0x73, 0x55, 0x55, 0x53, 0x71, 0x41, 0x00, 0x00, 0x63, 0x15, 0x23, + 0x45, 0x45, 0x35, 0x00, 0x00, 0x57, 0x52, 0x52, 0x52, 0x52, 0x72, 0x00, + 0x00, 0x55, 0x55, 0x55, 0x55, 0x72, 0x52, 0x00, 0x00, 0x55, 0x55, 0x52, + 0x22, 0x25, 0x25, 0x00, 0x00, 0x67, 0x24, 0x22, 0x21, 0x21, 0x67, 0x00, + 0x00, 0x31, 0x21, 0x22, 0x22, 0x24, 0x34, 0x00, 0x00, 0x02, 0x05, 0x00, + 0x00, 0x00, 0x70, 0x00, 0x00, 0x02, 0x34, 0x40, 0x70, 0x50, 0x70, 0x00, + 0x00, 0x01, 0x61, 0x13, 0x15, 0x15, 0x63, 0x00, 0x00, 0x04, 0x24, 0x56, + 0x75, 0x15, 0x66, 0x00, 0x00, 0x06, 0x61, 0x57, 0x51, 0x61, 0x41, 0x30, + 0x00, 0x21, 0x01, 0x33, 0x25, 0x25, 0x65, 0x00, 0x00, 0x14, 0x10, 0x54, + 0x34, 0x54, 0x54, 0x03, 0x00, 0x03, 0x52, 0x72, 0x52, 0x52, 0x56, 0x00, + 0x00, 0x00, 0x23, 0x55, 0x55, 0x55, 0x25, 0x00, 0x00, 0x00, 0x63, 0x55, + 0x55, 0x63, 0x41, 0x41, 0x00, 0x00, 0x66, 0x11, 0x21, 0x41, 0x31, 0x00, + 0x00, 0x02, 0x57, 0x52, 0x52, 0x52, 0x76, 0x00, 0x00, 0x00, 0x55, 0x55, + 0x55, 0x72, 0x52, 0x00, 0x00, 0x00, 0x55, 0x55, 0x52, 0x65, 0x45, 0x30, + 0x00, 0x60, 0x27, 0x14, 0x22, 0x21, 0x67, 0x00, 0x02, 0x32, 0x22, 0x42, + 0x22, 0x22, 0x32, 0x02, 0x00, 0x20, 0x2a, 0x25, 0x20, 0x20, 0x20, 0x00 }; diff --git a/src/col80_modified/icetmod_old.xbm b/src/col80_modified/icetmod_old.xbm new file mode 100644 index 0000000..01fa394 --- /dev/null +++ b/src/col80_modified/icetmod_old.xbm @@ -0,0 +1,35 @@ +#define icetmod_width 8 +#define icetmod_height 384 +static unsigned char icetmod_bits[] = { + 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, 0x55, 0x75, 0x50, + 0x70, 0x50, 0x00, 0x00, 0x02, 0x16, 0x41, 0x22, 0x14, 0x43, 0x02, 0x00, + 0x00, 0x42, 0x25, 0x02, 0x05, 0x02, 0x04, 0x00, 0x00, 0x14, 0x22, 0x22, + 0x22, 0x22, 0x14, 0x00, 0x00, 0x25, 0x22, 0x77, 0x22, 0x25, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, 0x02, 0x01, 0x00, 0x40, 0x40, 0x20, + 0x20, 0x12, 0x12, 0x00, 0x00, 0x22, 0x35, 0x25, 0x25, 0x25, 0x72, 0x00, + 0x00, 0x32, 0x45, 0x34, 0x42, 0x41, 0x37, 0x00, 0x00, 0x75, 0x15, 0x35, + 0x46, 0x44, 0x34, 0x00, 0x00, 0x72, 0x41, 0x23, 0x25, 0x15, 0x12, 0x00, + 0x00, 0x22, 0x55, 0x52, 0x65, 0x45, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x20, 0x22, 0x10, 0x00, 0x00, 0x04, 0x72, 0x01, 0x72, 0x04, 0x00, 0x00, + 0x00, 0x21, 0x52, 0x44, 0x22, 0x01, 0x20, 0x00, 0x00, 0x22, 0x57, 0x57, + 0x75, 0x51, 0x56, 0x00, 0x00, 0x63, 0x15, 0x13, 0x15, 0x15, 0x67, 0x00, + 0x00, 0x73, 0x15, 0x75, 0x15, 0x15, 0x73, 0x00, 0x00, 0x67, 0x11, 0x17, + 0x51, 0x51, 0x61, 0x00, 0x00, 0x75, 0x25, 0x27, 0x25, 0x25, 0x75, 0x00, + 0x00, 0x56, 0x54, 0x34, 0x54, 0x55, 0x52, 0x00, 0x00, 0x51, 0x71, 0x51, + 0x51, 0x51, 0x57, 0x00, 0x00, 0x74, 0x55, 0x57, 0x57, 0x55, 0x71, 0x00, + 0x00, 0x73, 0x55, 0x55, 0x53, 0x71, 0x41, 0x00, 0x00, 0x63, 0x15, 0x23, + 0x45, 0x45, 0x35, 0x00, 0x00, 0x57, 0x52, 0x52, 0x52, 0x52, 0x72, 0x00, + 0x00, 0x55, 0x55, 0x55, 0x55, 0x72, 0x52, 0x00, 0x00, 0x55, 0x55, 0x52, + 0x22, 0x25, 0x25, 0x00, 0x00, 0x67, 0x24, 0x22, 0x21, 0x21, 0x67, 0x00, + 0x00, 0x31, 0x21, 0x22, 0x22, 0x24, 0x34, 0x00, 0x00, 0x02, 0x05, 0x00, + 0x00, 0x00, 0x70, 0x00, 0x00, 0x02, 0x34, 0x40, 0x70, 0x50, 0x70, 0x00, + 0x00, 0x01, 0x61, 0x13, 0x15, 0x15, 0x63, 0x00, 0x00, 0x04, 0x24, 0x56, + 0x75, 0x15, 0x66, 0x00, 0x00, 0x06, 0x61, 0x57, 0x51, 0x61, 0x41, 0x30, + 0x00, 0x21, 0x01, 0x33, 0x25, 0x25, 0x65, 0x00, 0x00, 0x14, 0x10, 0x54, + 0x34, 0x54, 0x54, 0x03, 0x00, 0x03, 0x52, 0x72, 0x52, 0x52, 0x56, 0x00, + 0x00, 0x00, 0x23, 0x55, 0x55, 0x55, 0x25, 0x00, 0x00, 0x00, 0x63, 0x55, + 0x55, 0x63, 0x41, 0x41, 0x00, 0x00, 0x66, 0x11, 0x21, 0x41, 0x31, 0x00, + 0x00, 0x02, 0x57, 0x52, 0x52, 0x52, 0x76, 0x00, 0x00, 0x00, 0x55, 0x55, + 0x55, 0x72, 0x52, 0x00, 0x00, 0x00, 0x55, 0x55, 0x52, 0x65, 0x45, 0x30, + 0x00, 0x60, 0x27, 0x14, 0x22, 0x21, 0x67, 0x00, 0x02, 0x32, 0x22, 0x42, + 0x22, 0x22, 0x32, 0x02, 0x00, 0x20, 0x2a, 0x25, 0x20, 0x20, 0x20, 0x00 }; diff --git a/src/col80_modified/lsr.pl b/src/col80_modified/lsr.pl new file mode 100644 index 0000000..915f769 --- /dev/null +++ b/src/col80_modified/lsr.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +use bytes; + +$c = 0; + +while(<>) { + next unless @bytes = (/0x([0-9a-fA-F]{2})/g); + for(@bytes) { + if(!($c % 8)) { + print " .byte "; + } + + printf "\$%02X", (reverse_bits(hex $_) >> 1); + + if(($c % 8 == 7) || ($c == $#bytes)) { + print "\n"; + $c = 0; + } else { + print ","; + $c++; + } + } +} + +sub reverse_bits { + my $bitstr = reverse sprintf("%08b", $_[0]); + return eval "0b$bitstr"; +} diff --git a/src/col80_modified/new_font.s b/src/col80_modified/new_font.s new file mode 100644 index 0000000..f4fcfa4 --- /dev/null +++ b/src/col80_modified/new_font.s @@ -0,0 +1,48 @@ + .byte $00,$04,$04,$04,$04,$00,$04,$00 + .byte $00,$AA,$AE,$0A,$0E,$0A,$00,$00 + .byte $40,$68,$82,$44,$28,$C2,$40,$00 + .byte $40,$62,$84,$60,$80,$60,$40,$00 + .byte $00,$28,$44,$44,$44,$44,$28,$00 + .byte $00,$A4,$44,$EE,$44,$A4,$00,$00 + .byte $00,$00,$00,$0E,$00,$40,$40,$80 + .byte $00,$02,$02,$04,$04,$48,$48,$00 + .byte $00,$44,$AC,$A4,$A4,$A4,$4E,$00 + .byte $00,$4C,$A2,$2C,$42,$82,$EC,$00 + .byte $00,$AE,$A8,$AC,$62,$22,$2C,$00 + .byte $00,$4E,$82,$C4,$A4,$A8,$48,$00 + .byte $00,$44,$AA,$4A,$A6,$A2,$44,$00 + .byte $00,$00,$44,$00,$04,$44,$08,$00 + .byte $00,$20,$4E,$80,$4E,$20,$00,$00 + .byte $00,$84,$4A,$22,$44,$80,$04,$00 + .byte $00,$44,$EA,$EA,$AE,$8A,$6A,$00 + .byte $00,$C6,$A8,$C8,$A8,$A8,$E6,$00 + .byte $00,$CE,$A8,$AE,$A8,$A8,$CE,$00 + .byte $00,$E6,$88,$E8,$8A,$8A,$86,$00 + .byte $00,$AE,$A4,$E4,$A4,$A4,$AE,$00 + .byte $00,$6A,$2A,$2C,$2A,$AA,$4A,$00 + .byte $00,$8A,$8E,$8A,$8A,$8A,$EA,$00 + .byte $00,$CE,$AA,$AA,$AA,$AA,$AE,$00 + .byte $00,$CE,$AA,$AA,$CA,$8E,$82,$00 + .byte $00,$C6,$A8,$C4,$A2,$A2,$AC,$00 + .byte $00,$EA,$4A,$4A,$4A,$4A,$4E,$00 + .byte $00,$AA,$AA,$AA,$AA,$4E,$4A,$00 + .byte $00,$AA,$AA,$4A,$44,$A4,$A4,$00 + .byte $00,$E6,$24,$44,$84,$84,$E6,$00 + .byte $00,$8C,$84,$44,$44,$24,$2C,$00 + .byte $00,$40,$A0,$00,$00,$00,$0E,$00 + .byte $00,$40,$2C,$02,$0E,$0A,$0E,$00 + .byte $00,$80,$86,$C8,$A8,$A8,$C6,$00 + .byte $00,$20,$24,$6A,$AE,$A8,$66,$00 + .byte $00,$60,$86,$EA,$8A,$86,$82,$0C + .byte $00,$84,$80,$CC,$A4,$A4,$A6,$00 + .byte $00,$28,$08,$2A,$2C,$2A,$2A,$C0 + .byte $00,$C0,$4A,$4E,$4A,$4A,$6A,$00 + .byte $00,$00,$C4,$AA,$AA,$AA,$A4,$00 + .byte $00,$00,$C6,$AA,$AA,$C6,$82,$82 + .byte $00,$00,$66,$88,$84,$82,$8C,$00 + .byte $00,$40,$EA,$4A,$4A,$4A,$6E,$00 + .byte $00,$00,$AA,$AA,$AA,$4E,$4A,$00 + .byte $00,$00,$AA,$AA,$4A,$A6,$A2,$0C + .byte $00,$06,$E4,$28,$44,$84,$E6,$00 + .byte $40,$4C,$44,$42,$44,$44,$4C,$40 + .byte $00,$04,$54,$A4,$04,$04,$04,$00 diff --git a/src/col80_modified/t.dasm b/src/col80_modified/t.dasm new file mode 100644 index 0000000..e32d950 --- /dev/null +++ b/src/col80_modified/t.dasm @@ -0,0 +1,3 @@ + .processor 6502 + .org 0 + .include icetmod.s diff --git a/src/col80_modified/test.atr b/src/col80_modified/test.atr new file mode 100755 index 0000000..57b2d13 Binary files /dev/null and b/src/col80_modified/test.atr differ diff --git a/src/col80_modified/xbm2font.pl b/src/col80_modified/xbm2font.pl new file mode 100644 index 0000000..758d57e --- /dev/null +++ b/src/col80_modified/xbm2font.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +use bytes; + +$c = 0; + +while(<>) { + next unless @bytes = (/0x([0-9a-fA-F]{2})/g); + for(@bytes) { + if(!($c % 8)) { + print " .byte "; + } + + printf "\$%02X", reverse_bits(hex $_); + + if(($c % 8 == 7) || ($c == $#bytes)) { + print "\n"; + $c = 0; + } else { + print ","; + $c++; + } + } +} + +sub reverse_bits { + my $bitstr = reverse sprintf("%08b", $_[0]); + return eval "0b$bitstr"; +} diff --git a/src/commands.c b/src/commands.c new file mode 100644 index 0000000..001f384 --- /dev/null +++ b/src/commands.c @@ -0,0 +1,206 @@ + +#include +#include +#include +#include +#include +#include "fujichat.h" +#include "features.h" +#include "common.h" + +void cmd_join(void); +void cmd_msg(void); +void cmd_nick(void); +void cmd_part(void); +void cmd_ping(void); +// void cmd_quit(void); +void cmd_quote(void); +void cmd_ver(void); +void do_me(void); +#ifdef FEAT_COLOR_COMMAND +void cmd_fgcolor(void); +void cmd_bgcolor(void); +#endif + +fuji_cmd_t cmd_list[] = { + { "JOIN", ARGTYPE_OPT, cmd_join }, + { "J", ARGTYPE_OPT, cmd_join }, + { "MSG", ARGTYPE_REQUIRED, cmd_msg }, + { "M", ARGTYPE_REQUIRED, cmd_msg }, + { "NICK", ARGTYPE_REQUIRED, cmd_nick }, + { "PART", ARGTYPE_NONE, cmd_part }, + { "PING", ARGTYPE_REQUIRED, cmd_ping }, + // { "QUIT", ARGTYPE_OPT, cmd_quit }, + { "QUOTE", ARGTYPE_REQUIRED, cmd_quote }, + { "VER", ARGTYPE_REQUIRED, cmd_ver }, + { "VERSION", ARGTYPE_REQUIRED, cmd_ver }, + { "ME", ARGTYPE_REQUIRED, do_me }, +#ifdef FEAT_COLOR_COMMAND + { "FGCOLOR", ARGTYPE_REQUIRED, cmd_fgcolor }, + { "BGCOLOR", ARGTYPE_REQUIRED, cmd_bgcolor }, +#endif +}; + +#define CMD_LIST_SIZE (sizeof(cmd_list) / sizeof(fuji_cmd_t)) + +char *cmd_arg; + +static void errmsg(char *msg) { + puts(msg); + bell(); +} + +static void err_missing_arg(void) { + errmsg("Command requires argument"); +} + +static void err_arg_not_allowed(void) { + errmsg("No argument allowed"); +} + +static void err_already_joined(void) { + errmsg("You are already in a channel (use /part to leave)"); +} + + +void do_me(void) { + serv_msg_buf_len = sprintf(serv_msg_buf, "PRIVMSG %s :%cACTION %s%c%c", + channel, 1, cmd_arg, 1, NL); + send_serv_msg_buf(); +} + +void cmd_ver(void) { + serv_msg_buf_len = sprintf(serv_msg_buf, "PRIVMSG %s %cVERSION%c%c", + cmd_arg, 1, 1, NL); + send_serv_msg_buf(); +} + +void cmd_ping(void) { + serv_msg_buf_len = sprintf(serv_msg_buf, "PRIVMSG %s %cPING %03d %03d %03d%c%c", + cmd_arg, 1, PEEK(20), PEEK(19), PEEK(18), 1, NL); + send_serv_msg_buf(); +} + +void cmd_join(void) { + if(joined_channel) { + if(cmd_arg) + err_already_joined(); + else + send_server_cmd("JOIN", channel); + } else { + if(cmd_arg) { + joined_channel = 1; + strcpy(channel, cmd_arg); + send_server_cmd("JOIN", cmd_arg); + } else { + err_missing_arg(); + } + } +} + +void cmd_part(void) { + joined_channel = 0; + send_server_cmd("PART", channel); +} + +void cmd_msg(void) { + send_server_cmd("PRIVMSG", cmd_arg); +} + +void cmd_quote(void) { + send_server_cmd(cmd_arg, NULL); +} + +void cmd_nick(void) { + strcpy(config->nick, cmd_arg); + send_server_cmd("NICK", cmd_arg); + printf("> You are now known as %s\n", config->nick); +} + +#ifdef FEAT_COLOR_COMMAND +static void do_color(u16_t reg) { + u16_t c; + + if(cmd_arg[0] >= '0' && cmd_arg[0] <= '9') { + c = atoi(cmd_arg); + if(c < 0x100) { + POKE(reg, c); + return; + } + } + + puts("Bad color (range 0-255)"); + bell(); +} + +void cmd_fgcolor(void) { + do_color(709); +} + +void cmd_bgcolor(void) { + do_color(710); +} + +#endif + +void handle_command(void) { + char i, *cend; + char *cmd = input_buf + 1; + char *p = cmd; + + cmd_arg = NULL; + + /* convert command word to uppercase */ + while((*p != NL) && (*p != ' ')) { + *p = toupper(*p); + ++p; + } + + cend = p; + + /* set cmd_arg pointer, nul-terminate cmd_arg, if present */ + /* (otherwise, cmd_arg remains NULL) */ + if(*p != NL) { + cmd_arg = p; + /* skip extra whitespace */ + while(*cmd_arg == ' ') + ++cmd_arg; + p = cmd_arg + 1; + while(*p && (*p != NL)) + ++p; + *p = '\0'; + } + + /* nul-terminate cmd */ + *cend = '\0'; + + for(i=0; i +#include +#include +#include +#include +#include "uip.h" +#include "common.h" +#include "aexec.h" +#include "fujichat.h" + +int __fastcall__ (*atari_exec_p)(char *) = (int __fastcall__ (*)(char *))0x600; +fuji_conf_t *config = (fuji_conf_t *)CONFIG_ADDRESS; + +void disable_break(void) { + asm("lda $10"); /* POKMSK */ + asm("and #$7f"); + asm("sta $10"); /* POKMSK */ + asm("sta $D20E"); /* IRQEN */ +} + +/* easier to copy/paste this tiny function from uip.c + than it would be to rebuild all of uIP for use in + this program! Also don't want to bloat fujiconf by + linking uip.a, even if it would link without a + recompile. */ +/* +u16_t local_htons(u16_t val) { + return HTONS(val); +} +*/ + +/* this version's half the size */ +u16_t local_htons(u16_t val) { + __AX__ = val; + asm("sta tmp1"); + asm("txa"); + asm("ldx tmp1"); +} + +/* helper for fuji_cgetc */ +void __fastcall__ call_keybdv(void) { + asm("lda $E420+5"); /* KEYBDV */ + asm("pha"); + asm("lda $E420+4"); + asm("pha"); + asm("lda #12"); + asm("sta $2A"); /* ICAX1Z */ +} + +/* replacement for cgetc() that doesn't include cursor enable/disable + stuff (otherwise copied from cc65's cgetc.s) */ +char __fastcall__ fuji_cgetc(void) { + asm("jsr _call_keybdv"); + asm("ldx #0"); +} + + +#if 0 +char get_config(void) { + char config_valid = 0; + FILE *f = fopen(DEFAULT_CONF_FILE, "rb"); + + puts("Loading config from " DEFAULT_CONF_FILE); + + if(f) { + config_valid = + fread(config, 1, sizeof(fuji_conf_t), f) == sizeof(fuji_conf_t); + fclose(f); + if(!config_valid) + puts("Config file is wrong size"); + } else { + puts("No config file found"); + } + + if(config_valid) { + if(!config_is_valid()) { + puts("Invalid or outdated config file"); + config_valid = 0; + } else { + puts("Loaded OK"); + } + } + + return config_valid; +} + +#else +/* using open() read() close() instead of fopen() fread() fclose() + is a big win: save us 438 bytes! */ +char get_config(void) { + char config_valid = 0; + int f = open(DEFAULT_CONF_FILE, O_RDONLY); + + puts("Loading config from " DEFAULT_CONF_FILE); + + if(f >= 0) { + config_valid = + (read(f, config, sizeof(fuji_conf_t)) == sizeof(fuji_conf_t)); + close(f); + if(!config_valid) + puts("Config file is wrong size"); + } else { + puts("No config file found"); + } + + if(config_valid) { + if(!config_is_valid()) { + puts("Invalid or outdated config file"); + config_valid = 0; + } else { + puts("Loaded OK"); + } + } + + return config_valid; +} +#endif + +char config_is_valid(void) { + // return( (memcmp(config->signature, CONF_SIGNATURE, 2) == 0) && (config->version == CONF_VERSION) ); + return + *((char *)CONFIG_ADDRESS) == CONF_SIGNATURE_LO && + *(char *)(CONFIG_ADDRESS+1) == CONF_SIGNATURE_HI && + *(char *)(CONFIG_ADDRESS+2) == CONF_VERSION; +} + +void set_default_config(void) { + puts("Using built-in defaults"); + /* + // FIXME: why does this end up always 0.0.0.0 now? + // has something to do with macro expansion. What a mess. + uip_ipaddr(&(config->local_ip), 192,168,0,2); + uip_ipaddr(&(config->peer_ip), 192,168,0,1); + uip_ipaddr(&(config->resolver_ip), 192,168,0,1); + */ + + config->local_ip[0] = 0xa8c0; + config->local_ip[1] = 0x0200; + + config->peer_ip[0] = 0xa8c0; + config->peer_ip[1] = 0x0100; + + config->resolver_ip[0] = 0xa8c0; + config->resolver_ip[1] = 0x0100; + + strcpy(config->server, "na.newnet.net"); + strcpy(config->nick, DEFAULT_NICK); + strcpy(config->real_name, "FujiChat User"); + config->server_port = 6667; + config->ui_flags = UIFLAG_HIDEMOTD; + config->bg_color = 0xc0; /* dark green */ + config->fg_color = 0x0c; + config->baud = RS_BAUD_4800; + + *(char *)(CONFIG_ADDRESS) = CONF_SIGNATURE_LO; + *(char *)(CONFIG_ADDRESS+1) = CONF_SIGNATURE_HI; + *(char *)(CONFIG_ADDRESS+2) = CONF_VERSION; + + // config_valid = 1; +} + +static char ipbuf[20]; +/* +static char *fmt = "%d.%d.%d.%d"; +*/ +char * format_ip(uip_ipaddr_t *ip) { + + u16_t *ipaddr = (u16_t *)ip; + sprintf(ipbuf, "%d.%d.%d.%d", + local_htons(ipaddr[0]) >> 8, + local_htons(ipaddr[0]) & 0xff, + local_htons(ipaddr[1]) >> 8, + local_htons(ipaddr[1]) & 0xff); + + return ipbuf; + + /* + asm(" sta ptr1"); + asm(" stx ptr1+1"); + + asm(" lda #<_ipbuf"); + asm(" ldx #>_ipbuf"); + asm(" jsr pushax"); + + asm(" lda #<_fmt"); + asm(" ldx #>_fmt"); + asm(" jsr pushax"); + + asm(" ldy #0"); + asm(" lda (ptr1),y"); + asm(" jsr pusha0"); + + asm(" ldy #1"); + asm(" lda (ptr1),y"); + asm(" jsr pusha0"); + + asm(" ldy #2"); + asm(" lda (ptr1),y"); + asm(" jsr pusha0"); + + asm(" ldy #3"); + asm(" lda (ptr1),y"); + asm(" jsr pusha0"); + + asm(" ldy #$0c"); + asm(" jsr _sprintf"); + + asm(" lda #<_ipbuf"); + asm(" ldx #>_ipbuf"); + */ +} + +void get_line(char *buf, unsigned char len) { + asm("ldy #$00"); + asm("lda (sp),y"); + asm("sta $e2"); + + asm("ldy #$02"); + asm("jsr ldaxysp"); + asm("sta $e0"); + asm("stx $e0+1"); + + asm("@loop: lda _stdin"); + asm("ldx _stdin+1"); + asm("jsr _fgetc"); + + asm("cmp #$9B"); + asm("beq @out"); + + asm("ldy #$00"); + asm("sta ($e0),y"); + asm("inc $e0"); + asm("bne @noinc"); + asm("inc $e0+1"); + asm("@noinc:"); + + asm("dec $e2"); + asm("bne @loop"); + + asm("@out:"); + asm("ldy #$00"); + asm("tya"); + asm("sta ($e0),y"); + + /* + // C implementation is 80 bytes, asm is 50 + fgets(buf, len, stdin); + while(*buf) { + if(*buf == '\n') + *buf = '\0'; + ++buf; + } + */ +} + diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..c84b417 --- /dev/null +++ b/src/common.h @@ -0,0 +1,27 @@ +#ifndef COMMON_H +#define COMMON_H + +#include "fujichat.h" + +/* common functions, shared by fujichat.c and fujiconf.c. + Don't put anything here unless it really is shared! */ + +/* This stays resident */ +extern fuji_conf_t *config; + +/* uIP-related */ +char * format_ip(uip_ipaddr_t *ip); +u16_t local_htons(u16_t val); + +/* config-related */ +char get_config(void); +char config_is_valid(void); +void set_default_config(void); + +/* UI-related */ +char __fastcall__ fuji_cgetc(void); +void __fastcall__ fuji_putchar(char); /* fujiput.s */ +void get_line(char *buf, unsigned char len); +void disable_break(void); + +#endif diff --git a/src/dns.c b/src/dns.c new file mode 100644 index 0000000..f5eef0f --- /dev/null +++ b/src/dns.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include "uip.h" +#include "uiplib.h" +#include "rs232dev.h" +#include +#include +#include +#include + +#include "telnet.h" +#include "resolv.h" +#include "timer.h" + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +char buf[256]; + +int main(void) { + char c; + int i; + uip_ipaddr_t ipaddr; + struct timer periodic_timer; + + timer_set(&periodic_timer, CLOCK_SECOND / 2); + + rs232dev_init(); + uip_init(); + + uip_ipaddr(ipaddr, 192,168,0,2); + uip_sethostaddr(ipaddr); + uip_ipaddr(ipaddr, 192,168,0,1); + uip_setdraddr(ipaddr); + uip_ipaddr(ipaddr, 255,255,255,0); + uip_setnetmask(ipaddr); + + resolv_init(); + uip_ipaddr(ipaddr, 192,168,88,1); + resolv_conf(ipaddr); + + cursor(1); + + while(1) { + puts("DNS test. Hostname:"); + fgets(buf, 256, stdin); + for(i=0; i 0) { + uip_input(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } else if(timer_expired(&periodic_timer)) { + timer_reset(&periodic_timer); + for(i = 0; i < UIP_CONNS; i++) { + uip_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } + +#if UIP_UDP + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } +#endif /* UIP_UDP */ + } + + if(kbhit()) { + cgetc(); + break; + } + } + } +} + +void telnet_connected(struct telnet_state *s) { +} + +void telnet_closed(struct telnet_state *s) { +} + +void telnet_sent(struct telnet_state *s) { +} + +void telnet_aborted(struct telnet_state *s) { +} + +void telnet_timedout(struct telnet_state *s) { +} + +void telnet_newdata(struct telnet_state *s, char *data, u16_t len) { +} + +void resolv_found(char *name, u16_t *ipaddr) { + if(ipaddr == NULL) { + printf("Host '%s' not found.\n", name); + } else { + printf("Found name '%s' = %d.%d.%d.%d\n", name, + htons(ipaddr[0]) >> 8, + htons(ipaddr[0]) & 0xff, + htons(ipaddr[1]) >> 8, + htons(ipaddr[1]) & 0xff); + puts("Press any key..."); + // webclient_get("www.google.com", 80, "/index.html"); + // webclient_get(name, 80, "/~adam/uip"); + } +} diff --git a/src/dos25_4drives.atr b/src/dos25_4drives.atr new file mode 100644 index 0000000..a032ec9 Binary files /dev/null and b/src/dos25_4drives.atr differ diff --git a/src/dos_20s.atr b/src/dos_20s.atr new file mode 100644 index 0000000..8016b73 Binary files /dev/null and b/src/dos_20s.atr differ diff --git a/src/env.sh b/src/env.sh new file mode 100644 index 0000000..0d1e50e --- /dev/null +++ b/src/env.sh @@ -0,0 +1,10 @@ +# source this file to set up your environment for a snapshot of cc65 +# installed in a nonstandard place. + +CC65_PREFIX=/home/urchlay/cc65_snap + +PATH=$CC65_PREFIX/bin:$PATH +CC65_INC=$CC65_PREFIX/lib/cc65/include +CC65_LIB=$CC65_PREFIX/lib/cc65/lib + +export PATH CC65_INC CC65_LIB diff --git a/src/equates.inc b/src/equates.inc new file mode 100644 index 0000000..9759a8a --- /dev/null +++ b/src/equates.inc @@ -0,0 +1,1386 @@ +; +; ATARI 800 EQUATE LISTING +; +; (version 20070530_bkw) +; +; This is a heavily modified copy of Appendix A of the Atari System +; Reference Manual (with much info added from Appendix B, and from +; Mapping the Atari and other sources) +; +; +;This listing is based on the original release of Operating System, +;version A. The vectors shown here were not changed in version B. +;New equates for XL and XE models are included and noted. Changes +;from version B to XL/XE are also noted. +; +;Most of the equate names given below are the official Atari +;names. They are in common use but are not mandatory. + +; This file can be included in your assembly source, but it's also +; got a lot of useful human-readable comments. It's meant to serve as +; a "quick reference" to Atari programmers, particularly ones who use +; a cross-assembler on a UNIX-ish platform and a text editor that can +; use "ctags": + +; $ ctags equates.inc +; $ vim mystuff.dasm + +; While in vim, press ^] (control-right-bracket) while sitting on a label, +; to jump to that label's definition in this file. (Also, you can type +; :tag labelname). You can also do completion on the labels in vim by +; typing part of a label and pressing ^N (or Tab, if you use the +; CleverTab script from vimhelp.org) + +; GNU Emacs and XEmacs also support ctags, but I've never used them, so +; I dunno how to do it. I do know that you need to use "Exuberant" ctags, +; not the ctags that comes with emacs (which doesn't grok 6502 asm). + +; If you're using an Atari assembler instead of a cross-assembler, you +; don't want to use this as-is: all the extra comments make it huge, and +; it'll be either too large for the Atari's memory, or at least will take +; a long time to assemble. You can make a comment-less, Atari-compatible +; version like so: + +; perl -lne 's/;.*//; s/\s*$//; print if $_' < equates.inc > small.inc + +; ...then use a8eol to convert it to ATASCII format. + +; 20061028 bkw: Originally downloaded from: + +; http://atrey.karlin.mff.cuni.cz/~pavel/atari/atrb.html + +; ...and converted to DASM/ATASM/CA65 format. dasm, atasm, and ca65 use +; similar enough syntax that this file can be used as-is with any of +; them. Unfortunately, this means I can't do conditional assembly in this +; file, since the two assemblers use different semantics... macros are +; even less compatible :( + +; If you use ca65, you need this line in your source: + +;; .FEATURE labels_without_colons + +; before including this file, or else run ca65 with +; "--feature labels_without_colons"). + +; 20070529 bkw: updated, added missing GTIA/POKEY/ANTIC equates, +; documented where the shadows are for those GTIA/POKEY/ANTIC/PIA +; registers that have them. Also added a list of error messages and +; explanation of the cassette buffer layout, and organized the C_* +; CIO constants. Made minor modifications to get this file to assemble +; with ATasm as well as DASM. + +; I have added a few missing equates: this file only +; contained OS ROM locations when I got it. +; I added a few from FMS/DOS as well (e.g. RUNAD and INITAD). + +; XL-specific locations in the original file were duplicate labels +; (e.g. PTIMOT was defined as both $1C and $314), which keeps DASM +; from being able to assemble the file. I prefixed the XL/XL versions +; with "XL_" + +; Also, I've prefixed the CIO command and AUX1 constants with C_, since some +; of them conflicted with other labels in the original version. + +; Areas listed as "unmapped" are literally not connected to anything. +; Trying to read from unmapped address space results in reading whatever +; garbage was on the data bus when the read happened. On my 1200XL, this +; generally results in all 1's ($FF or 255). +; In a 400, 600XL or other Atari with less than 48K of RAM, the missing +; RAM address space is also unmapped. + +; Still TODO: +; - Rest of the DOS/FMS equates +; - Mark 800-ony locations with OSB_ +; - ifdef code, so the user can set the machine type (OSB or XL), +; then refer to e.g. PTIMOT and get either OSB_PTIMOT or XL_PTIMOT +; - Split into separate files? I'd rather not (it's only about 1000 lines) + +; This file's mostly intended for new development. It could also be +; useful for porting old ASM/ED or Mac65 code to DASM, but such code +; may need work... you can always assemble it with ATasm, in that case, +; since it's 99.999% source code compatible with Mac65. + +; References to "APPENDIX C" and such are referring to the Atari System +; Reference Manual, a version of which can be found at: + +; http://atrey.karlin.mff.cuni.cz/~pavel/atari/atrtblc.html + +; References to "Mapping" refer to "Mapping the Atari, Revised Edition", +; which can be found at: + +; http://www.atariarchives.org/mapping/index.php + +; I've pasted a few quotes from Mapping into this file; I consider them +; small enough to be covered under the "fair use" provisions of copyright law +; (I am not a lawyer, though). + +; +; +; DEVICE NAMES +; +; +;SCREDT = "E" SCREEN EDITOR +;KBD = "K" KEYBOARD +;DISPLY = "S" DISPLAY +;PRINTR = "P" PRINTER +;CASSET = "C" CASSETTE +;DISK = "D" DISK DRIVE +; +; +; +; STATUS CODES +; +; + +; 20070529 bkw: These are returned as error codes, though various DOSes +; also define their own codes (usually in the range 160-255). +; Errors 2-21 are defined by BASIC. +; Errors 150-154 are defined by the R: (850 or compatible, RS-232) handler. +SUCCES = $01 ; 1 +BRKABT = $80 ; 128 BREAK KEY ABORT +PRVOPN = $82 ; 130 IOCB ALREADY OPEN +NONDEV = $82 ; 130 NONEXISTANT DEVICE +WRONLY = $83 ; 131 OPENED FOR WRITE ONLY +NVALID = $84 ; 132 INVALID COMMAND +NOTOPN = $85 ; 133 DEVICE OR FILE NOT OPEN +BADIOC = $86 ; 134 INVALID IOCB NUMBER +RDONLY = $87 ; 135 OPENED FOR READ ONLY +EOFERR = $88 ; 136 END OF FILE +TRNRCD = $89 ; 137 TRUNCATED RECORD +TIMOUT = $8A ; 138 PERIPHERAL TIME OUT +DNACK = $8B ; 139 DEVICE DOES NOT ACKNOWLEDGE +FRMERR = $8C ; 140 SERIAL BUS FRAMING ERROR +CRSROR = $8D ; 141 CURSOR OUT OF RANGE +OVRRUN = $8E ; 142 SERIAL BUS DATA OVERRUN +CHKERR = $8F ; 143 SERIAL BUS CHECKSUM ERROR +DERROR = $90 ; 144 PERIPHERAL DEVICE ERROR +BADMOD = $91 ; 145 NON EXISTANT SCREEN MODE +FNCNOT = $92 ; 146 FUNCTION NOT IMPLEMENTED +SCRMEM = $93 ; 147 NOT ENOUGH MEMORY FOR SCREEN MODE + +; BASIC error codes (also used by e.g. Basic XL/XE and Turbo BASIC): +;; 2: Insufficient Memory +;; 3: Value Error +;; 4: Too Many Variables +;; 5: String Length Error +;; 6: Out of Data Error +;; 7: Number Greater than 32767 +;; 8: Input Statement Error +;; 9: Array or String DIM Error +;; 10: Argument Stack Overflow +;; 11: Floating Point Overflow or Underflow Error +;; 12: Line Not Found +;; 13: No Matching FOR Statement +;; 14: Line Too Long +;; 15: GOSUB or FOR Line Deleted +;; 16: RETURN Error +;; 17: Garbage Error +;; 18: Invalid String Character +;; 19: LOAD Program Too Long +;; 20: Bad Channel Number +;; 21: LOAD File Error + +; 850/R: error codes: +;; 150: Serial Port Already Open +;; 151: Concurrent Mode Not Enabled +;; 152: Illegal User-Supplied Buffer +;; 153: Active Concurrent Mode Error +;; 154: Concurrent Mode Not Active + +; DOS error codes (DOS 2.0S only; other DOSes may define other errors) +;; 160: Device Number Error +;; 161: Too Many OPEN Files +;; 162: Disk Full +;; 163: Fatal System Error +;; 164: File Number Mismatch +;; 165: Bad File Name +;; 166: POINT Data Length Error +;; 167: File Locked +;; 168: Invalid XIO Command +;; 169: Directory Full +;; 170: File Not Found +;; 171: POINT Invalid +;; 172: DOS 1 File +;; 173: Bad Sector +;; 255: FORMATTING Error (DOS 2.5) + +; +; +; +; +; COMMAND CODES FOR CIO +; +; + +; Command byte goes in ICCOM,x + +;; General-purpose commands: +C_OPEN = $03 ; 3 OPEN (BASIC OPEN) +C_GETREC = $05 ; 5 GET RECORD +C_GETCHR = $07 ; 7 GET BYTE +C_PUTREC = $09 ; 9 WRITE RECORD +C_PUTCHR = $0B ; 11 PUT-BYTE +C_CLOSE = $0C ; 12 +C_STATUS = $0D ; 13 +C_SPECIL = $0E ; 14 BEGINNING OF SPECIAL COMMANDS (aka XIO) +;; Commands for S: device: +C_DRAWLN = $11 ; 17 SCREEN DRAW (BASIC DRAWTO) +C_FILLIN = $12 ; 18 SCREEN FILL +;; Commands for D: device (only when DOS is loaded): +C_RENAME = $20 ; 32 +C_DELETE = $21 ; 33 +C_LOCK = $23 ; 35 +C_UNLOCK = $24 ; 36 +C_POINT = $25 ; 37 +C_NOTE = $26 ; 38 + +; AUX1 modes (ICAX1,x or 2nd parameter of BASIC OPEN command): +C_OPREAD = $04 ; 4 OPEN FOR INPUT +C_OWRITE = $08 ; 8 OPEN FOR OUTPUT +C_APPEND = $09 ; 9 OPEN TO APPEND TO END OF DISK FILE +C_OUPDAT = $0C ; 12 OPEN FOR INPUT AND OUTPUT AT THE SAME TIME +;; D: (DOS) only: +C_OPDIR = $06 ; 6 OPEN TO DISK DIRECTORY +;; S: only: +C_MXDMOD = $10 ; 16 OPEN TO SPLIT SCREEN (MIXED MODE) +C_INSCLR = $20 ; 32 OPEN TO SCREEN BUT DON'T ERASE +;; C: only: +C_NOIRG = $80 ; 128 NO GAP CASSETTE MODE + +;; Command bytes (ICCOM) for the RS-232 (R:) device: +;; +;; Output partial block 32 $20 +;; Control RTS,XMT,DTR 34 $22 +;; Baud, stop bits, word size 36 $24 +;; Translation mode 38 $26 +;; Concurrent mode 40 $28 +;; +;; (see the 850 Interface Manual for details) + + +; SIO command bytes (not part of CIO): +S_DFRMAT = $21 ; 33 FORMAT DISK (RESIDENT DISK HANDLER (RDH)) +S_PTSECT = $50 ; 80 RDH PUT SECTOR +S_GTSECT = $52 ; 82 RDH GET SECTOR +S_DSTAT = $53 ; 83 RDH GET STATUS +S_PSECTV = $57 ; 87 RDH PUT SECTOR AND VERIFY +; Various other SIO commands are supported by different drives + +; 20061028 bkw: CR/EOL not really part of CIO, but useful: +CR = $9B ; 155 CARRIAGE RETURN (EOL) +EOL = CR ; defined in SYSEQU.ASM + +; +IOCBSZ = $10 ; 16 IOCB SIZE +MAXIOC = $80 ; 128 MAX IOCB BLOCK SIZE +IOCBF = $FF ; 255 IOCB FREE +; +LEDGE = $02 ; 2 DEFAULT LEFT MARGIN +REDGE = $27 ; 39 DEFAULT RIGHT MARGIN + +; OS VARIABLES +; +; PAGE 0 +; +LINZBS = $00 ; 0 (800) FOR ORIGINAL DEBUGGER +; $00 0 (XL) RESERVED +NGFLAG = $01 ; 1 (XL) FOR POWER-UP SELF TEST +CASINI = $02 ; 2 +RAMLO = $04 ; 4 POINTER FOR SELF TEST +TRAMSZ = $06 ; 6 TEMPORARY RAM SIZE +TSTDAT = $07 ; 7 TEST DATA +WARMST = $08 ; 8 +BOOTQ = $09 ; 9 SUCCESSFUL BOOT FLAG +; aka BOOT? in the OS source, but some assemblers don't support ? in labels +DOSVEC = $0A ; 10 PROGRAM RUN VECTOR +DOSINI = $0C ; 12 PROGRAM INITIALIZATION +APPMHI = $0E ; 14 DISPLAY LOW LIMIT +POKMSK = $10 ; 16 IRQ ENABLE FLAGS (shadow for IRQEN) +BRKKEY = $11 ; 17 FLAG +RTCLOK = $12 ; 18 3 BYTES, MSB FIRST +BUFADR = $15 ; 21 INDIRECT BUFFER ADDRESS +ICCOMT = $17 ; 23 COMMAND FOR VECTOR +DSKFMS = $18 ; 24 DISK FILE MANAGER POINTER +DSKUTL = $1A ; 26 DISK UTILITY POINTER (DUP.SYS) +PTIMOT = $1C ; 28 (800) PRINTER TIME OUT REGISTER +ABUFPT = $1C ; 28 (XL) RESERVED +PBPNT = $1D ; 29 (800) PRINTER BUFFER POINTER +; $1D ; 29 (XL) RESERVED +PBUFSZ = $1E ; 30 (800) PRINTER BUFFER SIZE +; $1E ; 30 (XL) RESERVED +PTEMP = $1F ; 31 (800) TEMPORARY REGISTER (PTEMP deleted in XL OS) +; $1F ; 31 (XL) RESERVED +ZIOCB = $20 ; 32 ZERO PAGE IOCB +ICHIDZ = $20 ; 32 HANDLER INDEX NUMBER (ID) +ICDNOZ = $21 ; 33 DEVICE NUMBER +ICCOMZ = $22 ; 34 COMMAND +ICSTAZ = $23 ; 35 STATUS +ICBALZ = $24 ; 36 BUFFER POINTER LOW BYTE +ICBAHZ = $25 ; 37 BUFFER POINTER HIGH BYTE +ICPTLZ = $26 ; 38 PUT ROUTINE POINTER LOW +ICPTHZ = $27 ; 39 PUT ROUTINE POINTER HIGH +ICBLLZ = $28 ; 40 BUFFER LENGTH LOW +ICBLHZ = $29 ; 41 +ICAX1Z = $2A ; 42 AUXILIARY INFORMATION BYTE 1 +ICAX2Z = $2B ; 43 +ICSPRZ = $2C ; 44 TWO SPARE BYTES (CIO USE) +ICIDNO = $2E ; 46 IOCB NUMBER X 16 +CIOCHR = $2F ; 47 CHARACTER BYTE FOR CURRENT OPERATION +; +STATUS = $30 ; 48 STATUS STORAGE +CHKSUM = $31 ; 49 SUM WITH CARRY ADDED BACK +BUFRLO = $32 ; 50 DATA BUFFER LOW BYTE +BUFRHI = $33 ; 51 +BFENLO = $34 ; 52 ADDRESS OF LAST BUFFER BYTE +1 (LOW) +BFENHI = $35 ; 53 +CRETRY = $36 ; 54 (800) NUMBER OF COMMAND FRAME RETRIES +XL_LTEMP = $36 ; 54 (XL) LOADER TEMPORARY STORAGE, 2 BYTES +DRETRY = $37 ; 55 (800) DEVICE RETRIES +BUFRFL = $38 ; 56 BUFFER FULL FLAG +RECVDN = $39 ; 57 RECEIVE DONE FLAG +XMTDON = $3A ; 58 TRANSMISSION DONE FLAG +CHKSNT = $3B ; 59 CHECKSUM-SENT FLAG +NOCKSM = $3C ; 60 CHECKSUM-DOES-NOT-FOLLOW-DATA FLAG +BPTR = $3D ; 61 +FTYPE = $3E ; 62 +FEOF = $3F ; 63 +FREQ = $40 ; 64 +; +SOUNDR = $41 ; 65 0=QUIET I/O +CRITIC = $42 ; 66 CRITICAL FUNCTION FLAG, NO DEFFERED VBI +FMSZPG = $43 ; 67 DOS ZERO PAGE, 7 BYTES +CKEY = $4A ; 74 (800) START KEY FLAG +XL_ZCHAIN = $4A ; 74 (XL) HANDLER LOADER TEMP, 2 BYTES +CASSBT = $4B ; 75 (800) CASSETTE BOOT FLAG +DSTAT = $4C ; 76 DISPLAY STATUS +; +ATRACT = $4D ; 77 +DRKMSK = $4E ; 78 ATTRACT MASK +COLRSH = $4F ; 79 ATTRACT COLOR SHIFTER (EORed WITH GRAPHICS) +; +TMPCHR = $50 ; 80 +HOLD1 = $51 ; 81 +LMARGN = $52 ; 82 SCREEN LEFT MARGIN REGISTER +RMARGN = $53 ; 83 SCREEN RIGHT MARGIN +ROWCRS = $54 ; 84 CURSOR ROW +COLCRS = $55 ; 85 CURSOR COLUMN, 2 BYTES +DINDEX = $57 ; 87 DISPLAY MODE +SAVMSC = $58 ; 88 SCREEN ADDRESS +OLDROW = $5A ; 90 CURSOR BEFORE DRAW OR FILL +OLDCOL = $5B ; 91 +OLDCHR = $5D ; 93 DATA UNDER CURSOR +OLDADR = $5E ; 94 CURSOR ADDRESS +XL_FKDEF = $60 ; 96 (XL) FUNCTION KEY DEFINITION POINTER (LSB/MSB) +NEWROW = $60 ; 96 (800) DRAWTO DESTINATION +NEWCOL = $61 ; 97 (800) DRAWTO DESTINATION, 2 BYTES +XL_PALNTS = $62 ; 98 (XL) EUROPE/NORTH AMERICA TV FLAG +LOGCOL = $63 ; 99 LOGICAL LINE COLUMN POINTER +MLTTMP = $66 ; 102 +OPNTMP = $66 ; 102 TEMPORARY STORAGE FOR CHANNEL OPEN +SAVADR = $68 ; 104 +RAMTOP = $6A ; 106 START OF ROM (END OF RAM + 1), HIGH BYTE ONLY +BUFCNT = $6B ; 107 BUFFER COUNT +BUFSTR = $6C ; 108 POINTER USED BY EDITOR +BITMSK = $6E ; 110 POINTER USED BY EDITOR +SHFAMT = $6F ; 111 +ROWAC = $70 ; 112 +COLAC = $72 ; 114 +ENDPT = $74 ; 116 +DELTAR = $76 ; 118 +DELTAC = $77 ; 119 +ROWINC = $79 ; 121 (800) +XL_KEYDEF = $79 ; 121 (XL) KEY DEFINITION POINTER, 2 BYTES +COLINC = $7A ; 122 (800) +SWPFLG = $7B ; 123 NON 0 IF TEXT AND REGULAR RAM IS SWAPPED +HOLDCH = $7C ; 124 CH MOVED HERE BEFORE CTRL AND SHIFT +INSDAT = $7D ; 125 used by S: handler, tmp for char under cursor +COUNTR = $7E ; 126 used by XIO DRAW command (2 bytes) + +; $80 to $FF are free if BASIC and floating point are not used. +; If BASIC is not used, but FP is, $80 to $D0 are still free. +; There is no way to use BASIC without constantly using FP, as all BASIC +; numbers are FP (even "integers" such as line numbers). +ZROFRE = $80 ; 128 FREE ZERO PAGE, 84 BYTES + +; BASIC zero page variables: +LOMEM = $80 ; 128 LSB, BASIC start-of-memory pointer +; $81 ; 129 MSB, LOMEM (not to be confused with the OS's MEMLO!) +VNTP = $82 ; 130 LSB, BASIC start of Variable Name Table pointer +; $83 ; 131 MSB, VNTP +VNTD = $84 ; 132 LSB, BASIC end of Variable Name Table pointer (+1 byte) +; $85 ; 133 MSB, VNTP +VVTP = $86 ; 134 LSB, BASIC start of Variable Value Table pointer +; $87 ; 135 MSB, VVTP +STMTAB = $88 ; 136 LSB, BASIC start of Statement Table pointer +; $89 ; 137 MSB, STMTAB +STMCUR = $8A ; 138 LSB, BASIC current statement pointer +; $8B ; 139 MSB, STMCUR +STARP = $8C ; 140 LSB, BASIC current string/array table pointer +; $8D ; 141 MSB, STARP (also points to end of BASIC program) +RUNSTK = $8E ; 142 LSB, BASIC runtime stack pointer +; $8F ; 143 MSG, RUNSTK +; BASIC and the OS both use the name MEMTOP; I've renamed the BASIC one. +BAS_MEMTOP = $90 ; 144 LSB, pointer to top of BASIC memory +; $91 ; 145 MSB, BAS_MEMTOP +MEOLFLG = $92 ; 146 "modified EOL flag register", whatever that is +; $93 ; 147 listed as "spare" by Mapping's Errata +;COX = $94 ; 148 current output index (?) +POKADR = $95 ; 149 LSB, address of last POKE location +; ; 150 MSB, POKADR + +; Locations $96 to $B5 are used for various purposes by BASIC, +; and most of them are of little or no interest, even for someone +; writing assembly code meant to run as a USR() routine, so I haven't +; bothered listing them all here. See Compute! Books' "Atari BASIC Sourcebook" +; for the gory details. In fact, you can see it here: + +; http://users.telenet.be/kim1-6502/6502/absb.html + +; It's fascinating (at least it is to me)... includes full source code +; to Atari BASIC! + +; DATAD and DATALN are reset to 0 by BASIC RESTORE command. +DATAD = $B6 ; 182 the data element being read (e.g. 10 for 10th item + ; in a DATA statement) +DATALN = $B7 ; 183 LSB current DATA statement line number +; $B8 ; 184 MSB, DATALN +;ERRNUM = $B9 ; 185 Most recent error number. Gets cleared before you + ; can PEEK it; use ERRSAVE instead. +STOPLN = $BA ; 186 LSB, line where a program stopped by STOP/break/error +; $BB ; 187 MSB, STOPLN +; what are $BC and $BD for? +SAVCUR = $BE ; 190 Saves the current line address (LSB?) +; $BF ; 191 presumably, the MSB of SAVCUR? +IOCMD = $C0 ; 192, I/O Command (Mapping Errata) +IODVC = $C1 ; 193, I/O Device (Mapping Errata) +PROMPT = $C2 ; 194, Prompt character (Mapping Errata, presumably INPUT?) +ERRSAVE = $C3 ; 195 Error code that caused a stop or TRAP +;TEMPA = $C4 ; 196 a 2-byte temp +;ZTEMP2 = $C6 ; 198 a 2-byte temp +COLOR = $C8 ; 200 Stores color from COLOR command +PTABW = $C9 ; 201 Number of columns between tab stops + ; (for PRINT with commas, not the TAB key) +LOADFLG = $CA ; 202 Load in progress flag. I can tell you from bitter + ; experience that BASIC clears this often. + +; $CB - $CF are unused by BASIC or the ASM/ED cart. +; $D0 and $D1 are unused by BASIC (does that mean they *are* used by ASM/ED?) + +; $D2 and $D3 are used by BASIC. Mapping Errata calls them the "BASIC +; floating-point work area". They get cleared to 0 by BASIC, probably +; every time a FP number is used (e.g. "POKE 210,1:? PEEK(210)" prints 0). +; The BASIC source code labels $D2 as TVTYPE and VTYPE, and $D3 as +; TVNUM and VNUM. + +; Floating point zero page variables: +FPZRO = $D4 ; 212 FLOATING POINT RAM, 43 BYTES + ; (20070530 bkw: pretty sure that comment is wrong, and + ; should read 44 bytes; see $FF below) +FR0 = $D4 ; 212 FP REGISTER 0 (also used by BASIC for USR() return val) + ; (FR0/FRE/FR1/FR2 are each 6 bytes long) +FRE = $DA ; 218 +FR1 = $E0 ; 224 FP REGISTER 1 +FR2 = $E6 ; 230 FP REGISTER 2 +FRX = $EC ; 236 SPARE +EEXP = $ED ; 237 VALUE OF E +NSIGN = $ED ; 237 SIGN OF FP NUMBER +ESIGN = $EF ; 239 SIGN OF FP EXPONENT +FCHFLG = $F0 ; 240 FIRST CHARACTER FLAG +DIGRT = $F1 ; 241 NUMBER OF DIGITS RIGHT OF DECIMAL POINT +CIX = $F2 ; 242 INPUT INDEX +INBUFF = $F3 ; 243 POINTER TO ASCII FP NUMBER +ZTEMP1 = $F5 ; 245 +ZTEMP4 = $F7 ; 247 +ZTEMP3 = $F9 ; 249 +DEGFLG = $FB ; 251 +RADFLG = $FB ; 251 0=RADIANS, 6=DEGREES +FLPTR = $FC ; 252 POINTER TO BCD FP NUMBER (2 bytes) +FPTR2 = $FE ; 254 maybe a 2nd pointer to an FP number? (2 bytes) +; $FF ; 255 This *definitely* is used by the FP package + ; Try: POKE 255,0:? SIN(1):? PEEK(255) + +; +; PAGE 1 +; +; 65O2 STACK +; +; + +; +; +; PAGE 2 +; +; +; 20070529 bkw: Bytes listed as "spare" should NOT be used for your own +; purposes. They may not really be unused (just undocumented), and/or they +; may be unused on the 800 but not the XL (or vice versa). +INTABS = $0200 ; 512 INTERRUPT RAM +VDSLST = $0200 ; 512 NMI VECTOR +VPRCED = $0202 ; 514 PROCEED LINE IRQ VECTOR +VINTER = $0204 ; 516 INTERRUPT LINE IRQ VECTOR +VBREAK = $0206 ; 518 break key IRQ vector (not in OS rev. A) +VKEYBD = $0208 ; 520 keyboard IRQ vector (not break/console keys) +VSERIN = $020A ; 522 SERIAL INPUT READY IRQ +VSEROR = $020C ; 524 SERIAL OUTPUT READY IRQ +VSEROC = $020E ; 526 SERIAL OUTPUT COMPLETE IRQ +VTIMR1 = $0210 ; 528 TIMER 1 IRQ vector +VTIMR2 = $0212 ; 530 TIMER 2 IRQ vector +VTIMR4 = $0214 ; 532 TIMER 4 IRQ vector +VIMIRQ = $0216 ; 534 IRQ VECTOR +CDTMV1 = $0218 ; 536 COUNTDOWN TIMER 1 vector +CDTMV2 = $021A ; 538 COUNTDOWN TIMER 2 vector +CDTMV3 = $021C ; 540 COUNTDOWN TIMER 3 vector +CDTMV4 = $021E ; 542 COUNTDOWN TIMER 4 vector +CDTMV5 = $0220 ; 544 COUNTDOWN TIMER 5 vector +VVBLKI = $0222 ; 546 immediate VBLANK vector +VVBLKD = $0224 ; 548 deferred VBLANK vector (ignore if CRITIC != 0) +CDTMA1 = $0226 ; 550 COUNTDOWN TIMER 1 JSR ADDRESS +CDTMA2 = $0228 ; 552 COUNTDOWN TIMER 2 JSR ADDRESS +CDTMF3 = $022A ; 554 COUNTDOWN TIMER 3 FLAG +SRTIMR = $022B ; 555 REPEAT TIMER +CDTMF4 = $022C ; 556 COUNTDOWN TIMER 4 FLAG +INTEMP = $022D ; 557 IAN'S TEMP (used by SETVBL routine) +CDTMF5 = $022E ; 558 COUNTDOWN TIMER FLAG 5 +SDMCTL = $022F ; 559 DMACTL SHADOW +SDLSTL = $0230 ; 560 DISPLAY LIST POINTER, LSB (shadow for DLISTL) +SDLSTH = $0231 ; 561 display list pointer, MSB (shadow for DLISTH) +SSKCTL = $0232 ; 562 SKCTL SHADOW +; $0233 ; 563 (800) UNLISTED (Mapping calls this SPARE) +XL_LCOUNT = $0233 ; 563 (XL) LOADER TEMP +LPENH = $0234 ; 564 LIGHT PEN HORIZONTAL (shadow for PENH) +LPENV = $0235 ; 565 LIGHT PEN VERTICAL (shadow for PENV) +; $0236 ; 566 2 SPARE BYTES on OS rev A +VBRKKY = $0236 ; 566 Break key interrupt vector (OS rev B and XL) +BRKKY = VBRKKY ; "OS rev 5" listing calls it this +; $0238 ; 568 (800) SPARE, 2 BYTES +;XL_RELADR = $0238 ; 568 (XL) relocatable loader relative addr, 1200XL only! +XL_VPIRQ = $0238 ; 568 (XL) PBI IRQ vector (not on 1200XL!) +CDEVIC = $023A ; 570 DEVICE COMMAND FRAME BUFFER +CAUX1 = $023C ; 572 DEVICE COMMAND AUX 1 +CAUX2 = $023D ; 573 DEVICE COMMAND AUX 2 +TEMP = $023E ; 574 TEMPORARY STORAGE +ERRFLG = $023F ; 575 DEVICE ERROR FLAG (EXCEPT TIMEOUT) +DFLAGS = $0240 ; 576 FLAGS FROM DISK SECTOR 1 +DBSECT = $0241 ; 577 NUMBER OF BOOT DISK SECTORS +BOOTAD = $0242 ; 578 BOOT LOAD ADDRESS POINTER +COLDST = $0244 ; 580 COLD START FLAG, 1 = COLD START IN PROGRESS +; $0245 ; 581 (800) SPARE +XL_RECLEN = $0245 ; 581 (XL) LOADER +DSKTIM = $0246 ; 582 (800) DISK TIME OUT REGISTER +; $0246 ; 582 (XL) RESERVED, 39 BYTES +LINBUF = $0247 ; 583 (800) CHARACTER LINE BUFFER, 40 BYTES + ; LINBUF was deleted from the XL OS and replaced with: + +; $0247 - $024D are "reserved" on the 1200XL. On other XL's they are: +XL_PDVMSK = $0247 ; 583 shadow for PBI device selection register @ $D1FF +XL_SHPDVS = $0248 ; 584 shadow for PBI register (where??) +XL_PDMSK = $0249 ; 585 PBI interrupt mask +XL_RELADR = $024A ; 586 (XL) LSB, relocatable loader relative addr (NOT 1200XL) +; $024B ; 587 MSB, XL_RELADR +XL_PPTMPA = $024C ; 588 temporaries for relocatable loader +XL_PPTMPX = $024D ; 589 " + +; $024E - $026A are "spare" on all XL/XE's + +; More XL stuff: +XL_CHSALT = $026B ; 619 (XL) CHARACTER SET POINTER (ctrl-F4 on 1200XL) +XL_VSFLAG = $026C ; 620 (XL) FINE SCROLL TEMPORARY +XL_KEYDIS = $026D ; 621 (XL) KEYBOARD DISABLE (ctrl-F1 on 1200XL) +XL_FINE = $026E ; 622 (XL) FINE SCROLL FLAG (POKE 622,255:GR.0) + +GPRIOR = $026F ; 623 P/M PRIORITY AND GTIA MODES (shadow for PRIOR) +;GTIA = $026F ; 623 ; 20070529 bkw: does anyone define this? + +; Game controller shadows (joysticks/paddles) +; Joystick directions and paddle triggers (buttons) are wired to the PIA. +; Joystick triggers (fire buttons) and the actual paddle potentiometers +; are wired to the GTIA. +; If this seems a little odd, that's because it is :) + +; Paddles (potentiometers): +PADDL0 = $0270 ; 624 (XL) 3 MORE PADDLES, (800) 7 MORE PADDLES +PADDL1 = $0271 ; 625 (these are read in BASIC with PADDLE(x) +PADDL2 = $0272 ; 626 (PADDL0-7 are shadows for POT0-7) +PADDL3 = $0273 ; 627 +PADDL4 = $0274 ; 628 (PADDL4-7 are copies of PADDL0-3 on the XL) +PADDL5 = $0275 ; 629 +PADDL6 = $0276 ; 630 +PADDL7 = $0277 ; 631 + +; Joysticks (directions only) +STICK0 = $0278 ; 632 (XL) 1 MORE STICK, (800) 3 MORE STICKS +STICK1 = $0279 ; 633 (these are read in BASIC with STICK(x) +STICK2 = $027A ; 634 (STICK0/1 are shadows for PORTA; STICK2/3 shadows PORTB) +STICK3 = $027B ; 635 +; STICK0 is a shadow for bits 4-7 of PORTA (shifted 4 bits right) +; STICK1 is a shadow for bits 0-3 of PORTA + +; On the 800: +; STICK2 is a shadow for bits 4-7 of PORTB (shifted 4 bits right) +; STICK3 is a shadow for bits 0-3 of PORTB + +; On the XL/XE series: +; STICK2 and STICK3 are copies of STICK0 and STICK1, respectively. + +; In the XL/XE machines, there are only 2 joystick ports, and PORTB +; (formerly joystick ports) is now used to control the MMU. + +; joystick directions are active low (1=not pressed) and decode as: + +; bit direction +; 0 or 4 up +; 1 or 5 down +; 2 or 6 left +; 3 or 7 right + +; A value of $0F in a STICKx register means no direction is being pressed. +; When a direction is pressed, its bit becomes a logic 0, so e.g. $0E means +; someone's moving the joystick up. + +; (bits 4-7 are only used when reading directly from the HW registers, +; PORTA and PORTB). + +; Paddle triggers (buttons) +PTRIG0 = $027C ; 636 (XL) 3 MORE PADDLE TRIGGERS, (800) 7 MORE +PTRIG1 = $027D ; 637 (these are read in BASIC with PTRIG(x)) +PTRIG2 = $027E ; 638 (PTRIG0-3 are shadows for PORTA) +PTRIG3 = $027F ; 639 +PTRIG4 = $0280 ; 640 (PTRIG4-7 are shadows for PORTB on the 800) +PTRIG5 = $0281 ; 641 (they are copies of PTRIG0-3 on the XL) +PTRIG6 = $0282 ; 642 +PTRIG7 = $0283 ; 643 +; In case someone doesn't already know this: The paddle triggers are wired +; to the same pins on the joystick port as the left/right joystick directions. +; Each pair of paddles uses left for the first paddle's trigger and right +; for the second (so PTRIG0/1 are also the left/right bits in STICK0, +; PTRIG2/3 are STICK1, etc). + +; Joystick triggers (buttons) +STRIG0 = $0284 ; 644 (XL) 1 MORE STICK TRIGGER, (800) 3 MORE +STRIG1 = $0285 ; 645 (these are read in BASIC with STRIG(x)) +STRIG2 = $0286 ; 646 (STRIG0-3 are shadows for TRIG0-3) +STRIG3 = $0287 ; 647 + +; C: handler variables: +CSTAT = $0288 ; 648 (800) Cassette status register +; note that CSTAT was deleted from the XL OS, and replaced with: +XL_HIBYTE = $0288 ; 648 (XL) used by relocatable loader +WMODE = $0289 ; 649 used by C: handler (0=read, 128-write) +BLIM = $028A ; 650 cassette buffer data record size +; $028B ; 651 (800) 5 SPARE BYTES (to $028F) +XL_IMASK = $028B ; 651 (XL) used by relocatable loader +XL_JVECK = $028C ; 652 (XL) (Mapping says it's unused) + ; 653 (XL) Presumably the MSB of JVECK (unused?) +XL_NEWADR = $028E ; 654 (XL) LOADER RAM (2 bytes) + +; Misc. S: and/or E: handler variables: +TXTROW = $0290 ; 656 +TXTCOL = $0291 ; 657 +TINDEX = $0293 ; 659 TEXT INDEX +TXTMSC = $0294 ; 660 +TXTOLD = $0296 ; 662 OLD ROW AND OLD COL FOR TEXT, 2 BYTES +; $0298 ; 664 4 SPARE BYTES +TMPX1 = $029C ; 668 (800) +; note that TMPX1 was deleted from the XL OS, and replaced with: +XL_CRETRY = $029C ; 668 (XL) NUMBER OF COMMAND FRAME RETRIES + ; (moved from CRETRY on 800) +SUBTMP = $029E ; 670 +HOLD2 = $029F ; 671 +DMASK = $02A0 ; 672 +TMPLBT = $02A1 ; 673 +ESCFLG = $02A2 ; 674 +TABMAP = $02A3 ; 675 15 BYTE BIT MAP FOR TAB SETTINGS +LOGMAP = $02B2 ; 690 4 BYTE LOGICAL LINE START BIT MAP +INVFLG = $02B6 ; 694 mask for inverse video ($80=inverse, 0=normal) +FILFLG = $02B7 ; 695 FILL DURING DRAW FLAG +TMPROW = $02B8 ; 696 +TMPCOL = $02B9 ; 697 +SCRFLG = $02BB ; 699 SCROLL FLAG +HOLD4 = $02BC ; 700 +HOLD5 = $02BD ; 701 (800) +; note that HOLD5 was deleted from the XL OS, and replaced with: +XL_DRETRY = $02BD ; 701 (XL) NUMBER OF DEVICE RETRIES + ; (moved from DRETRY on 800) +SHFLOC = $02BE ; 702 +BOTSCR = $02BF ; 703 24 NORM, 4 SPLIT + +; Color register shadows (HW registers are in GTIA) +PCOLR0 = $02C0 ; 704 3 MORE PLAYER COLOR REGISTERS (shadows for COLPM0-3) +PCOLR1 = $02C1 ; 705 (missiles use same color regs as same-numbered players!) +PCOLR2 = $02C2 ; 706 +PCOLR3 = $02C3 ; 707 +COLOR0 = $02C4 ; 708 4 MORE GRAPHICS COLOR REGISTERS (shadows for COLPF0-3) +COLOR1 = $02C5 ; 709 (text luminance in GR.0) +COLOR2 = $02C6 ; 710 (text background and chroma in GR.0) +COLOR3 = $02C7 ; 711 +COLOR4 = $02C8 ; 712 (background, shadow for COLBK) +; On boot, system reset, or any time S:/E: devices are opened: +; PCOLR0-3 are initialzed to 0 ($00, black) +; COLOR0 is initialized to 40 ($28, orange) +; COLOR1 is initialized to 202 ($CA, green) +; COLOR2 is initialized to 148 ($94, blue) +; COLOR3 is initialized to 70 ($46, red) +; COLOR4 is initialized to 0 ($00, black) + +; $02C9 713 (800) 23 SPARE BYTES +; XL relocatable handler and other variables: +XL_RUNADR = $02C9 ; 713 (XL) LOADER VECTOR +XL_HIUSED = $02CB ; 715 (XL) LOADER VECTOR +XL_ZHIUSE = $02CD ; 717 (XL) LOADER VECTOR +XL_GBYTEA = $02CF ; 719 (XL) LOADER VECTOR +XL_LOADAD = $02D1 ; 721 (XL) LOADER VECTOR +XL_ZLOADA = $02D3 ; 723 (XL) LOADER VECTOR +XL_DSCTLN = $02D5 ; 725 (XL) DISK SECTOR SIZ +XL_ACMISR = $02D7 ; 727 (XL) RESERVED +XL_KRPDER = $02D9 ; 729 (XL) KEY AUTO REPEAT DELAY +XL_KEYREP = $02DA ; 730 (XL) KEY AUTO REPEAT RATE +XL_NOCLIK = $02DB ; 731 (XL) KEY CLICK DISABLE (ctrl-F3 on 1200XL) +XL_HELPFG = $02DC ; 732 (XL) HELP KEY FLAG +XL_DMASAV = $02DD ; 733 (XL) SDMCTL (DMA) SAVE (ctrl-F2 on 1200XL) +XL_PBPNT = $02DE ; 734 (XL) PRINTER BUFFER POINTER (moved from PBPNT on 800) +XL_PBUFSZ = $02DF ; 735 (XL) PRINTER BUFFER SIZE (moved from PBUFSZ on 800) +; note that PTEMP was deleted from the XL OS + +; DOS/FMS variables: +GLBABS = $02E0 ; 736 GLOBAL VARIABLES, 4 SPARE BYTES (if DOS not loaded) + ; If DOS/FMS is loaded: +RUNAD = $02E0 ; 736 (DOS) Run address for binary file (LSB/MSB) +INITAD = $02E2 ; 736 (DOS) Init address for binary file (LSB/MSB) + +; SYSEQU.ASM defines these: +GOADR = RUNAD +INITADR = INITAD + +; OS variables: +RAMSIZ = $02E4 ; 740 PERMANENT START OF ROM POINTER +MEMTOP = $02E5 ; 741 END OF FREE RAM +MEMLO = $02E7 ; 743 LSB, points to bottom of free memory ($0700 if DOS + ; not booted). Not to be confused with BASIC's LOMEM! +; $02E8 ; 744 MSB of MEMLO + +; $02E9 ; 745 (800) SPARE +XL_HNDLOD = $02E9 ; 745 (XL) HANDLER LOADER FLAG + +DVSTAT = $02EA ; 746 DEVICE STATUS BUFFER, 4 BYTES +CBAUDL = $02EE ; 750 CASSETTE BAUD RATE, 2 BYTES +CRSINH = $02F0 ; 752 1 = INHIBIT CURSOR +KEYDEL = $02F1 ; 753 KEY DELAY AND RATE (aka debounce counter) +CH1 = $02F2 ; 754 prior keyboard character code +CHACT = $02F3 ; 755 (shadow for CHACTL) +CHBAS = $02F4 ; 756 CHARACTER SET POINTER (shadow for CHBASE) + +; These next 4 are located elsewhere on the 800 OS: +XL_NEWROW = $02F5 ; 757 (XL) DRAW DESTINATION +XL_NEWCOL = $02F6 ; 758 (XL) DRAW DESTINATION +XL_ROWINC = $02F8 ; 760 (XL) +XL_COLINC = $02F9 ; 761 (XL) +; $02F5 - $02F9 are "spare" on the 800. + +CHAR = $02FA ; 762 most recent character read/written (screen code) +ATACHR = $02FB ; 763 ATASCII CHARACTER FOR CIO +CH = $02FC ; 764 last key pressed (internal scan code) +FILDAT = $02FC ; 764 COLOR FOR SCREEN FILL +DSPFLG = $02FE ; 766 DISPLAY CONTROL CHARACTERS FLAG +SSFLAG = $02FF ; 767 DISPLAY START/STOP FLAFG + +; +; PAGE 3 +; +; +; RESIDENT DISK HANDLER/SIO INTERFACE +; +; The DCB is used for SIO (serial I/O). +DCB = $0300 ; 768 DEVICE CONTROL BLOCK +DDEVIC = $0300 ; 768 device ID ($31-$38 for D1:-D8:) +DUNIT = $0301 ; 769 disk/device unit numder +DCOMND = $0302 ; 770 device command +DSTATS = $0303 ; 771 status code (set by OS) +DBUFLO = $0304 ; 772 data buffer LSB (set by user) +DBUFHI = $0305 ; 773 data buffer MSB (set by user) +DTIMLO = $0306 ; 774 timeout (set by user, units of 60/64 seconds) +DUNUSE = $0307 ; 775 unused +DBYTLO = $0308 ; 776 number of bytes to transfer, LSB +DBYTHI = $0309 ; 777 number of bytes to transfer, MSB +DAUX1 = $030A ; 778 LSB of sector number (for disk) (set by user) +DAUX2 = $030B ; 779 MSB of sector number (for disk) +TIMER1 = $030C ; 780 INITIAL TIMER VALUE +ADDCOR = $030E ; 782 (800) ADDITION CORRECTION +; note that ADDCOR was deleted from the XL OS, and replaced with: +XL_JMPERS = $030E ; 782 (XL) OPTION JUMPERS +CASFLG = $030F ; 783 CASSETTE MODE WHEN SET +TIMER2 = $0310 ; 784 FINAL VALUE, TIMERS 1 & 2 DETERMINE BAUD RATE +TEMP1 = $0312 ; 786 +XL_TEMP2 = $0313 ; 787 (XL) +TEMP2 = $0314 ; 788 (800) +XL_PTIMOT = $0314 ; 788 (XL) PRINTER TIME OUT +TEMP3 = $0315 ; 789 +SAVIO = $0316 ; 790 SAVE SERIAL IN DATA PORT +TIMFLG = $0317 ; 791 TIME OUT FLAG FOR BAUD RATE CORRECTION +STACKP = $0318 ; 792 SIO STACK POINTER SAVE +TSTAT = $0319 ; 793 TEMPORARY STATUS HOLDER +HATABS = $031A ; 794 HANDLER ADDRESS TABLE, 38 BYTES +MAXDEV = $0321 ; 801 MAXIMUM HANDLER ADDRESS INDEX +XL_PUPBT1 = $033D ; 829 (XL) POWER-UP/RESET +XL_PUPBT2 = $033E ; 830 (XL) POWER-UP/RESET +XL_PUPBT3 = $033F ; 831 (XL) POWER-UP/RESET + +; IOCB's, 8 of them, 16 bytes each. +; Set X register to (IOCB number * 16), and use e.g. ICCOM,x +; +IOCB = $0340 ; 832 ; IOCB base address +ICHID = $0340 ; 832 ; Handler ID (set by OS) +ICDNO = $0341 ; 833 ; Device number (set by OS) +ICCOM = $0342 ; 834 ; Command byte (see C_* constants) (set by user) +ICCMD = ICCOM ; ; alternate name for ICCOM, according to Mapping. +ICSTA = $0343 ; 835 ; Status (set by OS) +ICBAL = $0344 ; 836 ; Buffer address, LSB (set by user) +ICBAH = $0345 ; 837 ; Buffer address, MSB (set by user) +ICPTL = $0346 ; 838 ; Put-one-byte address minus one, LSB (set by OS) +ICPTH = $0347 ; 839 ; Put-one-byte address minus one, MSB (set by OS) +ICBLL = $0348 ; 840 ; Buffer length, LSB (set by user) +ICBLH = $0349 ; 841 ; Buffer length, MSB (set by user) +ICAX1 = $034A ; 842 ; AUX1 byte (2nd param in BASIC OPEN) (set by user) +ICAX2 = $034B ; 843 ; AUX2 byte (4rd param in BASIC OPEN) (set by user) +ICAX3 = $034C ; 844 ; AUX3 byte (used by NOTE/POINT) (set by user) +ICAX4 = $034D ; 845 ; AUX4 byte (used by NOTE/POINT) (set by user) +ICAX5 = $034E ; 846 ; AUX5 byte (used by NOTE/POINT) (set by user) +ICAX6 = $034F ; 847 ; Spare aux byte +; OTHER IOCB's, 112 BYTES ($300 + $10 * channel) + +IOCBLEN = ICAX6-IOCB+1 ; length of one IOCB (from SYSEQU.ASM) + +; Alternative names for the above. I found these in SYSEQU.ASM, as +; distributed with the disk version of Mac65. +ICBADR = ICBAL +ICPUT = ICPTL +ICBLEN = ICBLL +ICAUX1 = ICAX1 +ICAUX2 = ICAX2 +ICAUX3 = ICAX3 +ICAUX4 = ICAX4 +ICAUX5 = ICAX5 +ICAUX6 = ICAX6 + +PRNBUF = $03C0 ; 960 PRINTER BUFFER, 40 BYTES +; $03E8 ; 1000 (800) 21 SPARE BYTES +XL_SUPERF = $03E8 ; 1000 (XL) SCREEN EDITOR +XL_CKEY = $03E9 ; 1001 (XL) START KEY FLAG +XL_CASSBT = $03EA ; 1002 (XL) CASSETTE BOOT FLAG +XL_CARTCK = $03EB ; 1003 (XL) CARTRIDGE CHECKSUM +XL_ACMVAR = $03ED ; 1005 (XL) RESERVED, 10 BYTES (to $03F7) +XL_BASICF = $03F8 ; 1006 (XL) 0 if ROM-BASIC enabled, 1 if not +XL_MINTLK = $03F9 ; 1017 (XL) RESERVED +XL_GINTLK = $03FA ; 1018 (XL) CARTRIDGE INTERLOCK +XL_CHLINK = $03FB ; 1019 (XL) HANDLER CHAIN, 2 BYTES +CASBUF = $03FD ; 1021 CASSETTE BUFFER, 131 BYTES TO $047F + +; Layout of the cassette buffer after a cassette block is read: + +; Baud correction ($55 $55) bytes are located at offsets 0 and 1 +; Control byte is at offset 2 ($03FF): +; Actual data (128 bytes) runs from offset 3 ($0400) to $047F. +; Each cassette frame has a 1 byte checksum after the 128 data bytes, but +; the checksum is NOT stored anywhere in the cassette buffer! + +; CONTROL BYTE VALUES +; Value Meaning +; 250 ($FA) Partial record follows. The actual number of bytes is stored +; in the last byte of the record (CASBUF+130, or $047F). +; 252 ($FC) Record full; 128 bytes follow. +; 254 ($FE) End of File (EOF) record; followed by 128 zero bytes. + +; Boot tapes normally don't have partial or EOF records, but BASIC +; CLOAD/LOAD/LIST and data file tapes do. + +; Mapping the Atari says the first disk boot sector is read into CASBUF also. + +; +; +; PAGE 4 +; +; +USAREA = $0480 ; 1152 128 SPARE BYTES (but used by BASIC) +; +; SEE APPENDIX C FOR PAGES 4 AND 5 USAGE + +; +; +; +; +; PAGE 5 +; +PAGE5 = $0500 ; 1280 127 FREE BYTES +; $057E 1406 129 FREE BYTES IF FLOATING POINT ROUTINES NOT USED +; +;FLOATING POINT NON-ZERO PAGE RAM, NEEDED ONLY IF FP IS USED +; (20070529 bkw: BASIC constantly uses FP! Also, it uses some of these +; addresses for its own purposes.) +; +LBPR1 = $057E ; 1406 LBUFF PREFIX 1 +LBPR2 = $05FE ; 1534 LBUFF PREFIX 2 +LBUFF = $0580 ; 1408 LINE BUFFER +PLYARG = $05E0 ; 1504 POLYNOMIAL ARGUMENTS +FPSCR = $05E6 ; 1510 PLYARG+FPREC +FPSCR1 = $05EC ; 1516 FPSCR+FPREC +FSCR = $05E6 ; 1510 =FPSCR +FSCR1 = $05EC ; 1516 =FPSCR1 +LBFEND = $05FF ; 1535 END OF LBUFF + +; +; PAGE 6 +; +; +PAGE6 = $0600 ; 1536 256 FREE BYTES + +; +; +; PAGE 7 +; +; +BOOTRG = $0700 ; 1792 PROGRAM AREA +; Boot disks (including DOS) are generally loaded here. Also, BASIC RAM +; (variables and program) starts here, if BASIC is booted without DOS. + +; Page 80 (XL): Self-test (aka diagnostic) ROM is mapped at $5000, +; if enabled with bit 7 of PORTB. Normally only happens if you boot without +; BASIC, cartridge, tape, or disk... or if the OS detects a memory error +; during boot. + +; +; +; UPPER ADDRESSES +; +; +RITCAR = $8000 ;32768 RAM IF NO CARTRIDGE (extends to $9FFF) +LFTCAR = $A000 ;40960 RAM IF NO CARTRIDGE (extends to $BFFF) + +; These 2 are from the Atari System Reference Manual, chapter 12: +CARTA = LFTCAR +CARTB = RITCAR + +CARTLOC = $BFFA ;49146 cartridge run address (from SYSEQU.ASM) + +; Carts were originally 8K only when the 400/800 were first released. +; There were plans to release 16K programs on two cartridges, but this +; never happened (the price of 16K ROMs came down, I guess). 16K cartridges +; go in the left slot, but they actually use the address space for both +; the right and left slots. + +; Mapping the Atari has this to say about cartridges: +;; Byte Purpose +;; Left (A) Right(B) +;; 49146 ($BFFA) 40954 ($9FFA) Cartridge start address (low byte) +;; +;; 49147 ($BFFB) 40955 ($9FFB) Cartridge start address (high byte) +;; +;; 49148 ($BFFC) 40956 ($9FFC) Reads zero if a cartridge is +;; inserted, non-zero when no cartridge is present. This information +;; is passed down to the page zero RAM: if the A cartridge is plugged +;; in, then location 6 will read one; if the B cartridge is plugged in, +;; then location 7 will read one; otherwise they will read zero. +;; +;; 49149 ($BFFD) 40957 ($9FFD) Option byte. If BIT 0 equals one, +;; then boot the disk (else there is no disk boot). If BIT 2 equals one, +;; then initialize and start the cartridge (else initialize but do not +;; start). If BIT 7 equals one, then the cartridge is a diagnostic +;; cartridge which will take control, but not initialize the OS (else +;; non-diagnostic cartridge). Diagnostic cartridges were used by +;; Atari in the development of the system and are not available to the +;; public. +;; +;; 49150 ($BFFE) 40958 ($9FFE) Cartridge initialization address +;; low byte. +;; +;; 49151 ($BFFF) 40959 ($9FFF) Cartridge initialization address +;; high byte. This is the address to which the OS will jump during all +;; powerup and RESETs. +;; +;; The OS makes temporary use of locations 36876 to 36896 ($900C to +;; $9020) to set up vectors for the interrupt handler. See the OS +;; listings pages 31 and 81. This code was only used in the +;; development system used to design the Atari. + + +; Page 192 + +C0PAGE = $C000 ;49152 (800) EMPTY, 4K BYTES + ; 20070529 bkw: unmapped address space. + ; Mapping the Atari erroneously lists this as "unused ROM". + ; There are upgrades to the 800 to give 4K of RAM here + ; (for a total of 52K of RAM), or ROM (Omnimon?). + ; Also, there is RAM here if you boot the Translator + ; disk on an XL. + +; (XL) $C000 also contains info about the ROM revision. From Mapping: + +;Bytes 49152-49163 ($C000-$C00B) are used to identify the computer +;and the ROM in the $C000-$DFFF block: +; +;Byte Use +;49152-3/C000-1 Checksum (LSB/MSB) of all the bytes +; in ROM except the checksum bytes +; themselves. +;49154/C002 Revision date, stored in the form +; DDMMYY. This is DD, day, usually $10. +;49155/C003 Revision date, month; usually $05. +;49156/C004 Revision date, year; usually $83. +;49157/C005 Reserved option byte; reads zero for +; the 1200, 800XL, and 130XE. +;49158/C006 Part number in the form AANNNNNN; +; AA is an ASCII character and +; NNNNNN is a four-bit BCD digit. This is +; byte A1. +;49159-62/C007-A Part number, bytes A2, N1-N6 (each +; byte has two N values of four bits +; each). +;49163/C00B Revision number. Mapping author's 800XL and 130XE say 2. + +;C0PAGE = $C000 ;49152 (XL) OS ROM, mostly interrupt handlers +; $C800 51200 (XL) START OF OS ROM +CHORG2 = $CC00 ;52224 (XL) INTERNATIONAL CHARACTER SET + + + +; +; +; HARDWARE REGISTERS +; +; +; SEE REGISTER LIST FOR MORE INFORMATION +; +; + +; GTIA +GTIA = $D000 +HPOSP0 = $D000 ;53248 (W) ; P/M positions (no shadows) +HPOSP1 = $D001 ;53249 (W) +HPOSP2 = $D002 ;53250 (W) +HPOSP3 = $D003 ;53251 (W) +HPOSM0 = $D004 ;53252 (W) +HPOSM1 = $D005 ;53253 (W) +HPOSM2 = $D006 ;53254 (W) +HPOSM3 = $D007 ;53255 (W) +SIZEP0 = $D008 ;53256 (W) ; P/M size regs (no shadows) +SIZEP1 = $D009 ;53257 (W) +SIZEP2 = $D00A ;53258 (W) +SIZEP3 = $D00B ;53259 (W) +SIZEM = $D00C ;53260 (W) +M0PF = $D000 ;53248 (R) ; collision regs (no shadows) +M1PF = $D001 ;53249 (R) +M2PF = $D002 ;53250 (R) +M3PF = $D003 ;53251 (R) +P0PF = $D004 ;53252 (R) +P1PF = $D005 ;53253 (R) +P2PF = $D006 ;53254 (R) +P3PF = $D007 ;53255 (R) +M0PL = $D008 ;53256 (R) +M1PL = $D009 ;53257 (R) +M2PL = $D00A ;53258 (R) +M3PL = $D00B ;53259 (R) +P0PL = $D00C ;53260 (R) +P1PL = $D00D ;53261 (R) +P2PL = $D00E ;53262 (R) +P3PL = $D00F ;53263 (R) +GRAFP0 = $D00D ;53261 (W) ; direct (non-DMA) P/M graphics regs (no shadows) +GRAFP1 = $D00E ;53262 (W) +GRAFP2 = $D00F ;53263 (W) +GRAFP3 = $D010 ;53264 (W) +GRAFM = $D011 ;53265 (W) +TRIG0 = $D010 ;53264 (R) ; Joystick triggers (shadows @ STRIG0-3) +TRIG1 = $D011 ;53265 (R) +TRIG2 = $D012 ;53266 (R) +TRIG3 = $D013 ;53267 (R) +PAL = $D014 ;53268 (R) ; PAL/NTSC detect (no shadow) + ; PAL supposedly moved to XL_PALNTS on XL; what was it + ; replaced with? +COLPM0 = $D012 ;53266 (W) ; P/M colors (shadows @ PCOLR0-3) +COLPM1 = $D013 ;53267 (W) +COLPM2 = $D014 ;53268 (W) +COLPM3 = $D015 ;53269 (W) +COLPF0 = $D016 ;53270 (W) ; Playfield colors (shadows @ COLOR0-3) +COLPF1 = $D017 ;53271 (W) +COLPF2 = $D018 ;53272 (W) +COLPF3 = $D019 ;53273 (W) +COLBK = $D01A ;53274 (W) ; Background color (shadow @ COLOR4) +PRIOR = $D01B ;53275 (W) ; GTIA priority (shadow @ GPRIOR) +GTIAR = $D01B ;53275 (R?) +VDELAY = $D01C ;53276 (W) +GRACTL = $D01D ;53277 (W) +HITCLR = $D01E ;53278 (W), latch +CONSOL = $D01F ;53279 (W=keyclick spkr, R=console keys) + +; $D020 - $D0FF are mirrors of GTIA address space +; $D100 - $D1FF are supposed to be unused (unmapped) on the 800 +; On the XL, $D100 - $D1FF is switched to device memory during PBI I/O + +; POKEY +POKEY = $D200 +; no shadows for AUDC/AUDF +AUDF1 = $D200 ;53760 (W) ; Audio frequency 1 +AUDC1 = $D201 ;53761 (W) ; Audio control 1 (distortion/volume) +AUDF2 = $D202 ;53762 (W) +AUDC2 = $D203 ;53763 (W) +AUDF3 = $D204 ;53764 (W) +AUDC3 = $D205 ;53765 (W) +AUDF4 = $D206 ;53766 (W) +AUDC4 = $D207 ;53767 (W) + +; POT0-7 shadows at PADDL0-7 +POT0 = $D200 ;53760 (R) ; Paddle positions +POT1 = $D201 ;53761 (R) +POT2 = $D202 ;53762 (R) +POT3 = $D203 ;53763 (R) +POT4 = $D204 ;53764 (R) ; pots 3-7 don't exist on XL/XE +POT5 = $D205 ;53765 (R) +POT6 = $D206 ;53766 (R) +POT7 = $D207 ;53767 (R) + +AUDCTL = $D208 ;53768 (W) ; Audio control (no shadow) +ALLPOT = $D208 ;53768 (R) (no shadow) +STIMER = $D209 ;53769 (W) (no shadow) +KBCODE = $D209 ;53769 (R) (shadow @ CH) +SKREST = $D20A ;53770 (W) (latch) +RANDOM = $D20A ;53770 (R) (no shadow) +POTGO = $D20B ;53771 (W) (latch) +; $D20C (53772) is unused +SEROUT = $D20D ;53773 (W) (no shadow) +SERIN = $D20D ;53773 (R) (no shadow) +IRQEN = $D20E ;53774 (W) (shadow @ POKMSK) +IRQST = $D20E ;53774 (R) +SKCTL = $D20F ;53775 (W) (shadow @ SSKCTL) +SKSTAT = $D20F ;53775 (R) + +; $D210 - $D2FF are mirrors of POKEY address space. The "stereo POKEY" +; modification adds a second POKEY chip, usually addressed at $D210. + +; PIA +; No shadow regs for PIA regs +PIA = $D300 +PORTA = $D300 ;54016 +PORTB = $D301 ;54017 +PACTL = $D302 ;54018 +PBCTL = $D303 ;54019 + +; $D304 - $D3FF are mirrors of PIA address space + +; ANTIC +ANTIC = $D400 +DMACTL = $D400 ;54272 (W) (shadow @ SDMCTL) +CHACTL = $D401 ;54273 (W) (shadow @ CHACT) +DLISTL = $D402 ;54274 (W) (shadow @ SDLSTL) +DLISTH = $D403 ;54275 (W) (shadow @ SDLSTH) +HSCROL = $D404 ;54276 (W) (no shadow) +VSCROL = $D405 ;54277 (W) (no shadow) +; $D406 (54278) is unused +PMBASE = $D407 ;54279 (W) (no shadow) +; $D408 (54280) is unused +CHBASE = $D409 ;54281 (W) (shadow @ CHBAS) +WSYNC = $D40A ;54282 (W), latch (data written doesn't matter) +VCOUNT = $D40B ;54283 (R) (no shadow) +PENH = $D40C ;54284 (R) (shadow @ LPENH) +PENV = $D40D ;54285 (R) (shadow @ LPENV) +NMIEN = $D40E ;54286 (W) (no shadow) +NMIRES = $D40F ;54287 (W), latch? +NMIST = $D40F ;54287 (R) (no shadow) + +; $D410 - $D4FF are mirrors of ANTIC address space + +CCNTL = $D500 ;54528 Cartridge control (sometimes used for bankswitching) +; $D500 - $D5FF is supposed to be all be mapped to CCNTL + +; $D600 - $D7FF is unmapped? used by PBI on XL? seems to read all $FF + +; +; FLOATING POINT MATH ROUTINES +; +; From Mapping: +; These entry points are the same on 400/800 and XL OS, though the +; routines themselves are different (bugfixed/optimized for XL) +; Also, on the XL, the $D800 area is bankswitched to PBI device ROM, +; during PBI I/O. Not sure if all of $D800 - $DFFF is switched out +; or just part of it. +AFP = $D800 ;55296 ASCII to Floating Point (FP) conversion. +FASC = $D8E6 ;55526 FP value to ASCII conversion. +IFP = $D9AA ;55722 Integer to FP conversion +FPI = $D9D2 ;55762 FP to Integer conversion +ZFR0 = $DA44 ;55876 Clear FR0 (set all bytes to 0) +ZF1 = $DA46 ;55878 Clear FR1 (set all bytes to 0) (aka AF1 (De Re)) +FSUB = $DA60 ;55904 FP subtract: FR0 = FR0 - FR1 +FADD = $DA66 ;55910 FP add: FR0 = FR0 + FR1 +FMUL = $DADB ;56027 FP multiply: FR0 = FR0 * FR1 +FDIV = $DB28 ;56104 FP divide: FR0 = FR0 / FR1 +PLYEVL = $DD40 ;56640 FP polynomial evaluation +FLD0R = $DD89 ;56713 Load FP number into FR0 from 6502 X/Y registers +FLD0P = $DD8D ;56717 Load FP number into FR0 from FLPTR +FLD1R = $DD98 ;56728 Load FP number into FR1 from 6502 X/Y registers +FLD1P = $DD9C ;56732 Load FP number into FR1 from FLPTR +FST0R = $DDA7 ;56743 Store FP number into 6502 X/Y regs from FR0 +FST0P = $DDAB ;56747 Store FP number from FR0, using FLPTR +FMOVE = $DDB6 ;56758 Move FP number from FR0 into FR1 (FR1 = FR0) +EXP = $DDC0 ;56768 FP base e exponentiation +EXP10 = $DDCC ;56780 FP base 10 exponentiation +LOG = $DECD ;57037 FP natural logarithm +LOG10 = $DED1 ;57041 FP base 10 logarithm + +; +; +; OPERATING SYSTEM +; +; +; MODULE ORIGIN TABLE +; +CHORG = $E000 ;57344 CHARACTER SET, 1K +VECTBL = $E400 ;58368 VECTOR TABLE +VCTABL = $E480 ;58496 RAM VECTOR INITIAL VALUE TABLE +CIOORG = $E4A6 ;58534 CIO HANDLER +INTORG = $E6D5 ;59093 INTERRUPT HANDLER +SIOORG = $E944 ;59716 SIO DRIVER +DSKORT = $EDEA ;60906 DISK HANDLER +PRNORG = $EE78 ;61048 PRINTER HANDLER +CASORG = $EE78 ;61048 CASSETTE HANDLER +MONORG = $F0E3 ;61667 MONITOR/POWER UP MODULE +KBDORG = $F3E4 ;62436 KEYBOARD/DISPLAY HANDLER +; +; +; VECTOR TABLE, CONTAINS ADDRESSES OF CIO ROUTINES IN THE +; FOLLOWING ORDER. THE ADDRESSES IN THE TABLE ARE TRUE ADDRESSES-1 +; +; ADDRESS + 0 OPEN +; + 2 CLOSE +; + 4 GET +; + 6 PUT +; + 8 STATUS +; + A SPECIAL +; + C JMP TO INITIALIZATION +; + F NOT USED +; +; + +; 20070529 bkw: why are they address minus one? because they are called +; via RTS: a JSR actually pushes the return address minus one, and RTS +; increments the address on the stack after popping it. The Atari OS +; "pretends" to have done a JSR by pushing the address-1 on the stack, +; then executes RTS, which "returns" to the correct address. + +EDITRV = $E400 ;58368 EDITOR +SCRENV = $E410 ;58384 SCREEN +KEYBDV = $E420 ;58400 KEYBOARD +PRINTV = $E430 ;58416 PRINTER +CASETV = $E440 ;58432 CASSETTE +; +; ROM VECTORS +; +; 20070529 bkw: These consist of a JMP xxxx instruction in the ROM. +DSKINV = $E453 ;58451 +CIOV = $E456 ;58454 ; Main CIO entry point! +SIOV = $E459 ;58457 ; Main SIO entry point! +SETVBV = $E45C ;58460 +SYSVBV = $E45F ;58463 +VBIVAL = $E460 ;58464 ADR AT VVBLKI (operand of JMP @ $E45F) +XITVBV = $E462 ;58466 EXIT VBI +VBIXVL = $E463 ;58467 ADR AT VVBLKD (operand of JMP @ $E462) +SIOINV = $E465 ;58469 +SENDEV = $E468 ;58472 +INTINV = $E46B ;58475 +CIOINV = $E46E ;58478 +BLKBDV = $E471 ;58481 MEMO PAD MODE (self-test in XL) +WARMSV = $E474 ;58484 ; warmstart (RESET key jumps here) +COLDSV = $E477 ;58487 ; coldstart (reboot) the Atari +RBLOKV = $E47A ;58490 +CSOPIV = $E47D ;58493 + +; SYSEQU.ASM defines this: +CIO = CIOV + +; XL-only entry points: +XL_SELFSV = BLKBDV ; self-test (same entry point as 800 memo pad) +XL_SELFTST = BLKBDV ; alt. name (Mapping) +XL_PUPDIV = $E480 ;58496 (XL) Power-up ATARI logo (1200XL only), or self-test +XL_SLFTSV = $E483 ;58499 (XL) Self-test vector (points to $5000) +XL_PENTV = $E486 ;58502 (XL) Entry to the handler uploaded from peripheral + ; or disk (is this for the PBI?) +XL_PHUNLV = $E489 ;58505 (XL) Entry to uploaded handler unlink (PBI?) +XL_PHINIV = $E48C ;58508 (XL) Entry to uploaded handler init (PBI?) +XL_GPDVV = $E48F ;58511 (XL) General-purpose parallel device handler + ; (copy to HATABS to use) + +;;;;; Here endeth the list of official mnemonics + +; Mapping has this to say about the XL ROMs: +;Byte Use +;65518/FFEE Revision date D1 and D2 (four-bit BCD) +;65519/FFEF Revision date M1 and M2 +;65520/FFF0 Revision date Y1 and Y2 +;65521/FFF1 Option byte; should read 1 for the +; 1200XL (Mapping author's 800XL reads 2) +;65522-26/FFF2-6 Part number in the form AANNNNNN +;65527/FFF7 Revision number (again, mine reads 2) +;65528-9/FFF8-9 Checksum, bytes (LSB/MSB) +; There don't seem to be any known mnemonics for the above... + +; 20061120 bkw: display list stuff. These are not official Atari mnemonics, +; but they *are* somewhat based on the "Checkers Demo" by Carol Shaw, +; in the Atari Hardware Manual (she didn't define all these, and she didn't +; use the "DL_" prefix, probably because her assembler was limited to +; 6-character labels and/or didn't support the underscore). + +; blank lines, 1-8 scanlines high +DL_BLANK1 = $00 +DL_BLANK2 = $10 +DL_BLANK3 = $20 +DL_BLANK4 = $30 +DL_BLANK5 = $40 +DL_BLANK6 = $50 +DL_BLANK7 = $60 +DL_BLANK8 = $70 + +; modifier bits.. +DL_VSCROLL = $10 +DL_HSCROLL = $20 +DL_LMS = $40 +DL_DLI = $80 + +; graphics modes (these are the BASIC modes) +; If you're more familiar with the ANTIC modes, nobody's forcing you +; to use these :) +DL_GR0 = $02 +DL_GR1 = $06 +DL_GR2 = $07 +DL_GR3 = $08 +DL_GR4 = $09 +DL_GR5 = $0A +DL_GR6 = $0B +DL_GR7 = $0D +DL_GR8 = $0F +DL_GR12 = $04 ; GR. 12-15 only supported by GRAPHICS command on XL/XE, +DL_GR13 = $05 ; but they exist on all ANTIC revisions +DL_GR14 = $0C +DL_GR15 = $0E ; AKA "graphics 7.5" +; No GRAPHICS mode for ANTIC $03 (true descender) mode + +; jump instructions +DL_JMP = $01 ; jump without vertical blank (used to skip over 1K boundary) +DL_JVB = $41 ; jump & wait for VBLANK (end of display list) + +; How to use the above: here's a sample display list for GR.0, with a DLI +; on screen line 10. + +; dlist: +; ; 4*8 = 32 blank lines at start of display +; byte DL_BLANK8, DL_BLANK8, DL_BLANK8, DL_BLANK8 +; +; byte DL_GR0 | DL_LMS ; display GR.0 line, and load screen memory address.. +; word screen_ram ; ...from our screen memory (declared elsewhere) +; +; ; 8 more GR.0 lines +; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0 +; +; byte DL_GR0 | DL_DLI ; another GR.0 line, with the DLI bit enabled +; +; ; lines 11-24 (14 more GR.0 bytes) +; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0 +; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0 +; +; ; that's 24 lines, so finish with a VBLANK +; byte DL_JVB ; jump (and wait), to... +; word dlist ; ...the beginning. diff --git a/src/features.h b/src/features.h new file mode 100644 index 0000000..ec7d194 --- /dev/null +++ b/src/features.h @@ -0,0 +1,102 @@ +#ifndef FEATURES_H +#define FEATURES_H + + +// #define FEAT_COL64_HACK +// #define FEAT_COL80_HACK + +#ifdef FEAT_COL64_HACK +#define COLUMNS 64 +#define FEAT_COL80_HACK +#endif + +#if defined(FEAT_TINY) && defined(FEAT_COL80_HACK) +#error "You may not define both FEAT_TINY and FEAT_COL80_HACK" +#endif + +#ifdef FEAT_TINY + +#define FEAT_LOW_RAM_BUFFERS +#undef FEAT_DYNAMIC_VERSION +#undef FEAT_VISUAL_BELL +#undef FEAT_CURSOR_CONTROLS +#undef FEAT_KEYBOARD_MACROS +#undef FEAT_TRAFFIC_INDICATOR +#undef FEAT_ATRACT_AWAY +#undef FEAT_KEYBOARD_BUFFER +#undef FEAT_COLOR_COMMAND + +#elif defined(FEAT_COL80_HACK) + +#define FEAT_LOW_RAM_BUFFERS +#define FEAT_VISUAL_BELL +#define FEAT_KEYBOARD_MACROS +// #define FEAT_TRAFFIC_INDICATOR +#define FEAT_KEYBOARD_BUFFER +#define FEAT_COLOR_COMMAND + +/* COL80 hack uses 9K of high RAM, so let's disable + some bells & whistles. */ +#undef FEAT_DYNAMIC_VERSION +#undef FEAT_ATRACT_AWAY + +/* Do not enable cursor controls with COL80 hack, because they don't work + anyway (arrows and deletes not implemented in the driver). Not needed + anyway, fujichat.c contains code that does the same thing when COL80 + is enabled (slower though) */ +#undef FEAT_CURSOR_CONTROLS + +#else +/* Removable features. Compiling with everything turned off + (except FEAT_LOW_RAM_BUFFERS!) saves us around 1322 bytes at + runtime (including data/bss) */ + +/* Keep our bigger buffers in low memory, where possible. Saves + space in the DATA segment, allowing MEMTOP to be set lower + (to make room for more scrollback, or an 80-col driver, etc) */ +#define FEAT_LOW_RAM_BUFFERS + +/* Make CTCP version response say "Atari 8-bit" instead of calling + get_ostype(). Saves 179 bytes in executable. */ +#define FEAT_DYNAMIC_VERSION + +/* Support visual bell. Saves 110 bytes in exe when undef'd. */ +// TODO: make fujiconf not ask about visual bell, too +#define FEAT_VISUAL_BELL + +/* Don't use cursor controls to keep from splitting up the user's + edit buffer when packets come in while he's typing. The 80-column + version will probably need this disabled. + Saves 410 bytes in exe. */ +#define FEAT_CURSOR_CONTROLS + +/* Disable the keyboard macros (^W, ^N, Tab at start of line). Saves + about 230 bytes in exe. */ +#define FEAT_KEYBOARD_MACROS + +/* Have the rs232dev code display up/down arrows in top right of + screen. Accesses screen RAM directly, don't use with 80 cols. */ +#define FEAT_TRAFFIC_INDICATOR + +/* Set /away on the server when Atari goes into attract mode, + clear when user presses a key */ +#define FEAT_ATRACT_AWAY + +/* Experimental logging (backlog, scrollback) support. Expect trouble. */ +// TODO: implement! +// #define FEAT_LOGGING + +/* Disable the keyboard prebuffering during serial I/O */ +#define FEAT_KEYBOARD_BUFFER + +/* Support /bgcolor and /fgcolor command in FujiChat (instead of having to go + back to setup menu to change text colors) */ +#define FEAT_COLOR_COMMAND + +/* messing around, not functional yet */ +// #define FEAT_UNICODE_TEST + +/* End of features */ + +#endif +#endif diff --git a/src/fuji6432.atr b/src/fuji6432.atr new file mode 100644 index 0000000..f77c6dd Binary files /dev/null and b/src/fuji6432.atr differ diff --git a/src/fuji80.atr b/src/fuji80.atr new file mode 100644 index 0000000..d8757ba Binary files /dev/null and b/src/fuji80.atr differ diff --git a/src/fuji_asm.s b/src/fuji_asm.s new file mode 100644 index 0000000..2d9f205 --- /dev/null +++ b/src/fuji_asm.s @@ -0,0 +1,3016 @@ +; +; File generated by cc65 v 2.12.9 +; + .fopt compiler,"cc65 v 2.12.9" + .setcpu "6502" + .smart on + .autoimport on + .case on + .debuginfo off + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .import _stdout + .import _fflush + .import _fputs + .import _printf + .import _putchar + .import _puts + .import _sprintf + .import _atoi + .import _exit + .import _strcmp + .import _strcpy + .import _strlen + .import _memcmp + .import _memcpy + .import _strcasecmp + .import _toupper + .import _get_ostype + .import _kbhit + .import _cgetc + .import _cursor + .import __clocks_per_sec + .import _clock + .import _timer_set + .import _timer_reset + .import _timer_expired + .export _resolv_found + .import _resolv_conf + .import _resolv_init + .import _resolv_query + .import _telnet_send + .export _telnet_connected + .export _telnet_closed + .export _telnet_sent + .export _telnet_aborted + .export _telnet_timedout + .export _telnet_newdata + .import _uip_init + .import _uip_connect + .import _htons + .import _uip_len + .import _uip_conn + .import _uip_conns + .import _uip_udp_conn + .import _uip_udp_conns + .import _uip_flags + .import _uip_process + .import _uip_hostaddr + .import _uip_netmask + .import _uip_draddr + .import _uiplib_ipaddrconv + .import _rs232dev_init + .import _rs232dev_send + .import _rs232dev_close + .import _rs232dev_poll + .import _atari_exec_p + .import _config + .import _format_ip + .import _get_config + .import _config_is_valid + .import _get_line + .import _set_default_config + .import _disable_break + .export _os_version + .export _input_buf + .export _chan_msg_buf + .export _output_buf + .export _channel + .export _last_msg_nick + .export _input_buf_len + .export _output_buf_len + .export _done + .export _connected + .export _joined_channel + .export _nick_registered + .export _vbell_active + .export _bell + .export _redraw_user_buffer + .export _nick_reg_timer + .export _tstate + .export _vbell_timer + .export _main + .export _do_pong + .export _do_server_msg + .export _do_ctcp + .export _do_msg + .export _del_user_buffer + +.segment "DATA" + +_os_version: + .byte $58,$4C,$5F,$58,$45,$00 + .res 4,$00 +_input_buf: + .word $2900 +_chan_msg_buf: + .word $2A00 +_output_buf: + .word $2C00 +_last_msg_nick: + .byte $00 + .res 20,$00 +_input_buf_len: + .word $0000 +_output_buf_len: + .word $0000 +_done: + .byte $00 +_connected: + .byte $00 +_joined_channel: + .byte $00 +_nick_registered: + .byte $00 +_vbell_active: + .byte $00 + +.segment "RODATA" + +L0001: + .byte $38,$30,$30,$00,$31,$32,$30,$30,$58,$4C,$00,$C6,$F5,$EA,$E9,$C3 + .byte $E8,$E1,$F4,$20,$76,$30,$2E,$35,$00,$53,$65,$72,$76,$65,$72,$20 + .byte $6E,$61,$6D,$65,$2F,$49,$50,$2C,$20,$5B,$43,$5D,$6F,$6E,$66,$69 + .byte $67,$2C,$20,$6F,$72,$20,$5B,$44,$5D,$4F,$53,$9B,$00,$5B,$25,$73 + .byte $5D,$3A,$20,$00,$64,$00,$63,$00,$44,$3A,$46,$55,$4A,$49,$43,$4F + .byte $4E,$46,$2E,$43,$4F,$4D,$00,$45,$72,$72,$6F,$72,$20,$25,$64,$21 + .byte $9B,$00,$2A,$20,$52,$65,$67,$69,$73,$74,$65,$72,$69,$6E,$67,$20 + .byte $6E,$69,$63,$6B,$00,$4E,$49,$43,$4B,$20,$25,$73,$25,$63,$55,$53 + .byte $45,$52,$20,$25,$73,$20,$25,$73,$20,$25,$73,$20,$3A,$25,$73,$25 + .byte $63,$00,$46,$75,$6A,$69,$43,$68,$61,$74,$00,$43,$6F,$6D,$6D,$61 + .byte $6E,$64,$20,$72,$65,$71,$75,$69,$72,$65,$73,$20,$61,$72,$67,$75 + .byte $6D,$65,$6E,$74,$00,$59,$6F,$75,$20,$61,$72,$65,$20,$6E,$6F,$74 + .byte $20,$69,$6E,$20,$61,$20,$63,$68,$61,$6E,$6E,$65,$6C,$20,$28,$75 + .byte $73,$65,$20,$2F,$6A,$6F,$69,$6E,$20,$23,$63,$68,$61,$6E,$6E,$65 + .byte $6C,$29,$00,$59,$6F,$75,$20,$61,$72,$65,$20,$61,$6C,$72,$65,$61 + .byte $64,$79,$20,$69,$6E,$20,$61,$20,$63,$68,$61,$6E,$6E,$65,$6C,$20 + .byte $28,$75,$73,$65,$20,$2F,$70,$61,$72,$74,$20,$74,$6F,$20,$6C,$65 + .byte $61,$76,$65,$29,$00,$4E,$41,$4D,$45,$53,$00,$57,$48,$4F,$00,$2F + .byte $6D,$73,$67,$20,$25,$73,$20,$00,$50,$52,$49,$56,$4D,$53,$47,$20 + .byte $25,$73,$20,$3A,$25,$73,$00,$25,$73,$20,$25,$73,$25,$63,$00,$25 + .byte $73,$25,$63,$00,$50,$52,$49,$56,$4D,$53,$47,$20,$25,$73,$20,$25 + .byte $63,$56,$45,$52,$53,$49,$4F,$4E,$25,$63,$25,$63,$00,$50,$52,$49 + .byte $56,$4D,$53,$47,$20,$25,$73,$20,$25,$63,$50,$49,$4E,$47,$20,$25 + .byte $30,$33,$64,$20,$25,$30,$33,$64,$20,$25,$30,$33,$64,$25,$63,$25 + .byte $63,$00,$50,$52,$49,$56,$4D,$53,$47,$20,$25,$73,$20,$3A,$25,$63 + .byte $41,$43,$54,$49,$4F,$4E,$20,$25,$73,$25,$63,$25,$63,$00,$4D,$45 + .byte $00,$4D,$53,$47,$00,$4D,$00,$50,$52,$49,$56,$4D,$53,$47,$00,$4A + .byte $4F,$49,$4E,$00,$4A,$00,$4A,$4F,$49,$4E,$00,$4A,$4F,$49,$4E,$00 + .byte $50,$41,$52,$54,$00,$50,$41,$52,$54,$00,$56,$45,$52,$53,$49,$4F + .byte $4E,$00,$56,$45,$52,$00,$50,$49,$4E,$47,$00,$4E,$49,$43,$4B,$00 + .byte $2A,$20,$59,$6F,$75,$20,$61,$72,$65,$20,$6E,$6F,$77,$20,$6B,$6E + .byte $6F,$77,$6E,$20,$61,$73,$20,$25,$73,$9B,$00,$51,$55,$4F,$54,$45 + .byte $00,$43,$6F,$6E,$6E,$65,$63,$74,$65,$64,$20,$74,$6F,$20,$73,$65 + .byte $72,$76,$65,$72,$00,$43,$6F,$6E,$6E,$65,$63,$74,$69,$6F,$6E,$20 + .byte $63,$6C,$6F,$73,$65,$64,$00,$43,$6F,$6E,$6E,$65,$63,$74,$69,$6F + .byte $6E,$20,$61,$62,$6F,$72,$74,$65,$64,$00,$43,$6F,$6E,$6E,$65,$63 + .byte $74,$69,$6F,$6E,$20,$74,$69,$6D,$65,$64,$20,$6F,$75,$74,$00,$5B + .byte $50,$49,$4E,$47,$2C,$50,$4F,$4E,$47,$5D,$00,$2A,$20,$54,$6F,$70 + .byte $69,$63,$3A,$20,$25,$73,$00,$2A,$20,$54,$6F,$70,$69,$63,$20,$73 + .byte $65,$74,$20,$62,$79,$20,$25,$73,$00,$2A,$20,$48,$69,$64,$69,$6E + .byte $67,$20,$4D,$4F,$54,$44,$20,$28,$62,$65,$20,$70,$61,$74,$69,$65 + .byte $6E,$74,$29,$00,$25,$64,$20,$25,$73,$00,$25,$73,$20,$25,$73,$00 + .byte $50,$49,$4E,$47,$20,$00,$2A,$20,$25,$73,$20,$70,$69,$6E,$67,$20 + .byte $74,$69,$6D,$65,$3A,$20,$25,$64,$2E,$25,$64,$9B,$00,$50,$52,$49 + .byte $56,$4D,$53,$47,$00,$01,$41,$43,$54,$49,$4F,$4E,$20,$00,$2A,$20 + .byte $25,$73,$20,$25,$73,$00,$25,$73,$20,$25,$73,$00,$01,$50,$49,$4E + .byte $47,$20,$00,$4E,$4F,$54,$49,$43,$45,$20,$25,$73,$20,$3A,$01,$50 + .byte $49,$4E,$47,$20,$25,$73,$01,$25,$63,$00,$2A,$20,$43,$54,$43,$50 + .byte $20,$50,$49,$4E,$47,$20,$66,$72,$6F,$6D,$20,$25,$73,$9B,$00,$01 + .byte $56,$45,$52,$53,$49,$4F,$4E,$01,$00,$4E,$4F,$54,$49,$43,$45,$20 + .byte $25,$73,$20,$3A,$01,$56,$45,$52,$53,$49,$4F,$4E,$20,$46,$75,$6A + .byte $69,$43,$68,$61,$74,$20,$76,$30,$2E,$35,$20,$2D,$20,$72,$75,$6E + .byte $6E,$69,$6E,$67,$20,$6F,$6E,$20,$61,$6E,$20,$41,$74,$61,$72,$69 + .byte $20,$25,$73,$01,$25,$63,$00,$2A,$20,$43,$54,$43,$50,$20,$56,$45 + .byte $52,$53,$49,$4F,$4E,$20,$66,$72,$6F,$6D,$20,$25,$73,$9B,$00,$4D + .byte $53,$47,$3A,$20,$25,$73,$20,$25,$73,$00,$4E,$4F,$54,$49,$43,$45 + .byte $00,$2A,$20,$43,$54,$43,$50,$20,$72,$65,$70,$6C,$79,$20,$66,$72 + .byte $6F,$6D,$20,$25,$73,$3A,$20,$25,$73,$00,$25,$73,$20,$25,$73,$20 + .byte $25,$73,$20,$25,$73,$00,$25,$73,$20,$25,$73,$20,$25,$73,$00,$5B + .byte $62,$75,$66,$66,$65,$72,$20,$6F,$76,$65,$72,$66,$6C,$6F,$77,$5D + .byte $FD,$00,$50,$49,$4E,$47,$00,$48,$6F,$73,$74,$20,$27,$25,$73,$27 + .byte $20,$6E,$6F,$74,$20,$66,$6F,$75,$6E,$64,$2E,$9B,$00,$25,$73,$20 + .byte $69,$73,$20,$25,$73,$9B,$00 + +.segment "BSS" + +_channel: + .res 64,$00 +_nick_reg_timer: + .res 4,$00 +_tstate: + .res 2,$00 +_vbell_timer: + .res 4,$00 + +; --------------------------------------------------------------- +; void __near__ resolv_found (__near__ unsigned char*, __near__ unsigned int*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _resolv_found: near + +.segment "CODE" + + ldy #$00 + lda (sp),y + iny + ora (sp),y + bne L0501 + lda #<(L0001+967) + ldx #>(L0001+967) + jsr pushax + ldy #$07 + jsr pushwysp + ldy #$04 + jsr _printf + lda #$01 + sta _done + jmp incsp4 +L0501: lda #<(L0001+989) + ldx #>(L0001+989) + jsr pushax + ldy #$07 + jsr pushwysp + ldy #$07 + jsr pushwysp + jsr _format_ip + jsr pushax + ldy #$06 + jsr _printf + lda _connected + jne incsp4 + jsr pushw0sp + lda _config + ldx _config+1 + ldy #$53 + jsr pushwidx + jsr _htons + jsr pushax + jsr _uip_connect + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; void __near__ telnet_connected (__near__ struct telnet_state*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _telnet_connected: near + +.segment "CODE" + + lda #<(L0001+513) + ldx #>(L0001+513) + jsr _puts + jsr ldax0sp + sta _tstate + stx _tstate+1 + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$01 + sta (sreg),y + iny + sta (sreg),y + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$03 + sta (sreg),y + iny + sta (sreg),y + lda #<(_nick_reg_timer) + ldx #>(_nick_reg_timer) + jsr pushax + jsr __clocks_per_sec + jsr pushax + jsr _timer_set + lda #$01 + sta _connected + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ telnet_closed (__near__ struct telnet_state*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _telnet_closed: near + +.segment "CODE" + + lda #<(L0001+533) + ldx #>(L0001+533) + jsr _puts + lda #$10 + sta _uip_flags + lda #$01 + sta _done + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ telnet_sent (__near__ struct telnet_state*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _telnet_sent: near + +.segment "CODE" + + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ telnet_aborted (__near__ struct telnet_state*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _telnet_aborted: near + +.segment "CODE" + + lda #<(L0001+551) + ldx #>(L0001+551) + jsr _puts + lda #$20 + sta _uip_flags + lda #$01 + sta _done + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ telnet_timedout (__near__ struct telnet_state*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _telnet_timedout: near + +.segment "CODE" + + lda #<(L0001+570) + ldx #>(L0001+570) + jsr _puts + lda #$20 + sta _uip_flags + lda #$01 + sta _done + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ telnet_newdata (__near__ struct telnet_state*, __near__ unsigned char*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _telnet_newdata: near + +.segment "CODE" + + jsr pushw0sp + jsr decsp1 + ldy #$08 + jsr pushwysp + jsr pushc0 +L04AF: ldy #$05 + jsr ldaxysp + sta regsave + stx regsave+1 + jsr decax1 + ldy #$04 + jsr staxysp + lda regsave + ora regsave+1 + jeq L04B0 + ldy #$02 + jsr ldaxysp + sta regsave + stx regsave+1 + jsr incax1 + ldy #$01 + jsr staxysp + ldy #$00 + lda (regsave),y + ldy #$03 + sta (sp),y + cmp #$0A + beq L04AF + lda (sp),y + cmp #$0D + bne L04B8 + lda #$9B + sta (sp),y + lda #$01 + ldy #$00 + jmp L0515 +L04B8: lda (sp),y + cmp #$09 + bne L04BF + lda #$7F + jmp L0515 +L04BF: lda (sp),y + cmp #$7B + bne L04C4 + lda #$DB + jmp L0515 +L04C4: lda (sp),y + cmp #$7D + bne L04C9 + lda #$DD + jmp L0515 +L04C9: lda (sp),y + cmp #$7E + bne L04CE + lda #$DE + jmp L0515 +L04CE: lda (sp),y + cmp #$60 + bne L04D3 + lda #$A7 +L0515: sta (sp),y +L04D3: lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _output_buf_len + ldx _output_buf_len+1 + sta regsave + stx regsave+1 + jsr incax1 + sta _output_buf_len + stx _output_buf_len+1 + lda regsave + ldx regsave+1 + jsr tosaddax + sta sreg + stx sreg+1 + ldy #$03 + lda (sp),y + ldy #$00 + sta (sreg),y + lda _output_buf_len + ldx _output_buf_len+1 + jsr pushax + ldx #$02 + lda #$00 + jsr tosicmp + bmi L04DA + lda #<(L0001+943) + ldx #>(L0001+943) + jsr _puts + lda #$01 + ldy #$00 + sta (sp),y + jmp L04B0 +L04DA: ldy #$00 + lda (sp),y + jeq L04AF + jsr _del_user_buffer + lda _output_buf + ldx _output_buf+1 + clc + adc _output_buf_len + pha + txa + adc _output_buf_len+1 + tax + pla + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda _output_buf_len + ldx _output_buf_len+1 + jsr pushax + lda #$05 + jsr tosgea0 + beq L04E6 + lda _output_buf + ldx _output_buf+1 + jsr pushax + lda #<(L0001+962) + ldx #>(L0001+962) + jsr pushax + ldx #$00 + lda #$04 + jsr _memcmp + cpx #$00 + bne L04E6 + cmp #$00 + bne L04E6 + jsr _do_pong + jmp L04F5 +L04E6: lda _output_buf + ldx _output_buf+1 + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$3A + bne L04F1 + jsr _do_msg + jmp L04F5 +L04F1: lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _stdout + ldx _stdout+1 + jsr _fputs + lda _stdout + ldx _stdout+1 + jsr _fflush +L04F5: jsr _redraw_user_buffer + lda #$00 + sta _output_buf_len + sta _output_buf_len+1 + tay + sta (sp),y + jmp L04AF +L04B0: ldy #$0C + jmp addysp + +.endproc + +; --------------------------------------------------------------- +; void __near__ handle_keystroke (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _handle_keystroke: near + +.segment "CODE" + + jsr decsp2 + jsr pushc0 + jsr _cgetc + ldy #$01 + sta (sp),y + lda _input_buf_len + ora _input_buf_len+1 + jne L01A9 + lda (sp),y + cmp #$0E + beq L01AB + cmp #$17 + beq L01B2 + cmp #$7F + beq L01BB + cmp #$9B + jeq incsp3 + jmp L01A9 +L01AB: lda _joined_channel + jeq incsp3 + lda #<(L0001+277) + ldx #>(L0001+277) + jsr pushax + lda #<(_channel) + ldx #>(_channel) + jsr pushax + jsr _send_server_cmd + jmp incsp3 +L01B2: lda _joined_channel + jeq incsp3 + lda #<(L0001+283) + ldx #>(L0001+283) + jsr pushax + lda #<(_channel) + ldx #>(_channel) + jsr pushax + jsr _send_server_cmd + jmp incsp3 +L01BB: lda _last_msg_nick + jeq incsp3 + lda _input_buf + ldx _input_buf+1 + jsr pushax + lda #<(L0001+287) + ldx #>(L0001+287) + jsr pushax + lda #<(_last_msg_nick) + ldx #>(_last_msg_nick) + jsr pushax + ldy #$06 + jsr _sprintf + lda _input_buf + ldx _input_buf+1 + jsr _strlen + sta _input_buf_len + stx _input_buf_len+1 + lda #$00 + ldy #$02 +L0519: sta (sp),y + lda (sp),y + jsr pusha0 + lda _input_buf_len + ldx _input_buf_len+1 + jsr tosicmp + jcs incsp3 + lda _input_buf + sta sreg + lda _input_buf+1 + sta sreg+1 + ldy #$02 + lda (sp),y + clc + adc sreg + ldx sreg+1 + bcc L0517 + inx +L0517: ldy #$00 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + ora #$80 + jsr _putchar + ldy #$02 + lda (sp),y + clc + adc #$01 + jmp L0519 +L01A9: lda (sp),y + cmp #$7E + bne L01D2 + lda _input_buf_len + ldx _input_buf_len+1 + jsr pushax + lda #$01 + jsr tosgea0 + beq L01D4 + lda _input_buf_len + ldx _input_buf_len+1 + jsr decax1 + sta _input_buf_len + stx _input_buf_len+1 + ldy #$01 + ldx #$00 + lda (sp),y + jsr _putchar + jmp incsp3 +L01D4: jsr _bell + jmp incsp3 +L01D2: lda (sp),y + cmp #$9C + beq L01DD + lda (sp),y + cmp #$15 + bne L01DC +L01DD: ldx #$00 + txa + sta _input_buf_len + sta _input_buf_len+1 + lda #$9C + jsr _putchar + jmp incsp3 +L01DC: lda (sp),y + cmp #$17 + bne L01E4 + jsr _del_last_word + jmp incsp3 +L01E4: ldx #$00 + lda (sp),y + ora #$80 + jsr _putchar + ldy #$01 + lda (sp),y + cmp #$9B + bne L01E9 + lda #$0A + sta (sp),y + tya + dey + jmp L0518 +L01E9: lda (sp),y + cmp #$7F + bne L01F0 + lda #$09 +L0518: sta (sp),y +L01F0: lda _input_buf + ldx _input_buf+1 + jsr pushax + lda _input_buf_len + ldx _input_buf_len+1 + sta regsave + stx regsave+1 + jsr incax1 + sta _input_buf_len + stx _input_buf_len+1 + lda regsave + ldx regsave+1 + jsr tosaddax + sta sreg + stx sreg+1 + ldy #$01 + lda (sp),y + dey + sta (sreg),y + lda _input_buf_len + ldx _input_buf_len+1 + jsr pushax + ldx #$01 + lda #$00 + jsr tosicmp + bmi L01F9 + ldy #$00 + lda (sp),y + bne L01F9 + jsr _bell + ldx #$00 + lda #$7E + jsr _putchar + lda _input_buf_len + ldx _input_buf_len+1 + jsr decax1 + sta _input_buf_len + stx _input_buf_len+1 +L01F9: ldy #$00 + lda (sp),y + jeq incsp3 + lda _input_buf + ldx _input_buf+1 + clc + adc _input_buf_len + pha + txa + adc _input_buf_len+1 + tax + pla + sta sreg + stx sreg+1 + tya + sta (sreg),y + lda _input_buf + sta ptr1 + lda _input_buf+1 + sta ptr1+1 + lda (ptr1),y + cmp #$2F + bne L0204 + jsr _handle_command + jmp L0214 +L0204: lda _joined_channel + beq L0208 + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+296) + ldx #>(L0001+296) + jsr pushax + lda #<(_channel) + ldx #>(_channel) + jsr pushax + lda _input_buf + ldx _input_buf+1 + jsr pushax + ldy #$08 + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + jmp L0214 +L0208: jsr _err_no_channel +L0214: lda #$00 + sta _input_buf_len + sta _input_buf_len+1 + jmp incsp3 + +.endproc + +; --------------------------------------------------------------- +; void __near__ handle_command (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _handle_command: near + +.segment "CODE" + + lda _input_buf + ldx _input_buf+1 + jsr incax1 + jsr pushax + jsr decsp2 + jsr push0 + ldy #$07 + jsr pushwysp +L0261: jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$0A + beq L0262 + jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L0262 + jsr pushw0sp + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr _toupper + ldy #$00 + jsr staspidx + ldx #$00 + lda #$01 + jsr addeq0sp + jmp L0261 +L0262: jsr ldax0sp + ldy #$04 + jsr staxysp + jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$0A + beq L026E + jsr ldax0sp + ldy #$02 + jsr staxysp +L0272: ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + bne L0273 + ldy #$02 + ldx #$00 + lda #$01 + jsr addeqysp + jmp L0272 +L0273: ldy #$03 + jsr ldaxysp + jsr incax1 + jsr stax0sp +L0278: jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L0279 + jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$0A + beq L0279 + ldx #$00 + lda #$01 + jsr addeq0sp + jmp L0278 +L0279: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y +L026E: ldy #$05 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + ldy #$09 + jsr pushwysp + lda #<(L0001+414) + ldx #>(L0001+414) + jsr _strcmp + cpx #$00 + bne L0283 + cmp #$00 + bne L0283 + lda _joined_channel + bne L0288 + jsr _err_no_channel + jmp incsp8 +L0288: ldy #$03 + lda (sp),y + dey + ora (sp),y + bne L028C + jsr _err_missing_arg + jmp incsp8 +L028C: ldy #$05 + jsr pushwysp + jsr _do_me + jmp incsp8 +L0283: ldy #$09 + jsr pushwysp + lda #<(L0001+417) + ldx #>(L0001+417) + jsr _strcmp + cpx #$00 + bne L051B + cmp #$00 + beq L0294 +L051B: ldy #$09 + jsr pushwysp + lda #<(L0001+421) + ldx #>(L0001+421) + jsr _strcmp + cpx #$00 + bne L0293 + cmp #$00 + bne L0293 +L0294: ldy #$03 + lda (sp),y + dey + ora (sp),y + bne L029C + jsr _err_missing_arg + jmp incsp8 +L029C: lda #<(L0001+423) + ldx #>(L0001+423) + jmp L0524 +L0293: ldy #$09 + jsr pushwysp + lda #<(L0001+431) + ldx #>(L0001+431) + jsr _strcmp + cpx #$00 + bne L051D + cmp #$00 + beq L02A5 +L051D: ldy #$09 + jsr pushwysp + lda #<(L0001+436) + ldx #>(L0001+436) + jsr _strcmp + cpx #$00 + bne L02A4 + cmp #$00 + bne L02A4 +L02A5: lda _joined_channel + beq L02AD + ldy #$03 + lda (sp),y + dey + ora (sp),y + beq L02AF + jsr _err_already_joined + jmp incsp8 +L02AF: lda #<(L0001+438) + ldx #>(L0001+438) + jsr pushax + lda #<(_channel) + ldx #>(_channel) + jmp L0521 +L02AD: ldy #$03 + lda (sp),y + dey + ora (sp),y + beq L02B7 + lda #$01 + sta _joined_channel + lda #<(_channel) + ldx #>(_channel) + jsr pushax + ldy #$05 + jsr ldaxysp + jsr _strcpy + lda #<(L0001+443) + ldx #>(L0001+443) + jmp L0524 +L02B7: jsr _err_missing_arg + jmp incsp8 +L02A4: ldy #$09 + jsr pushwysp + lda #<(L0001+448) + ldx #>(L0001+448) + jsr _strcmp + cpx #$00 + bne L02C4 + cmp #$00 + bne L02C4 + lda _joined_channel + bne L02C9 + jsr _err_no_channel + jmp incsp8 +L02C9: txa + sta _joined_channel + lda #<(L0001+453) + ldx #>(L0001+453) + jsr pushax + lda #<(_channel) + ldx #>(_channel) + jmp L0521 +L02C4: ldy #$09 + jsr pushwysp + lda #<(L0001+458) + ldx #>(L0001+458) + jsr _strcmp + cpx #$00 + bne L051F + cmp #$00 + beq L02D4 +L051F: ldy #$09 + jsr pushwysp + lda #<(L0001+466) + ldx #>(L0001+466) + jsr _strcmp + cpx #$00 + bne L02D3 + cmp #$00 + bne L02D3 +L02D4: ldy #$03 + lda (sp),y + dey + ora (sp),y + bne L02DC + jsr _err_missing_arg + jmp incsp8 +L02DC: ldy #$05 + jsr pushwysp + jsr _send_ctcp_version + jmp incsp8 +L02D3: ldy #$09 + jsr pushwysp + lda #<(L0001+470) + ldx #>(L0001+470) + jsr _strcmp + cpx #$00 + bne L02E3 + cmp #$00 + bne L02E3 + ldy #$03 + lda (sp),y + dey + ora (sp),y + bne L02E8 + jsr _err_missing_arg + jmp incsp8 +L02E8: ldy #$05 + jsr pushwysp + jsr _send_ctcp_ping + jmp incsp8 +L02E3: ldy #$09 + jsr pushwysp + lda #<(L0001+475) + ldx #>(L0001+475) + jsr _strcmp + cpx #$00 + bne L02EF + cmp #$00 + bne L02EF + ldy #$03 + lda (sp),y + dey + ora (sp),y + bne L02F4 + jsr _err_missing_arg + jmp incsp8 +L02F4: lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr pushax + ldy #$05 + jsr ldaxysp + jsr _strcpy + ldy #$09 + jsr pushwysp + ldy #$07 + jsr pushwysp + jsr _send_server_cmd + lda #<(L0001+480) + ldx #>(L0001+480) + jsr pushax + lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr pushax + ldy #$04 + jsr _printf + jmp incsp8 +L02EF: ldy #$09 + jsr pushwysp + lda #<(L0001+507) + ldx #>(L0001+507) + jsr _strcmp + cpx #$00 + bne L0302 + cmp #$00 + bne L0302 + ldy #$03 + lda (sp),y + dey + ora (sp),y + bne L0307 + jsr _err_missing_arg + jmp incsp8 +L0307: ldy #$05 + jsr pushwysp + ldx #$00 + txa + jmp L0521 +L0302: ldy #$07 + jsr ldaxysp +L0524: jsr pushax + ldy #$05 + jsr ldaxysp +L0521: jsr pushax + jsr _send_server_cmd + jmp incsp8 + +.endproc + +; --------------------------------------------------------------- +; void __near__ send_server_cmd (__near__ unsigned char*, __near__ unsigned char*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _send_server_cmd: near + +.segment "CODE" + + ldy #$01 + lda (sp),y + dey + ora (sp),y + beq L0219 + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+311) + ldx #>(L0001+311) + jsr pushax + ldy #$09 + jsr pushwysp + ldy #$09 + jsr pushwysp + lda #$0A + jsr pusha0 + tay + jmp L0525 +L0219: lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+319) + ldx #>(L0001+319) + jsr pushax + ldy #$09 + jsr pushwysp + lda #$0A + jsr pusha0 + ldy #$08 +L0525: jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; void __near__ bell (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _bell: near + +.segment "CODE" + + lda _config + ldx _config+1 + ldy #$96 + jsr ldaxidx + txa + and #$08 + bne L015D + lda _config + ldx _config+1 + ldy #$96 + jsr ldaxidx + txa + and #$20 + beq L0160 + lda #$01 + sta _vbell_active + lda #<(_vbell_timer) + ldx #>(_vbell_timer) + jsr pushax + jsr __clocks_per_sec + jsr pushax + lda #$0A + jsr tosudiva0 + jsr pushax + jsr _timer_set + lda _config + ldx _config+1 + ldy #$93 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + clc + adc #$08 + sta $02C6 + rts +L0160: ldx #$00 + lda #$FD + jmp _putchar +L015D: rts + +.endproc + +; --------------------------------------------------------------- +; void __near__ redraw_user_buffer (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _redraw_user_buffer: near + +.segment "CODE" + + jsr decsp2 + ldx #$28 + lda #$00 + jsr pushax + lda _input_buf_len + ora _input_buf_len+1 + jeq incsp4 + lda _input_buf_len + ldx _input_buf_len+1 + jsr decax1 + ldy #$02 + jsr staxysp +L049B: jsr ldax0sp + sta sreg + stx sreg+1 + ldy #$03 + jsr ldaxysp + clc + adc sreg + sta sreg + txa + adc sreg+1 + tax + lda sreg + sta ptr2 + stx ptr2+1 + lda _input_buf + sta sreg + lda _input_buf+1 + sta sreg+1 + ldy #$03 + jsr ldaxysp + clc + adc sreg + sta sreg + txa + adc sreg+1 + tax + lda sreg + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + ora #$80 + sta (ptr2),y + ldy #$03 + jsr ldaxysp + sta regsave + stx regsave+1 + jsr decax1 + ldy #$02 + jsr staxysp + lda regsave + ora regsave+1 + bne L049B + jsr ldax0sp + clc + adc _input_buf_len + pha + txa + adc _input_buf_len+1 + tax + pla + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + jsr pushw0sp + lda _stdout + ldx _stdout+1 + jsr _fputs + lda _stdout + ldx _stdout+1 + jsr _fflush + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; void __near__ main (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _main: near + +.segment "CODE" + + ldy #$4C + jsr subysp + jsr _disable_break + jsr _get_ostype + and #$07 + ldy #$4B + sta (sp),y + cmp #$01 + bne L003B + ldy #$FF +L0040: iny + lda L0001,y + sta _os_version,y + bne L0040 + jmp L0042 +L003B: lda (sp),y + cmp #$02 + bne L0042 + ldy #$FF +L0047: iny + lda L0001+4,y + sta _os_version,y + bne L0047 +L0042: lda #$01 + jsr _cursor + lda #$00 + sta $02C6 + lda #$0C + sta $02C5 + ldx #$00 + lda #$7D + jsr _putchar + lda #<(L0001+11) + ldx #>(L0001+11) + jsr _puts + ldx #$00 + lda #$9B + jsr _putchar + jsr _config_is_valid + tax + bne L005C + jsr _get_config + tax + bne L005C + jsr _set_default_config +L005C: lda _config + ldx _config+1 + sta sreg + stx sreg+1 + ldy #$96 + jsr ldaxidx + pha + txa + ora #$10 + tax + pla + ldy #$95 + sta (sreg),y + iny + txa + sta (sreg),y +L0061: lda #$00 + sta _done + jsr _rs232dev_close + lda _config + ldx _config+1 + ldy #$93 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta $02C6 + lda _config + ldx _config+1 + iny + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta $02C5 + lda #<(L0001+25) + ldx #>(L0001+25) + jsr pushax + ldy #$02 + jsr _printf + lda #<(L0001+61) + ldx #>(L0001+61) + jsr pushax + lda _config + ldx _config+1 + ldy #$11 + jsr incaxy + jsr pushax + ldy #$04 + jsr _printf + lda _stdout + ldx _stdout+1 + jsr _fflush + lda sp + ldx sp+1 + jsr pushax + lda #$40 + jsr pusha + jsr _get_line + lda sp + ldx sp+1 + jsr pushax + lda #<(L0001+68) + ldx #>(L0001+68) + jsr _strcasecmp + cpx #$00 + bne L007B + cmp #$00 + bne L007B + jsr _exit + jmp L0092 +L007B: lda sp + ldx sp+1 + jsr pushax + lda #<(L0001+70) + ldx #>(L0001+70) + jsr _strcasecmp + cpx #$00 + bne L0083 + cmp #$00 + bne L0083 + lda _atari_exec_p + ldx _atari_exec_p+1 + jsr pushax + lda #<(L0001+72) + ldx #>(L0001+72) + pha + ldy #$00 + lda (sp),y + sta jmpvec+1 + iny + lda (sp),y + sta jmpvec+2 + pla + jsr jmpvec + jsr incsp2 + ldy #$49 + jsr staxysp + lda #<(L0001+87) + ldx #>(L0001+87) + jsr pushax + ldy #$4E + jsr pushwysp + ldy #$04 + jsr _printf + ldy #$00 + jsr _bell + jmp L0061 +L0083: ldy #$00 + lda (sp),y + beq L0092 + lda _config + ldx _config+1 + ldy #$11 + jsr incaxy + jsr pushax + lda #$02 + jsr leaasp + jsr _strcpy +L0092: lda _config + ldx _config+1 + ldy #$10 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + jsr pusha + jsr _rs232dev_init + cmp #$00 + jne L0061 + lda #$41 + jsr leaasp + jsr pushax + jsr __clocks_per_sec + jsr shrax1 + jsr pushax + jsr _timer_set + jsr _uip_init + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr pushax + lda _config + ldx _config+1 + jsr incax4 + jsr pushax + ldx #$00 + lda #$04 + jsr _memcpy + lda #<(_uip_draddr) + ldx #>(_uip_draddr) + jsr pushax + lda _config + ldx _config+1 + jsr incax8 + jsr pushax + ldx #$00 + lda #$04 + jsr _memcpy + lda #$45 + jsr leaasp + sta sreg + stx sreg+1 + lda #$FF + ldy #$00 + sta (sreg),y + iny + sta (sreg),y + lda #$45 + jsr leaasp + sta sreg + stx sreg+1 + lda #$FF + iny + sta (sreg),y + iny + lda #$00 + sta (sreg),y + lda #<(_uip_netmask) + ldx #>(_uip_netmask) + jsr pushax + lda #$47 + jsr leaasp + jsr ldaxi + ldy #$00 + jsr staxspidx + lda #<(_uip_netmask) + ldx #>(_uip_netmask) + jsr pushax + lda #$47 + jsr leaasp + ldy #$03 + jsr ldaxidx + ldy #$02 + jsr staxspidx + lda _config + ldx _config+1 + ldy #$11 + jsr incaxy + jsr pushax + lda #$47 + jsr leaasp + jsr pushax + jsr _uiplib_ipaddrconv + tax + beq L00E3 + lda #$45 + jsr leaasp + jsr pushax + lda _config + ldx _config+1 + ldy #$53 + jsr pushwidx + jsr _htons + jsr pushax + jsr _uip_connect + jmp L00EB +L00E3: jsr _resolv_init + lda _config + ldx _config+1 + ldy #$0C + jsr incaxy + jsr pushax + jsr _resolv_conf + lda _config + ldx _config+1 + ldy #$11 + jsr incaxy + jsr pushax + jsr _resolv_query +L00EB: lda _done + jne L00F3 + jsr _rs232dev_poll + sta _uip_len + stx _uip_len+1 + cpx #$00 + bne L0526 + cmp #$00 + beq L00F7 +L0526: jsr pushc1 + jsr _uip_process + lda _uip_len + ora _uip_len+1 + jeq L011C + jsr _rs232dev_send + jmp L011C +L00F7: lda #$41 + jsr leaasp + jsr pushax + jsr _timer_expired + stx tmp1 + ora tmp1 + jeq L011C + lda #$41 + jsr leaasp + jsr pushax + jsr _timer_reset + ldx #$00 + txa +L0529: ldy #$49 + jsr staxysp + jsr pushax + lda #$01 + jsr toslta0 + beq L0107 + ldy #$4A + jsr ldaxysp + jsr pushax + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + tay + txa + adc #>(_uip_conns) + tax + tya + sta _uip_conn + stx _uip_conn+1 + jsr pushc2 + jsr _uip_process + lda _uip_len + ora _uip_len+1 + beq L0108 + jsr _rs232dev_send +L0108: ldy #$4A + jsr ldaxysp + jsr incax1 + jmp L0529 +L0107: ldx #$00 + txa +L052A: ldy #$49 + jsr staxysp + jsr pushax + lda #$01 + jsr toslta0 + beq L011C + ldy #$4A + jsr ldaxysp + jsr pushax + lda #$0B + jsr tosmula0 + clc + adc #<(_uip_udp_conns) + tay + txa + adc #>(_uip_udp_conns) + tax + tya + sta _uip_udp_conn + stx _uip_udp_conn+1 + lda #$05 + jsr pusha + jsr _uip_process + lda _uip_len + ora _uip_len+1 + beq L011D + jsr _rs232dev_send +L011D: ldy #$4A + jsr ldaxysp + jsr incax1 + jmp L052A +L011C: lda _vbell_active + beq L0130 + lda #<(_vbell_timer) + ldx #>(_vbell_timer) + jsr pushax + jsr _timer_expired + stx tmp1 + ora tmp1 + beq L0130 + lda _config + ldx _config+1 + ldy #$93 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta $02C6 + lda #$00 + sta _vbell_active +L0130: jsr _kbhit + tax + beq L013C + jsr _handle_keystroke +L013C: lda _connected + jeq L00EB + lda _nick_registered + jne L00EB + lda #<(_nick_reg_timer) + ldx #>(_nick_reg_timer) + jsr pushax + jsr _timer_expired + stx tmp1 + ora tmp1 + jeq L00EB + lda #<(L0001+98) + ldx #>(L0001+98) + jsr _puts + lda _input_buf + ldx _input_buf+1 + jsr pushax + lda #<(L0001+117) + ldx #>(L0001+117) + jsr pushax + lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr pushax + lda #$0A + jsr pusha0 + lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr pushax + lda #<(L0001+146) + ldx #>(L0001+146) + jsr pushax + lda _config + ldx _config+1 + ldy #$11 + jsr incaxy + jsr pushax + lda _config + ldx _config+1 + ldy #$69 + jsr incaxy + jsr pushax + lda #$0A + jsr pusha0 + ldy #$12 + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _input_buf + ldx _input_buf+1 + jsr pushax + lda _input_buf + ldx _input_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + lda #$00 + sta _input_buf_len + sta _input_buf_len+1 + lda #$01 + sta _nick_registered + jmp L00EB +L00F3: lda #$00 + sta _joined_channel + sta _nick_registered + sta _connected + jmp L0061 + +.endproc + +; --------------------------------------------------------------- +; void __near__ err_missing_arg (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _err_missing_arg: near + +.segment "CODE" + + lda #<(L0001+155) + ldx #>(L0001+155) + jsr _puts + jmp _bell + +.endproc + +; --------------------------------------------------------------- +; void __near__ err_no_channel (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _err_no_channel: near + +.segment "CODE" + + lda #<(L0001+181) + ldx #>(L0001+181) + jsr _puts + jmp _bell + +.endproc + +; --------------------------------------------------------------- +; void __near__ err_already_joined (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _err_already_joined: near + +.segment "CODE" + + lda #<(L0001+227) + ldx #>(L0001+227) + jsr _puts + jmp _bell + +.endproc + +; --------------------------------------------------------------- +; void __near__ del_last_word (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _del_last_word: near + +.segment "CODE" + + lda _input_buf_len + ldx _input_buf_len+1 + jsr pushax + jsr push0 +L017E: lda _input_buf_len + ora _input_buf_len+1 + beq L017F + lda _input_buf + ldx _input_buf+1 + clc + adc _input_buf_len + pha + txa + adc _input_buf_len+1 + tax + pla + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + bne L017F + ldx #$00 + lda #$01 + jsr addeq0sp + lda _input_buf_len + ldx _input_buf_len+1 + jsr decax1 + sta _input_buf_len + stx _input_buf_len+1 + jmp L017E +L017F: lda _input_buf_len + ora _input_buf_len+1 + beq L0187 + lda _input_buf + ldx _input_buf+1 + clc + adc _input_buf_len + pha + txa + adc _input_buf_len+1 + tax + pla + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L0187 + ldx #$00 + lda #$01 + jsr addeq0sp + lda _input_buf_len + ldx _input_buf_len+1 + jsr decax1 + sta _input_buf_len + stx _input_buf_len+1 + jmp L017F +L0187: ldy #$05 + jsr pushwysp + lda #$79 + jsr tosgea0 + beq L018E + lda _input_buf_len + ldx _input_buf_len+1 + jsr pushax + lda #$79 + jsr toslta0 + beq L018E + ldx #$00 + lda #$1C + jsr _putchar + ldx #$00 + lda #$9C + jsr _putchar + ldx #$00 + lda #$9C + jsr _putchar + ldy #$00 + jsr _redraw_user_buffer + jmp incsp4 +L018E: ldx #$00 + lda #$7E + jsr _putchar + ldx #$00 + lda #$01 + ldy #$00 + jsr subeqysp + stx tmp1 + ora tmp1 + bne L018E + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; void __near__ send_ctcp_version (__near__ unsigned char*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _send_ctcp_version: near + +.segment "CODE" + + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+324) + ldx #>(L0001+324) + jsr pushax + ldy #$07 + jsr pushwysp + jsr push1 + jsr push1 + lda #$0A + jsr pusha0 + ldy #$0C + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ send_ctcp_ping (__near__ unsigned char*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _send_ctcp_ping: near + +.segment "CODE" + + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+349) + ldx #>(L0001+349) + jsr pushax + ldy #$07 + jsr pushwysp + jsr push1 + lda $0014 + jsr pusha0 + lda $0013 + jsr pusha0 + lda $0012 + jsr pusha0 + jsr push1 + lda #$0A + jsr pusha0 + ldy #$12 + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ do_me (__near__ unsigned char*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _do_me: near + +.segment "CODE" + + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+386) + ldx #>(L0001+386) + jsr pushax + lda #<(_channel) + ldx #>(_channel) + jsr pushax + jsr push1 + ldy #$0B + jsr pushwysp + jsr push1 + lda #$0A + jsr pusha0 + ldy #$0E + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ do_pong (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _do_pong: near + +.segment "CODE" + + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _output_buf_len + ldx _output_buf_len+1 + jsr _memcpy + lda _chan_msg_buf + sta sreg + lda _chan_msg_buf+1 + sta sreg+1 + lda #$4F + ldy #$01 + sta (sreg),y +L0343: jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L0344 + jsr ldax0sp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$9B + bne L0346 + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$0A + ldy #$00 + sta (sreg),y +L0346: jsr ldax0sp + jsr incax1 + jsr stax0sp + jmp L0343 +L0344: lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _output_buf_len + ldx _output_buf_len+1 + jsr pushax + jsr _telnet_send + lda _config + ldx _config+1 + ldy #$96 + jsr ldaxidx + txa + and #$40 + jeq incsp2 + lda #<(L0001+591) + ldx #>(L0001+591) + jsr _puts + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ do_server_msg (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _do_server_msg: near + +.segment "CODE" + + lda _output_buf + ldx _output_buf+1 + jsr pushax + jsr decsp6 + jsr push0 + jsr decsp2 +L0356: ldy #$0B + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L0357 + ldy #$0A + ldx #$00 + lda #$01 + jsr addeqysp + jmp L0356 +L0357: ldy #$0A + ldx #$00 + lda #$01 + jsr addeqysp + ldy #$0B + jsr ldaxysp + ldy #$08 + jsr staxysp +L035D: ldy #$09 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L035E + ldy #$08 + ldx #$00 + lda #$01 + jsr addeqysp + jmp L035D +L035E: ldy #$09 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + ldy #$08 + tax + lda #$01 + jsr addeqysp + lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr _strlen + jsr stax0sp + ldy #$0B + jsr pushwysp + lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr pushax + ldy #$05 + jsr ldaxysp + jsr _memcmp + cpx #$00 + bne L0367 + cmp #$00 + bne L0367 + jsr ldax0sp + jsr incax1 + ldy #$08 + jsr addeqysp +L0367: ldy #$0B + jsr ldaxysp + jsr _atoi + ldy #$02 + jsr staxysp + stx tmp1 + ora tmp1 + jeq L0370 + ldy #$03 + jsr ldaxysp + cpx #$01 + jne L039D + cmp #$3B + jeq L038C + cmp #$4C + beq L0379 + cmp #$4D + beq L037E + cmp #$60 + beq L038C + cmp #$61 + beq L038C + cmp #$6E + beq L038C + cmp #$74 + beq L0383 + cmp #$76 + beq L038C + cmp #$77 + beq L038B + jmp L039D +L0379: lda #<(L0001+603) + ldx #>(L0001+603) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$04 + jmp L052B +L037E: lda #<(L0001+615) + ldx #>(L0001+615) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$04 + jmp L052B +L0383: lda _config + ldx _config+1 + ldy #$96 + jsr ldaxidx + txa + and #$10 + tax + lda #$00 + jsr bnegax + beq L03A2 + ldy #$0B + jsr pushwysp + lda _stdout + ldx _stdout+1 + jsr _fputs + jmp L03A2 +L038B: lda _config + ldx _config+1 + ldy #$96 + jsr ldaxidx + txa + and #$10 + beq L038C + lda #<(L0001+633) + ldx #>(L0001+633) + jsr _puts + jmp L03A2 +L038C: ldy #$0B + jsr pushwysp + lda _stdout + ldx _stdout+1 + jsr _fputs + jmp L03A2 +L039D: lda #<(L0001+660) + ldx #>(L0001+660) + jsr pushax + ldy #$05 + jmp L0531 +L0370: lda #<(L0001+666) + ldx #>(L0001+666) + jsr pushax + ldy #$0D +L0531: jsr ldaxysp + jsr pushax + ldy #$0F + jsr pushwysp + ldy #$06 +L052B: jsr _printf +L03A2: ldy #$0C + jmp addysp + +.endproc + +; --------------------------------------------------------------- +; unsigned char __near__ do_ctcp (__near__ unsigned char*, __near__ unsigned char*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _do_ctcp: near + +.segment "CODE" + + ldy #$0C + jsr subysp + ldy #$0F + jsr pushwysp + lda #<(L0001+672) + ldx #>(L0001+672) + jsr pushax + ldx #$00 + lda #$05 + jsr _memcmp + cpx #$00 + jne L03A8 + cmp #$00 + jne L03A8 + jsr _clock + jsr pusheax + ldx #$00 + stx sreg + stx sreg+1 + lda #$0A + jsr tosumuleax + ldy #$08 + jsr steaxysp + ldy #$0D + jsr ldaxysp + jsr incax5 + jsr _atoi + jsr axlong + jsr pusheax + ldy #$11 + jsr ldaxysp + ldy #$09 + jsr incaxy + jsr _atoi + jsr axlong + ldy sreg + sty sreg+1 + stx sreg + tax + lda #$00 + jsr tosaddeax + jsr pusheax + ldy #$11 + jsr ldaxysp + ldy #$0D + jsr incaxy + jsr _atoi + jsr axlong + stx sreg+1 + sta sreg + lda #$00 + tax + jsr tosaddeax + jsr pusheax + ldx #$00 + stx sreg + stx sreg+1 + lda #$0A + jsr tosmuleax + ldy #$04 + jsr steaxysp + ldy #$07 + jsr ldeaxysp + ldy #$08 + jsr lsubeqysp + ldy #$0B + jsr ldeaxysp + jsr pusheax + jsr __clocks_per_sec + jsr axulong + jsr tosudiveax + ldy #$08 + jsr steaxysp + ldy #$0B + jsr ldeaxysp + jsr pusheax + ldx #$00 + stx sreg + stx sreg+1 + lda #$0A + jsr tosdiveax + ldy #$02 + jsr staxysp + ldy #$0B + jsr ldeaxysp + jsr pusheax + ldx #$00 + stx sreg + stx sreg+1 + lda #$0A + jsr tosmodeax + jsr stax0sp + lda #<(L0001+678) + ldx #>(L0001+678) + jsr pushax + ldy #$13 + jsr pushwysp + ldy #$09 + jsr pushwysp + ldy #$09 + jsr pushwysp + ldy #$08 + jsr _printf + ldx #$00 + lda #$01 + jmp L03A7 +L03A8: ldx #$00 + txa +L03A7: ldy #$10 + jmp addysp + +.endproc + +; --------------------------------------------------------------- +; void __near__ do_msg (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _do_msg: near + +.segment "CODE" + + lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _output_buf + ldx _output_buf+1 + jsr pushax + jsr push0 + jsr push0 + jsr push0 +L03D0: ldy #$07 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L03D1 + ldy #$07 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$21 + bne L03D3 + ldy #$07 + jsr ldaxysp + jsr stax0sp +L03D3: ldy #$06 + ldx #$00 + lda #$01 + jsr addeqysp + jmp L03D0 +L03D1: iny + lda (sp),y + dey + ora (sp),y + bne L03D8 + jsr _do_server_msg + jmp L03CA +L03D8: ldy #$07 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + ldy #$06 + tax + lda #$01 + jsr addeqysp + ldy #$07 + jsr ldaxysp + ldy #$04 + jsr staxysp +L03E0: ldy #$05 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L03E1 + ldy #$04 + ldx #$00 + lda #$01 + jsr addeqysp + jmp L03E0 +L03E1: ldy #$05 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + ldy #$04 + tax + lda #$01 + jsr addeqysp + ldy #$05 + jsr ldaxysp + ldy #$02 + jsr staxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$9B + beq L03F6 +L03EB: ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L03EC + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$20 + beq L03EC + ldy #$02 + ldx #$00 + lda #$01 + jsr addeqysp + jmp L03EB +L03EC: ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L03F6 + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + ldy #$02 + tax + lda #$01 + jsr addeqysp + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$3A + bne L03F6 + ldy #$02 + ldx #$00 + lda #$01 + jsr addeqysp +L03F6: ldy #$09 + jsr pushwysp + lda #<(L0001+701) + ldx #>(L0001+701) + jsr _strcmp + cpx #$00 + jne L03F9 + cmp #$00 + jne L03F9 + ldy #$09 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$3C + ldy #$00 + sta (sreg),y + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$3E + ldy #$00 + sta (sreg),y + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$01 + sta (sreg),y + ldy #$07 + jsr pushwysp + lda _config + ldx _config+1 + ldy #$54 + jsr incaxy + jsr _strcasecmp + cpx #$00 + bne L0533 + cmp #$00 + jeq L0407 +L0533: ldy #$05 + jsr pushwysp + lda #<(L0001+709) + ldx #>(L0001+709) + jsr pushax + ldx #$00 + lda #$08 + jsr _memcmp + cpx #$00 + bne L040C + cmp #$00 + bne L040C + ldy #$09 + jsr ldaxysp + jsr incax1 + ldy #$08 + jsr staxysp + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _output_buf_len + ldx _output_buf_len+1 + jsr decax2 + jsr tosaddax + sta sreg + stx sreg+1 + lda #$9B + ldy #$00 + sta (sreg),y + lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _output_buf_len + ldx _output_buf_len+1 + jsr decax1 + jsr tosaddax + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda #<(L0001+718) + ldx #>(L0001+718) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$07 + jsr ldaxysp + jsr incax8 + jsr pushax + ldy #$06 + jmp L0532 +L040C: lda #<(L0001+726) + ldx #>(L0001+726) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$09 + jsr pushwysp + ldy #$06 + jmp L0532 +L0407: ldy #$05 + jsr pushwysp + lda #<(L0001+732) + ldx #>(L0001+732) + jsr pushax + ldx #$00 + lda #$06 + jsr _memcmp + cpx #$00 + jne L0425 + cmp #$00 + jne L0425 + ldy #$09 + jsr ldaxysp + jsr incax1 + ldy #$08 + jsr staxysp + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda _output_buf + ldx _output_buf+1 + jsr pushax + lda _output_buf_len + ldx _output_buf_len+1 + jsr decax2 + jsr tosaddax + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+739) + ldx #>(L0001+739) + jsr pushax + ldy #$0F + jsr pushwysp + ldy #$09 + jsr ldaxysp + jsr incax6 + jsr pushax + lda #$0A + jsr pusha0 + tay + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + lda #<(L0001+762) + ldx #>(L0001+762) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$04 + jmp L0532 +L0425: ldy #$05 + jsr pushwysp + lda #<(L0001+783) + ldx #>(L0001+783) + jsr pushax + ldx #$00 + lda #$09 + jsr _memcmp + cpx #$00 + bne L0440 + cmp #$00 + bne L0440 + ldy #$09 + jsr ldaxysp + jsr incax1 + ldy #$08 + jsr staxysp + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda #<(L0001+793) + ldx #>(L0001+793) + jsr pushax + ldy #$0F + jsr pushwysp + lda #<(_os_version) + ldx #>(_os_version) + jsr pushax + lda #$0A + jsr pusha0 + tay + jsr _sprintf + lda _tstate + ldx _tstate+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr pushax + lda _chan_msg_buf + ldx _chan_msg_buf+1 + jsr _strlen + jsr pushax + jsr _telnet_send + lda #<(L0001+855) + ldx #>(L0001+855) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$04 + jmp L0532 +L0440: lda #<(L0001+879) + ldx #>(L0001+879) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$09 + jsr pushwysp + ldy #$06 + jsr _printf + lda _config + ldx _config+1 + ldy #$96 + jsr ldaxidx + txa + and #$80 + beq L045C + jsr _bell +L045C: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + lda #<(_last_msg_nick) + ldx #>(_last_msg_nick) + jsr pushax + ldy #$0B + jsr ldaxysp + jsr incax1 + jsr _strcpy + jmp L0482 +L03F9: ldy #$09 + jsr pushwysp + lda #<(L0001+890) + ldx #>(L0001+890) + jsr _strcmp + cpx #$00 + bne L0465 + cmp #$00 + bne L0465 + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$01 + bne L0465 + ldy #$09 + jsr ldaxysp + jsr incax1 + ldy #$08 + jsr staxysp + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + ldy #$0B + jsr pushwysp + ldy #$05 + jsr ldaxysp + jsr incax1 + jsr pushax + jsr _do_ctcp + tax + bne L0482 + lda #<(L0001+897) + ldx #>(L0001+897) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$07 + jsr ldaxysp + jsr incax1 + jsr pushax + ldy #$06 + jmp L0532 +L0465: ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L047A + lda #<(L0001+922) + ldx #>(L0001+922) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$0D + jsr pushwysp + ldy #$0D + jsr pushwysp + ldy #$0D + jsr pushwysp + ldy #$0A + jmp L0532 +L047A: lda #<(L0001+934) + ldx #>(L0001+934) + jsr pushax + ldy #$0D + jsr pushwysp + ldy #$0D + jsr pushwysp + ldy #$0D + jsr pushwysp + ldy #$08 +L0532: jsr _printf +L0482: lda _stdout + ldx _stdout+1 + jsr _fflush +L03CA: ldy #$0A + jmp addysp + +.endproc + +; --------------------------------------------------------------- +; void __near__ del_user_buffer (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _del_user_buffer: near + +.segment "CODE" + + lda _input_buf_len + ora _input_buf_len+1 + beq L048F + ldx #$00 + lda #$9C + jsr _putchar + lda _input_buf_len + ldx _input_buf_len+1 + jsr pushax + lda #$78 + jsr tosgea0 + beq L048F + ldx #$00 + lda #$1C + jsr _putchar + ldx #$00 + lda #$9C + jmp _putchar +L048F: rts + +.endproc + diff --git a/src/fujichat-0.1.atr b/src/fujichat-0.1.atr new file mode 100644 index 0000000..47f16d0 Binary files /dev/null and b/src/fujichat-0.1.atr differ diff --git a/src/fujichat-0.3.atr b/src/fujichat-0.3.atr new file mode 100644 index 0000000..95c2f70 Binary files /dev/null and b/src/fujichat-0.3.atr differ diff --git a/src/fujichat.atr b/src/fujichat.atr new file mode 100644 index 0000000..613a085 Binary files /dev/null and b/src/fujichat.atr differ diff --git a/src/fujichat.atr.ok b/src/fujichat.atr.ok new file mode 100644 index 0000000..b1f8912 Binary files /dev/null and b/src/fujichat.atr.ok differ diff --git a/src/fujichat.c b/src/fujichat.c new file mode 100644 index 0000000..c6412c6 --- /dev/null +++ b/src/fujichat.c @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2008, Brian Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgements: + * This product includes software developed by Adam Dunkels. + * This product includes software developed by Brian Watson. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the FujiChat IRC client. + * + */ + + +/* standard C includes */ +#include +#include +#include +#include + +/* cc65 includes */ +#include +#include +#include + +/* uIP includes */ +#include "timer.h" +#include "uip.h" +#include "uiplib.h" +#include "rs232dev.h" + +/* FujiChat includes */ +#include "fujichat.h" +#include "common.h" +#include "features.h" + +#ifdef FEAT_KEYBOARD_MACROS +#include "keybuf.h" +#endif + +#ifdef FEAT_COL80_HACK +/* $54 and $55 are ROWCRS and COLCRS. + COL80 uses them the same way the OS does. */ +# define fuji_gotox(x) POKE(0x55, x) +# define fuji_gotoy(y) POKE(0x54, y) +# define fuji_getxpos() PEEK(0x55) +# define fuji_getypos() PEEK(0x54) + +/* TODO: calculate from RMARGN-LMARGN. Currently COL80 doesn't set RMARGN */ +# ifndef COLUMNS +# define COLUMNS 80 +# endif +#endif + + +#ifdef FEAT_DYNAMIC_VERSION +char os_version[10] = "XL_XE"; +#else +#define os_version "8-bit" +#endif + +#ifdef FEAT_LOW_RAM_BUFFERS +#define LOW_RAM_BASE 0x2900 +char *input_buf = (char *)LOW_RAM_BASE; // $2900 - $21FF +char *serv_msg_buf = (char *)(LOW_RAM_BASE + BUF_SIZE); // $2A00 - $2BFF +char *output_buf = (char *)(LOW_RAM_BASE + BUF_SIZE + BUF_SIZE * 2); // $2C00 - $2DFF +#else +char input_buf[BUF_SIZE]; +char serv_msg_buf[BUF_SIZE * 2]; +char output_buf[OUTBUF_SIZE]; +#endif + +char channel[HOSTLEN]; + +#ifdef FEAT_KEYBOARD_MACROS +char last_msg_nick[NICKLEN+1] = ""; +#endif + +int serv_msg_buf_len = 0; +int input_buf_len = 0; +int output_buf_len = 0; + +char done = 0; +char connected = 0; +char joined_channel = 0; /* true if we're in a channel */ +char nick_registered = 0; + +#ifdef FEAT_VISUAL_BELL +char vbell_active = 0; +#endif + +#ifdef FEAT_ATRACT_AWAY +char away = 0; +#endif + +static void handle_keystroke(void); + +#ifdef FEAT_LOGGING +static void alloc_log_buffer(); +#endif + +#if defined(FEAT_CURSOR_CONTROLS) || defined(FEAT_COL80_HACK) +void redraw_user_buffer(); +void del_user_buffer(); +#endif + +/* uIP API stuff */ +struct timer nick_reg_timer; /* ../uip/timer.h */ +struct telnet_state *tstate; /* ../apps/telnet.h */ + +#ifdef FEAT_VISUAL_BELL +struct timer vbell_timer; +#endif + +/*---------------------------------------------------------------------------*/ +void main(void) { +#ifdef FEAT_DYNAMIC_VERSION + char c; +#endif + int i; + uip_ipaddr_t ipaddr; + struct timer periodic_timer; + char cmdbuf[HOSTLEN+1]; + + disable_break(); + +#ifdef FEAT_DYNAMIC_VERSION + c = get_ostype() & AT_OS_TYPE_MAIN; + if(c == AT_OS_400800) { + strcpy(os_version, "800"); + } else if(c == AT_OS_1200XL) { + strcpy(os_version, "1200XL"); + } +#endif + + /* set screen colors to white-on-black initially. They may be + reset by the user's config file, once it's loaded */ + POKE(710, 0); + POKE(709, 12); + +#ifndef FEAT_COL80_HACK + fuji_putchar(A_CLR); +#endif + + puts(BANNER); + fuji_putchar('\n'); + + if(!config_is_valid()) { + if(!get_config()) + set_default_config(); + } + +#ifdef FEAT_LOGGING + alloc_log_buffer(); +#endif + + // config->ui_flags |= UIFLAG_HIDEMOTD; // TODO: make it a preference! + + while(1) { + done = 0; + rs232dev_close(); + + POKE(710, config->bg_color); + POKE(709, config->fg_color); + + printf("Server name/IP, [C]onfig, or [D]OS\n"); + printf("[%s]: ", config->server); + fflush(stdout); + get_line(cmdbuf, HOSTLEN); + + if(strcasecmp(cmdbuf, "d") == 0) { + exit(0); + } else if(strcasecmp(cmdbuf, "c") == 0) { + i = atari_exec(SETUP_FILENAME); + printf("Error %d!\n", i); + bell(); + continue; + } else if(*cmdbuf) { + strcpy(config->server, cmdbuf); + } + /* else, use the existing config->server */ + + if(rs232dev_init(config->baud) != RS_ERR_OK) + continue; + + timer_set(&periodic_timer, CLOCK_SECOND / 2); + + uip_init(); + + memcpy(uip_hostaddr, &(config->local_ip), 4); + memcpy(uip_draddr, &(config->peer_ip), 4); + + /* can I use 255.255.255.252 here? Does it matter? */ + uip_ipaddr(ipaddr, 255,255,255,0); + uip_setnetmask(ipaddr); + + if(uiplib_ipaddrconv(config->server, (unsigned char*)&ipaddr)) { + (void)uip_connect(&ipaddr, htons(config->server_port)); + } else { + resolv_init(); + resolv_conf((u16_t *)&(config->resolver_ip)); // TODO: fix so I don't need extra () + resolv_query(config->server); + } + + while(!done) { + /* This part of the while loop is straight from the no-ARP example + code, from the uIP docs. */ + uip_len = rs232dev_poll(); + if(uip_len > 0) { + uip_input(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } else if(timer_expired(&periodic_timer)) { + timer_reset(&periodic_timer); + for(i = 0; i < UIP_CONNS; i++) { + uip_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } + +#if UIP_UDP + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } +#endif /* UIP_UDP */ + } + +#ifdef FEAT_VISUAL_BELL + if(vbell_active && timer_expired(&vbell_timer)) { + POKE(710, config->bg_color); + vbell_active = 0; + } +#endif + + /* Call the keyboard handler if the user pressed a key. Note that + we're using stdio for printing, but conio for reading, which + works on the Atari but may not work on all other cc65 platforms */ +#ifdef FEAT_KEYBOARD_BUFFER + /* always call; will return if nothing to do */ + handle_keystroke(); +#else + if(PEEK(764) != 0xff) { /* check CH (replaces kbhit()) */ + handle_keystroke(); + } +#endif + +#ifdef FEAT_ATRACT_AWAY + if(away && input_buf_len && !(PEEK(77) & 0x80)) { + away = 0; + send_server_cmd("AWAY", NULL); + } else if(!away && (PEEK(77) & 0x80)) { + away = 1; + send_server_cmd("AWAY", "ATRACT Mode"); + } +#endif + + /* Automatically register the nick and userhost after being + connected for a couple seconds. The parameters for the USER + command are ignored by the server (at least the NewNet servers) */ + if(connected && !nick_registered && timer_expired(&nick_reg_timer)) { + puts("> Registering nick"); + + serv_msg_buf_len = sprintf( + serv_msg_buf, "NICK %s%cUSER %s %s %s :%s%c", + config->nick, NL, config->nick, SELF, + config->server, config->real_name, NL); + send_serv_msg_buf(); + + /* + sprintf(input_buf, "NICK %s%cUSER %s %s %s :%s%c", + config->nick, NL, config->nick, SELF, + config->server, config->real_name, NL); + telnet_send(tstate, input_buf, strlen(input_buf)); + */ + + input_buf_len = 0; + nick_registered = 1; + /* TODO: check for failure registering the nick */ + } + + /* + if(PEEK(53279) == 6) { // START pressed + puts("Disconnecting"); + uip_close(); + // done = 1; + } + */ + } + + connected = nick_registered = joined_channel = 0; + } + // return 0; +} + +void bell() { + if(config->ui_flags & UIFLAG_NOBELL) + return; + +#ifdef FEAT_VISUAL_BELL + if(config->ui_flags & UIFLAG_VBELL) { + vbell_active = 1; + timer_set(&vbell_timer, CLOCK_SECOND / 10); + POKE(710, config->bg_color + 8); + return; + } +#endif + +#ifndef FEAT_COL80_HACK /* COL80 E: doesn't do the bell character */ + fuji_putchar(A_BEL); +#endif +} + +static void err_no_channel(void) { + puts("You are not in a channel (use /join #channel)"); + bell(); +} + +#ifdef FEAT_CURSOR_CONTROLS +static void del_last_word(void) { + int old = input_buf_len, bs = 0; + + while(input_buf_len && input_buf[input_buf_len] == ' ') { + ++bs; + input_buf_len--; + } + + while(input_buf_len && input_buf[input_buf_len] != ' ') { + ++bs; + input_buf_len--; + } + + if(old > 120 && input_buf_len <= 120) { + fuji_putchar(0x1c); + fuji_putchar(A_DEL); + fuji_putchar(A_DEL); + redraw_user_buffer(); + } else do { + fuji_putchar(A_BS); + } while(--bs); +} +#endif + +#ifdef FEAT_COL80_HACK +void col80_backspace(char destructive) { + char x = fuji_getxpos(); + char y = fuji_getypos(); + + if(x) { + --x; + } else { + x = COLUMNS - 1; + --y; + } + + fuji_gotox(x); + fuji_gotoy(y); + if(destructive) { + fuji_putchar(' '); + fuji_gotox(x); + fuji_gotoy(y); + } +} + +//void col80_cursor(void) { +// fuji_putchar(0xa0); /* inverse space */ +// col80_backspace(0); +//} + +# define backspace() col80_backspace(1) + +#else +# define backspace() fuji_putchar(A_BS) +#endif + +/* Keyboard handler. For now, the keyboard macros are hard-coded. */ +static void handle_keystroke(void) { + char i, c, send_buf = 0; + + /* TODO: + ctrl-7 = ` (warning: cgetc() can't read this) + ctrl-, = { + ctrl-. = } + ctrl-; = ~ (don't do ctrl-^, that's left-arrow!) + + Ignore inverse-video key, ATASCII graphics, unwanted + cursor actions, make caps-lock stop freezing the program. + To do this right, we have to examine location 764 for some + of these, and don't call cgetc() at all... or actually, + stuff a valid keycode there, then call cgetc() to make a + keyclick noise (but ignore its return value). + Addendum - this should be handled in keybuf.s? + + Stock col80 key mappings are warped: + ctrl-clear = } + ctrl-; = { + ctrl-. = ` + No way to type a tilde because that's the A8 backspace char :( + + */ +#ifdef FEAT_KEYBOARD_BUFFER + c = keybuf_cgetc(); + if(!c) return; +#else + c = fuji_cgetc(); +#endif + +#ifdef FEAT_KEYBOARD_MACROS + /* Keyboard macros, only allowed at the start of a new line */ + if(input_buf_len == 0) { + switch(c) { + case 0x0e: /* ctrl-N */ + if(joined_channel) send_server_cmd("NAMES", channel); + return; + + case 0x17: /* ctrl-W */ + if(joined_channel) send_server_cmd("WHO", channel); + return; + + case A_EOL: + return; /* ignore Return on a line by itself */ + + case A_TAB: + if(last_msg_nick[0]) { + sprintf(input_buf, "/msg %s ", last_msg_nick); + input_buf_len = strlen(input_buf); + for(i=0; i 0) { + input_buf_len--; +#ifdef FEAT_COL80_HACK + col80_backspace(1); + // fuji_putchar(' '); + // col80_backspace(0); + // col80_cursor(); +#else + fuji_putchar(c); +#endif + } else { + bell(); + } + + return; + } else if(c == A_DEL || c == 0x15) { + /* shift-backspace or ^U (delete line) */ +#ifdef FEAT_COL80_HACK + del_user_buffer(); + // col80_cursor(); +#else + fuji_putchar(A_DEL); +#endif + input_buf_len = 0; + return; +#ifdef FEAT_CURSOR_CONTROLS + } else if(c == 0x17) { + /* ^W (delete word) */ + del_last_word(); + return; +#endif + } + + /* Echo keystroke */ + fuji_putchar(c | 0x80); /* inverse video for now */ + + if(c == A_EOL) { + c = NL; + send_buf = 1; + } else if(c == A_TAB) { + c = TAB; + } +// #ifdef FEAT_COL80_HACK + // else { col80_cursor(); } +// #endif + + +#ifdef FEAT_UNICODE_TEST + if(c == 0x10) { /* ATASCII clubs symbol */ + input_buf[input_buf_len++] = 0xe2; /* UTF-8 marker */ + input_buf[input_buf_len++] = 0x99; + input_buf[input_buf_len++] = 0xa3; + fuji_putchar(c); + return; + } +#endif + + /* Store keystroke in input buffer */ + input_buf[input_buf_len++] = c; + + /* If line too long, ring the "margin" bell */ + if(input_buf_len > BUF_SIZE - 1) + if(!send_buf) { + bell(); + // fuji_putchar(A_BS); + backspace(); + input_buf_len--; + } + + /* If we've got a complete line of input and user has pressed Return, + send it to the server */ + if(send_buf) { + input_buf[input_buf_len] = '\0'; + + if(*input_buf == '/') { + handle_command(); + } else if(joined_channel) { + sprintf(serv_msg_buf, "PRIVMSG %s :%s", channel, input_buf); + telnet_send(tstate, serv_msg_buf, strlen(serv_msg_buf)); + } else { + err_no_channel(); + } + + input_buf_len = 0; + } +} + +void send_serv_msg_buf(void) { + telnet_send(tstate, serv_msg_buf, serv_msg_buf_len); +} + +void send_server_cmd(char *cmd, char *arg) { + if(arg) { + serv_msg_buf_len = sprintf(serv_msg_buf, "%s %s%c", cmd, arg, NL); + } else { + serv_msg_buf_len = sprintf(serv_msg_buf, "%s%c", cmd, NL); + } + + send_serv_msg_buf(); +} + +/* The telnet_* functions are uIP application callbacks. */ +void telnet_connected(struct telnet_state *s) { + /* puts("Connected to host, press START to disconnect"); */ + puts("> Connected to server"); + tstate = s; + s->text = NULL; + s->textlen = 0; + timer_set(&nick_reg_timer, CLOCK_SECOND); + connected = 1; +} + +/* 20081125 bkw: why don't these pragmas do anything? */ +#pragma warn (off) +void telnet_closed(struct telnet_state *s) { + puts("> Connection closed"); + uip_close(); + done = 1; +} + +void telnet_sent(struct telnet_state *s) { +} + +void telnet_aborted(struct telnet_state *s) { + puts("> Connection aborted"); + uip_abort(); + done = 1; +} + +void telnet_timedout(struct telnet_state *s) { + puts("> Connection timed out"); + uip_abort(); + done = 1; +} +#pragma warn (on) + +void do_pong() { + char *p = serv_msg_buf; + + memcpy(serv_msg_buf, output_buf, output_buf_len); + serv_msg_buf[1] = 'O'; + while(*p) { + if(*p == A_EOL) *p = NL; + p++; + } + + telnet_send(tstate, serv_msg_buf, output_buf_len); + if(config->ui_flags & UIFLAG_SHOWPING) + puts("[PING,PONG]"); +} + +void do_server_msg() { + char *cmd = output_buf, *arg; + int numeric = 0, len; + + while(*cmd != ' ') + ++cmd; + + ++cmd; + + arg = cmd; + while(*arg != ' ') + ++arg; + + *arg = '\0'; + ++arg; + + len = strlen(config->nick); + if(memcmp(arg, config->nick, len) == 0) + arg += (len + 1); // skip nick if present + + if(arg[0] == ':') + ++arg; + + /* now cmd points to the command (numeric or whatever), + arg points to the rest of the string. + Numeric commands we handle now I guess. I think they + all have the nick as the 1st argument... + */ + if( (numeric = atoi(cmd)) ) { + switch(numeric) { + case 332: // topic + printf("> Topic: %s", arg); + return; + break; + + case 333: // topic nick + printf("> Topic set by %s", arg); + return; + break; + + case 375: // start of MOTD + case 372: // MOTD text + if(config->ui_flags & UIFLAG_HIDEMOTD) { + if(numeric == 375) + puts("> Hiding MOTD (be patient)"); + } + return; + break; + + case 376: // end of MOTD + case 422: // or MOTD missing + if(*(config->channel)) { + strcpy(channel, config->channel); + printf("> Joining %s\n", channel); + send_server_cmd("JOIN", channel); + joined_channel = 1; + } + break; + + /* + case 352: // /who list + case 353: // /names list + case 366: // end of /names + case 315: // end of /who + break; + */ + + default: + break; + } + } + + printf("%s %s", cmd, arg); +} + +char incoming_ctcp(char *nick, char *msg) { + long now, then; + int sec, dec; + + if(memcmp(msg, "PING ", 5) == 0) { + now = clock() * 10L; + then = ((long)(atoi(msg + 5)) + + ((long)(atoi(msg + 9)) << 8) + + ((long)(atoi(msg + 13)) << 16)) * 10L; + + now -= then; + now /= CLOCKS_PER_SEC; + sec = now / 10; + dec = now % 10; + + /* silently ignore timestamp wraparound */ + /* + if(then >= now) + return 1; + */ + + printf("> %s ping time: %d.%d\n", nick, sec, dec); + return 1; + } + + return 0; +} + +/* Handler for text received from the server, responsible for + formatting. TODO: part/join/quit aren't handled correctly. */ +void do_msg() { + char *nick = output_buf, *cmd = output_buf, *chan = NULL, *msg = NULL; + char *bang = NULL; + + while(*cmd != ' ') { + if(*cmd == '!') { + bang = cmd; + } + ++cmd; + } + + /* no ! in nick means a server message */ + if(!bang) { + do_server_msg(); + return; + } + + *cmd = '\0'; + ++cmd; + chan = cmd; + + while(*chan != ' ') + ++chan; + *chan = '\0'; + ++chan; + msg = chan; + + if(*msg != A_EOL) { + while(*msg && *msg != ' ') + ++msg; + if(*msg) { + *msg = '\0'; + ++msg; + if(*msg == ':') ++msg; + } + } + + /* FIXME: This stuff is hairy, unmaintainable, and probably just wrong + (works OK with the 2 or 3 NewNet servers I test with, not tried + others). It's the result of too much coffee, and needs to be + redesigned. Heck, it needs to be designed in the first place! */ + if(strcmp(cmd, "PRIVMSG") == 0) { + nick[0] = '<'; + bang[0] = '>'; + bang[1] = '\0'; + if(strcasecmp(chan, config->nick) != 0) { + // privmsg, not to our nick, must be channel text + if(memcmp(msg, "\x01" "ACTION ", 8) == 0) { + nick++; + *bang = '\0'; + output_buf[output_buf_len - 2] = A_EOL; + output_buf[output_buf_len - 1] = '\0'; + printf("* %s %s", nick, msg + 8); + } else { + printf("%s %s", nick, msg); + } + } else { + // privmsg, is to our nick + if(memcmp(msg, "\x01" "PING ", 6) == 0) { + nick++; + bang[0] = '\0'; + output_buf[output_buf_len - 2] = '\0'; + serv_msg_buf_len = sprintf(serv_msg_buf, "NOTICE %s :\x01PING %s\x01%c", + nick, msg + 6, 0x0a); + send_serv_msg_buf(); + printf("* CTCP PING from %s\n", nick); + } else if(memcmp(msg, "\x01" "VERSION\x01", 9) == 0) { + nick++; + *bang = '\0'; + serv_msg_buf_len = sprintf(serv_msg_buf, "NOTICE %s :\x01VERSION " + VERSION_REPLY " - running on " + "an Atari %s\x01%c", + nick, os_version, 0x0a); + send_serv_msg_buf(); + printf("* CTCP VERSION from %s\n", nick); + } else { + printf("-> %s %s", nick, msg); + if(config->ui_flags & UIFLAG_MSGBELL) + bell(); + bang[0] = '\0'; +#ifdef FEAT_KEYBOARD_MACROS + strcpy(last_msg_nick, nick + 1); +#endif + } + } + } else if((strcmp(cmd, "NOTICE") == 0) && msg[0] == '\x01') { + nick++; + *bang = '\0'; + if(!incoming_ctcp(nick, msg+1)) + printf("* CTCP reply from %s: %s", nick, msg+1); // still has A_EOL + } else { + if(*msg) { + printf("%s %s %s %s", nick, cmd, chan, msg); + } else { + printf("%s %s %s", nick, cmd, chan); + } + } + + fflush(stdout); +} + +#ifdef FEAT_CURSOR_CONTROLS +void del_user_buffer() { + /* delete user edit buffer */ + if(input_buf_len) { + fuji_putchar(A_DEL); + if(input_buf_len > 119) { + fuji_putchar(0x1c); /* up arrow */ + fuji_putchar(A_DEL); + } + } +} + +#elif defined(FEAT_COL80_HACK) + +/* COL80 doesn't support the delete-line or arrow key + control codes. + + Deleting and redrawing the user buffer is done by: + + 1. Move the cursor to the start of the buffer on screen + 2. Print input_buf_len spaces + 3. Move cursor to the same spot as (1) + 4. Print the incoming text including EOL as usual + 5. redraw_user_buffer() as usual +*/ + +void del_user_buffer() { + int tlen; + char oldy; + + if(!input_buf_len) + return; + + tlen = input_buf_len; + oldy = fuji_getypos() - (input_buf_len / COLUMNS); + + fuji_gotox(0); + fuji_gotoy(oldy); + + do { + fuji_putchar(' '); + } while(--tlen); + + fuji_gotox(0); + fuji_gotoy(oldy); +} + +#endif + +#if defined(FEAT_CURSOR_CONTROLS) || defined(FEAT_COL80_HACK) +//void redraw_user_buffer() { +// int tlen; +//# ifdef FEAT_LOW_RAM_BUFFERS +//# define redraw_buf ((char *) 0x2800) +//# else +// static char redraw_buf[BUF_SIZE]; +//# endif +// /* reprint user edit buffer */ +// if(input_buf_len) { +// tlen = input_buf_len - 1; +// do { +// redraw_buf[tlen] = input_buf[tlen] | 0x80; +// } while(tlen--); +// redraw_buf[input_buf_len] = '\0'; +// fputs(redraw_buf, stdout); +// fflush(stdout); +// } +//} + +void redraw_user_buffer() { + int i; + if(input_buf_len) { + for(i=0; i EOL + c = A_EOL; + buf_done = 1; + } else if(c == TAB) { // tab + c = A_TAB; +#ifndef FEAT_COL80_HACK + /* COL80 can actually print these OK */ + } else if(c == '{') { + c = '[' | 0x80; + } else if(c == '}') { + c = ']' | 0x80; + } else if(c == '~') { + c = '^' | 0x80; + } else if(c == 0x60) { // backtick + c = 0xa7; // inverse quote +#endif + } + + output_buf[output_buf_len++] = c; + if(output_buf_len >= OUTBUF_SIZE) { + puts("[buffer overflow]\xfd"); + buf_done = 1; + break; + } + + if(buf_done) { +#if defined(FEAT_CURSOR_CONTROLS) || defined(FEAT_COL80_HACK) + del_user_buffer(); +#endif + output_buf[output_buf_len] = '\0'; + + if(output_buf_len > 4 && (memcmp(output_buf, "PING", 4) == 0)) { + do_pong(); + } else if(output_buf[0] == ':') { + do_msg(); + } else { + fputs(output_buf, stdout); + fflush(stdout); + } + +#if defined(FEAT_CURSOR_CONTROLS) || defined(FEAT_COL80_HACK) + redraw_user_buffer(); +#endif + +#ifdef FEAT_COL80_HACK + // col80_cursor(); +#endif + output_buf_len = 0; + buf_done = 0; + } + } +} + + +/*---------------------------------------------------------------------------*/ + +/* uIP app callback for the resolver */ +void resolv_found(char *name, u16_t *ipaddr) { + if(ipaddr == NULL) { + printf("Host '%s' not found.\n", name); + done = 1; + } else { + printf("%s is %s\n", name, format_ip((uip_ipaddr_t *)ipaddr)); + /* + printf("Found name '%s' = %d.%d.%d.%d\n", name, + htons(ipaddr[0]) >> 8, + htons(ipaddr[0]) & 0xff, + htons(ipaddr[1]) >> 8, + htons(ipaddr[1]) & 0xff); + */ + if(!connected) + (void)uip_connect((uip_ipaddr_t *)ipaddr, htons(config->server_port)); + } +} + +#ifdef FEAT_LOGGING + +/* 0x100 * 32 = 8K (but we likely won't get that much) */ +#define LOG_PAGE_SIZE 0x200 +#define LOG_MAX_PAGES 16 +#define LOG_SCROLL_PAGES 2 + +static char *log_buffer = NULL; +static char *log_buf_end = NULL; +static char *log_buf_current = NULL; +static int log_pages = LOG_MAX_PAGES; + +static char last_log_nick[NICKLEN + 1]; + +static void alloc_log_buffer() { + do { + printf("Trying to malloc(%x)...", LOG_PAGE_SIZE * log_pages); + + log_buffer = malloc(LOG_PAGE_SIZE * log_pages); + + if(log_buffer) { + puts("OK"); + } else { + puts("Failed"); + } + } while(!log_buffer && (--log_pages > LOG_SCROLL_PAGES * 2)); + + if(!log_buffer) return; + + log_buf_end = (char *)(log_pages * LOG_PAGE_SIZE - 1); + log_buf_current = log_buffer; + + printf("log_buffer == %x (%x)", log_buffer, log_pages * LOG_PAGE_SIZE); + fuji_cgetc(); +} + +static void log_msg(char *msg) { + int len = strlen(msg); + if( (log_buf_current + len + 1) > log_buf_end ) { + memmove(log_buffer, log_buffer + (LOG_SCROLL_PAGES * LOG_PAGE_SIZE), (log_pages - LOG_SCROLL_PAGES) * LOG_PAGE_SIZE); + log_buf_current -= (LOG_SCROLL_PAGES * LOG_PAGE_SIZE); + } +} + +#endif diff --git a/src/fujichat.cfg b/src/fujichat.cfg new file mode 100644 index 0000000..974f49e Binary files /dev/null and b/src/fujichat.cfg differ diff --git a/src/fujichat.h b/src/fujichat.h new file mode 100644 index 0000000..6b899ea --- /dev/null +++ b/src/fujichat.h @@ -0,0 +1,136 @@ +#ifndef FUJICHAT_H +#define FUJICHAT_H + +#include "uip.h" +#include "aexec.h" + +/* Program name (plain ASCII for network use) */ +#define SELF "FujiChat" +/* inverse video version, used for local prompts: */ +#define SELF_INV "\xc6\xf5\xea\xe9\xc3\xe8\xe1\xf4" + +#define VERSION "0.5_pre4" +#define BANNER SELF_INV " v" VERSION +#define VERSION_REPLY SELF " v" VERSION + +#define DEFAULT_NICK SELF + +// #define CONF_SIGNATURE "\x03\x0e" +#define CONF_SIGNATURE_LO 0x03 +#define CONF_SIGNATURE_HI 0x0e +#define CONF_VERSION 5 + +#define BUF_SIZE 256 +#define OUTBUF_SIZE 512 +#define NICKLEN 20 +#define HOSTLEN 64 + +/* fuji_conf_t is stored in the config file verbatim. + Don't forget to update CONF_VERSION when changing this struct! + Also, the first member should never, ever change, and the 2nd + (version) should only ever be set to CONF_VERSION (which can be + changed) + + */ +typedef struct { + char signature[2]; + u16_t version; + + /* uIP settings: */ + uip_ipaddr_t local_ip; + uip_ipaddr_t peer_ip; + uip_ipaddr_t resolver_ip; + char baud; + + /* IRC settings: */ + char server[HOSTLEN+1]; + u16_t server_port; + char nick[NICKLEN+1]; + char alt_nick[NICKLEN+1]; + char real_name[NICKLEN+1]; + char channel[NICKLEN+1]; + + /* UI settings: */ + char bg_color; + char fg_color; + u16_t ui_flags; /* bitwise OR of UIFLAG_* constants */ + + /* Other stuff: */ + char timezone; /* for later, when we use /TIME to set the clock */ +} fuji_conf_t; + +/* Chunk of RAM that holds our config data. Setup leaves the config + here for FujiChat to find. */ +#define CONFIG_ADDRESS 0x500 + +#define ARGTYPE_NONE 0 +#define ARGTYPE_REQUIRED 1 +#define ARGTYPE_OPT 2 + +typedef struct { + char *cmd; /* e.g. "ME" or "PING" */ + char arg_type; /* one of ARGTYPE_* constants */ + void (*handler)(void); +} fuji_cmd_t; + +extern fuji_cmd_t cmd_list[]; +extern char *serv_msg_buf; +extern int serv_msg_buf_len; +extern char *cmd_arg; +extern char channel[]; +extern struct telnet_state *tstate; +extern char joined_channel; +extern char *input_buf; + +void send_serv_msg_buf(void); +void send_server_cmd(char *cmd, char *arg); +void handle_command(void); +void bell(); + +/* Filenames */ +#define DEFAULT_CONF_FILE "D:FUJICHAT.CFG" +#define MENU_FILENAME "D:FUJIMENU.COM" +#define SETUP_FILENAME "D:FUJICONF.COM" +#define IRC_FILENAME "D:FUJICHAT.COM" +// #define IRC_LOADER_FILENAME "D:LOADCHAT.COM" +#define SERIAL_DRIVER_FILENAME "D:DEFAULT.SER" +#define DEFAULT_SERIAL_DRIVER "D:BOBVERT.SER" + +/* Whether or not to ring the bell on receiving private message */ +#define UIFLAG_MSGBELL 0x8000 + +/* Whether or not to show [PING,PONG] */ +#define UIFLAG_SHOWPING 0x4000 + +/* Visual bell (screen flash) instead of audible */ +#define UIFLAG_VBELL 0x2000 + +/* Hide (don't display) the server MOTD */ +#define UIFLAG_HIDEMOTD 0x1000 + +/* Disable bells entirely */ +#define UIFLAG_NOBELL 0x0800 + +/* Auto-away when ATRACT mode kicks in */ +#define UIFLAG_ATRACT_AWAY 0x400 + + +/* ATASCII characters */ +#define A_EOL 0x9b +#define A_TAB 0x7f +#define A_BS 0x7e +#define A_CLR 0x7d +#define A_BEL 0xfd +#define A_DEL 0x9c + +/* plain ASCII characters */ +#define NL 0x0a +#define CR 0x0d +#define TAB 0x09 + +/* cc65's rs232.h doesn't define this for Atari: */ +#ifndef RS_BAUD_19200 +#define RS_BAUD_19200 0x0f +#endif + +#endif diff --git a/src/fujiconf.c b/src/fujiconf.c new file mode 100644 index 0000000..f77f2a9 --- /dev/null +++ b/src/fujiconf.c @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include +#include +#include "uip.h" +#include "uiplib.h" +#include "fujichat.h" +#include "common.h" + +/* TODO: move these to an external file or otherwise come up with a way + to reuse the memory */ +#define SERVER_LIST_LEN (sizeof(servers) / sizeof(servers[0])) +static char *servers[][2] = { + /* + { "82.165.139.95", "irc.tobug.net (US)" }, + { "63.243.153.235", "irc.carterroadband.com (US)" }, + { "209.133.9.109", "ircd.eyearesee.org (US)" }, + { "89.238.135.210", "london.eyearesee.org (EU)" }, + { "193.23.141.104", "hungary.eyearesee.org (EU)" }, + */ + { "na.newnet.net", "NewNet (North America)" }, + { "eu.newnet.net", "NewNet (Europe)" }, + { "us.undernet.org", "Undernet (US)" }, + { "eu.undernet.org", "Undernet (Europe)" }, + { "irc.freenode.org", "FreeNode" }, + { "kubrick.freenode.net", "FreeNode (US)" }, + { "irc.efnet.org", "Eris Free Net" }, + { "82.165.139.95", "irc.tobug.net (NewNet, US)" }, +}; + +// char rs232_already_loaded = 0; + +int baud_values[] = { 1200, 2400, 4800, 9600, 19200 }; +char baud_bytes[] = { RS_BAUD_1200, RS_BAUD_2400, RS_BAUD_4800, RS_BAUD_9600, RS_BAUD_19200 }; +char max_baud = sizeof(baud_bytes); + +static void get_conf_color(char *name, char *color, char dflt); +static char get_yesno(char *prompt, char dflt); +void save_config(void); + +static void bell() { + putchar(A_BEL); +} + +static void get_baudrate(void) { + char i, buf[5]; + + putchar('\n'); + for(i=0; ibaud == baud_bytes[i]) + printf("[%d] %d\n", i+1, baud_values[i]); + else + printf(" %d. %d\n", i+1, baud_values[i]); + + fputs("\nBaud rate: ", stdout); + fflush(stdout); + + do { + get_line(buf, 4); + if(!*buf) + return; + + i = atoi(buf); + } while (i < 1 || i > max_baud); + config->baud = baud_bytes[--i]; +} + +static void get_ip_addr(char *prompt, char *dflt, uip_ipaddr_t *addr) { + char ok; + char buf[HOSTLEN+1]; + + do { + printf("%s IP address [%s]: ", prompt, dflt); + fflush(stdout); + get_line(buf, HOSTLEN); + if(!*buf) strcpy(buf, dflt); + ok = uiplib_ipaddrconv(buf, (unsigned char*)addr); + if(!ok) bell(); + } while(!ok); +} + +#if 0 +char scan_hatabs(char dev) { + int entry; + + /* 0x031A is HATABS from OS equates */ + for(entry = 0x031A; entry < 0x033F; entry += 3) + if(PEEK(entry) == dev) return 1; + + return 0; +} + +int copy_file(char *dst, char *src) { + // THIS FUNCTION IS BROKEN! + static char buf[256]; + int i; + FILE *from, *to; + + if( !(from = fopen(src, "rb")) ) { + perror(src); + i = errno; + goto done; + } + + if( !(to = fopen(dst, "wb")) ) { + perror(dst); + i = errno; + goto done; + } + + while( (i = fread(buf, 1, 256, from)) ) + fwrite(buf, 1, i, to); + + if(feof(from)) + i = 0; + else + i = errno; + +done: + if(from) fclose(from); + if(to) fclose(to); + return i; +} +#endif + +static void config_menu(void) { + char i, buf[HOSTLEN+1], ok = 0; + unsigned int new_value; + + // strcpy(config->signature, CONF_SIGNATURE); + ((char *)config->signature)[0] = CONF_SIGNATURE_LO; + ((char *)config->signature)[1] = CONF_SIGNATURE_HI; + config->version = CONF_VERSION; + + if(!config_is_valid()) + set_default_config(); + + do { + puts("\n==> Serial Port Settings\n"); + + if(get_yesno("Change RS232 driver", 0)) { + atari_exec("D:MAKEAUTO.COM"); + } + + get_baudrate(); + + /* TODO: choose which Rn: device to use (e.g. on the 850), + turn HW flow control on/off (buried in cc65 rs232 lib code) */ + + puts("\n==> Network Settings\n"); + get_ip_addr("Local", format_ip(&(config->local_ip)), &(config->local_ip)); + get_ip_addr("Peer", format_ip(&(config->peer_ip)), &(config->peer_ip)); + get_ip_addr("DNS Server", format_ip(&(config->resolver_ip)), &(config->resolver_ip)); + + puts("\n==> IRC Settings\n"); + puts("Server list:"); + for(i=0; iserver); + fflush(stdout); + fgets(buf, HOSTLEN, stdin); + + if(*buf != '\n') { + if(buf[0] >= '1' && buf[0] <= (SERVER_LIST_LEN + '0') && buf[1] == '\n') { + strcpy(buf, servers[buf[0] - '1'][0]); + } + + for(i=0; buf[i] && (buf[i] != '\n'); ++i) + ; + + buf[i] = '\0'; + strcpy(config->server, buf); + } + + printf("Server port [%d]: ", config->server_port); + get_line(buf, 10); + new_value = atoi(buf); + if(new_value) config->server_port = new_value; + + printf("Your nickname [%s]: ", config->nick); + get_line(buf, NICKLEN); + if(*buf) strcpy(config->nick, buf); + + printf("Your 'real' name [%s]: ", config->real_name); + get_line(buf, NICKLEN); + if(*buf) strcpy(config->real_name, buf); + + do { + printf("Autojoin channel (or 0 for none)\n[%s]: ", config->channel); + get_line(buf, NICKLEN); + + switch(*buf) { + case '\0': + ok = 1; + break; + + case '#': + case '&': + strcpy(config->channel, buf); + ok = 1; + break; + + case '0': + *(config->channel) = '\0'; + ok = 1; + break; + + default: + // user-friendly: + *(config->channel) = '#'; + strcpy((config->channel) + 1, buf); + ok = 1; + break; + + // user-hostile: + /* + puts("IRC channel names must begin with # or &"); + bell(); + ok = 0; + */ + } + + /* TODO: scan for illegal chars, set ok=0 */ + } while(!ok); + + + puts("\n==> User Interface Settings\n"); + do { + get_conf_color("Background", &(config->bg_color), config->bg_color); + get_conf_color("Foreground", &(config->fg_color), config->fg_color); + ok = ((config->bg_color & 0x0e) != (config->fg_color & 0x0e)); + if(!ok) + puts("These colors would make your text\n" + "impossible to see. Try again.\n"); + } while(!ok); + + new_value = + (get_yesno("Disable bell", config->ui_flags & UIFLAG_NOBELL) ? UIFLAG_NOBELL : 0); + + if(!(new_value & UIFLAG_NOBELL)) { + new_value |= + (get_yesno("Visual bell", config->ui_flags & UIFLAG_VBELL) ? UIFLAG_VBELL : 0); + + new_value |= + (get_yesno("Bell on msg", config->ui_flags & UIFLAG_MSGBELL) ? UIFLAG_MSGBELL : 0); + }; + + new_value |= + (get_yesno("Show ping/pong", config->ui_flags & UIFLAG_SHOWPING) ? UIFLAG_SHOWPING : 0); + + new_value |= + (get_yesno("Hide MOTD", config->ui_flags & UIFLAG_HIDEMOTD) ? UIFLAG_HIDEMOTD : 0); + + config->ui_flags = new_value; + + puts("\n==> Config complete\n"); + ok = get_yesno("Is this correct", 1); + } while(!ok); + + if(get_yesno("Save this config", 1)) + save_config(); + + putchar('\n'); +} + +void save_config(void) { + FILE *f = fopen(DEFAULT_CONF_FILE, "wb"); + if(f) { + fwrite(config, sizeof(fuji_conf_t), 1, f); + fclose(f); + puts("Config saved to " DEFAULT_CONF_FILE); + } +} + +static void get_conf_color(char *name, char *color, char dflt) { + char buf[5]; + + printf("%s color [%d]: ", name, dflt); + fgets(buf, 5, stdin); + + if(!(*buf >= '0' && *buf <= '9')) + *color = dflt; + else + *color = atoi(buf); +} + +static char get_yesno(char *prompt, char dflt) { + char buf[5]; + + printf("%s [%c/%c]: ", + prompt, + (dflt ? 'Y' : 'y'), + (dflt ? 'n' : 'N')); + + fflush(stdout); + get_line(buf, 4); + switch(*buf) { + case 'y': + case 'Y': + return 1; + + case 'n': + case 'N': + return 0; + + default: + return dflt; + } +} + +void reboot(void) { + asm("jmp $e477"); +} + +void main(void) { + char *next_file, buf[2]; + int ret; + + disable_break(); + + putchar(125); + puts(BANNER " Setup\n"); + get_config(); + + if(!config_is_valid()) + set_default_config(); + + config_menu(); + + /* + if(rs232_already_loaded) { + puts("\nAn RS232 driver is already resident.\n" + "You must reboot to use the new driver.\n"); + if(get_yesno("Reboot now", 1)) + reboot(); + } + */ + + if(get_yesno("Start FujiChat now", 1)) { + // next_file = IRC_LOADER_FILENAME; + next_file = IRC_FILENAME; + } else { + next_file = MENU_FILENAME; + } + + printf("\nLoading %s...\n", next_file); + ret = atari_exec(next_file); + + printf("Error %d!\n\xfd", ret); + puts("Press Enter to exit to DOS"); + get_line(buf, 2); +} diff --git a/src/fujimenu.c b/src/fujimenu.c new file mode 100644 index 0000000..29c9d7d --- /dev/null +++ b/src/fujimenu.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include "fujichat.h" +#include "common.h" + +/* TODO: + - rewrite in asm +*/ + +void run_prog(char *file) { + int c; + printf("\nLoading %s...\n", file); + c = atari_exec(file); + printf("Error %d!\n\xfd", c); +} + +void main(void) { + int c, have_conf; + + disable_break(); + + puts("\x7d" BANNER " Main Menu\n"); + + have_conf = get_config(); + if(!have_conf) + set_default_config(); + + while(1) { + printf("\n %cbout\n", 'A' | 0x80); + + printf("%s%cetup\n", + (have_conf ? " " : "* "), + 'S' | 0x80); + + printf("%s%chat\n", + (have_conf ? "* " : " "), + 'C' | 0x80); + + printf(" %cOS\n", 'D' | 0x80); + + putchar('\n'); + putchar('>'); + + cursor(1); + c = cgetc(); + if(c == A_EOL || c == ' ') + c = (have_conf ? 'C' : 'S'); + + putchar(c | 0x80); + + switch(c) { + case 'A': + case 'a': + run_prog("D:ABOUT.COM"); + break; + + case 'S': + case 's': + run_prog(SETUP_FILENAME); + break; + + case 'C': + case 'c': + run_prog(IRC_FILENAME); + // run_prog(IRC_LOADER_FILENAME); + break; + + /* + if(config_is_valid()) { + // atari_exec(IRC_LOADER_FILENAME); + atari_exec(IRC_FILENAME); + return 0; + } else { + putchar(A_BS); + puts("\nYou must run Setup first"); + break; + } + */ + + case 'D': + case 'd': + return; + + default: + putchar(A_BS); + break; + } + } +} diff --git a/src/fujiput.s b/src/fujiput.s new file mode 100644 index 0000000..21a4969 --- /dev/null +++ b/src/fujiput.s @@ -0,0 +1,21 @@ + .fopt compiler,"cc65 v 2.12.9" + .setcpu "6502" + .smart on + .autoimport on + .case on + .debuginfo off + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .export _fuji_putchar + +.segment "CODE" +_fuji_putchar: + tax + ;lda $E407 ; don't use ROM, might be running COL80 + lda $0347 ; grab from IOCB 0 instead + pha + ;lda $E406 + lda $0346 + pha + txa + rts diff --git a/src/fujitest.atr b/src/fujitest.atr new file mode 100644 index 0000000..7157856 Binary files /dev/null and b/src/fujitest.atr differ diff --git a/src/getsmess.c b/src/getsmess.c new file mode 100644 index 0000000..1a8494b --- /dev/null +++ b/src/getsmess.c @@ -0,0 +1,66 @@ +#include +#include + + +void getlnasm(char *buf, char len) { + asm("ldy #$00"); + asm("lda (sp),y"); + asm("sta $e2"); + + asm("ldy #$02"); + asm("jsr ldaxysp"); + asm("sta $e0"); + asm("stx $e0+1"); + + asm("@loop: lda _stdin"); + asm("ldx _stdin+1"); + asm("jsr _fgetc"); + + asm("cmp #$9B"); + asm("beq @out"); + + asm("ldy #$00"); + asm("sta ($e0),y"); + asm("inc $e0"); + asm("bne @noinc"); + asm("inc $e0+1"); + asm("@noinc:"); + + asm("dec $e2"); + asm("bne @loop"); + + asm("@out:"); + asm("ldy #$00"); + asm("tya"); + asm("sta ($e0),y"); +} + +void getln(char *buf, char len) { + char *p = buf; + + do { + *p = fgetc(stdin); + if(*p == '\n') break; + } while(++p, --len); + *p = '\0'; +} + +void main(void) { + char buf[100] = "HELLO"; + while(1) { + /* + puts("gets"); + gets(buf); + puts(buf); + puts("fgets"); + fgets(buf, 99, stdin); + puts(buf); + puts("getln"); + getln(buf, 99); + puts(buf); + */ + puts("getlnasm"); + getlnasm(buf, 99); + puts(buf); + } +} diff --git a/src/hex2inc.pl b/src/hex2inc.pl new file mode 100644 index 0000000..047438d --- /dev/null +++ b/src/hex2inc.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl -w + +$|++; + +while(<>) { + chomp; + my ($c, $data) = split /:/; + $c = hex($c); + next unless $c >= 32 && $c <= 127; + + my @data = ($data =~ /(..)/g); + die "invalid data" unless @data == 6; + my $last = pop @data; + die "bottom row not blank: $last" if $last ne "00"; + + $glyphs[$c] = \@data; +} + +$idx = 0; +for(my $c = 32; $c < 128; $c += 2) { + print " byte "; + $bits = ""; + for(my $byte = 0; $byte < 5; ++$byte) { + printf '$%02X', hex($glyphs[$c][$byte]) | (hex($glyphs[$c+1][$byte]) >> 4); + print ", " unless $byte == 4; + $bits .= sprintf "%08b\n", hex($glyphs[$c][$byte]) | (hex($glyphs[$c+1][$byte]) >> 4); + } + print " ; [$idx] $c," . ($c+1) . " " . chr($c) . "," . chr($c+1) . "\n"; +# print STDERR $bits; + $idx += 5; +} diff --git a/src/irc_notes b/src/irc_notes new file mode 100644 index 0000000..11006f0 --- /dev/null +++ b/src/irc_notes @@ -0,0 +1,95 @@ +connect to server, wait a second... NICK $nick +USER dammit dammit irc.newnet.net :dammit +JOIN #channel +PRIVMSG #channel Hello world! + +At any time, if you get a PING $whatever, respond with PONG $whatever + +For now just dump everything to stdout, raw. Later we can be nice and format +stuff like a real IRC client would... + +Need a custom DL, 24 lines of GR.0, set up correctly for the OS to print +and scroll, etc, then one blank scanline and one more line of GR.0. Whatever +the user types on the bottom line there gets displayed but not sent to +the server until the user presses Return. If joined to a channel, there +should be a prompt with the channel name, and any text typed should get +sent as PRIVMSG #$channel $text. If no channel, don't send to server. +Whether on a channel or not, user can use /commands. Minimal set we +want to support: + +/nick $newnick +/join #$channel +/part +/quit <$quitmsg> +/msg $user $text +/whois + +For now, only one channel can be joined. PRIVMSG's from other users, and +server messages, etc, will be displayed mixed with channel text. + +Actually, the DL should maybe have an additional GR.0 status line at +the top. This will be 26 lines... or we can have the 2nd line have a LMS +pointing 40 bytes past the "real" location of the OS's screen RAM, meaning +the OS will print & scroll the top line, but it won't actually be displayed. +Eventually the whole thing has to be done with a custom screen handler, +for performance reasons. + +/nick $nick + +Send "NICK $nick" to server + +If you send NICK $nick and get back a 433, that's "nick already in use", +pick a different nick & try again. The USER command won't succeed until +the initial NICK is established (nor will any JOINs, etc) + +/join $channel + +Send "JOIN $channel" to server. The user has to type the # (which might +be some other character for some kinds of channels). Only one channel is +supported for now. + +/part - send "PART $channel" to server ($channel is from the previous +/join command) + +/quit <$quitmsg> + +With a message, send "QUIT :$quitmsg", otherwise just send "QUIT" + +/msg $user $test - send "PRIVMSG $user :$text" (should also allow /m) + +/whois $nick - send "WHOIS $nick" + +For normal channel text, send "PRIVMSG $channel :$text" + +Incoming text, need to translate EOLs and tabs... and strip color codes, +handle ^AACTION, translate or ignore other unprintables in ATASCII, +particularly { } ~ chars. Nicks need everything after the ! removed. +A PRIVMSG to the current channel also needs everything up to and +including "PRIVMSG $channel :" removed. + +The biggest problem right now: the code assumes each line of text from +the IRC server (terminated with \n) will arrive in its own packet. This +is often the case, but not always. What needs to happen is that there +should be an output line buffer. The buffer starts empty, and as packets +come in, they should be scanned for \n's and put into the buffer... when +we hit a \n char, print (or format/parse) the output buffer, clear it, +and start scanning again. If we hit end-of-packet, don't do anything with +the buffer. Next packet, we'll start appending to the old buffer until we +hit \n again. This will allow us to respond to PING requests even when +they get split across packets. The buffer will probably be 1K in size, +we need to handle overflow conditions in a sane way (maybe just pretend +we got a \n and print/clear the buffer). + +actions: + +Send: +PRIVMSG #chan :^AACTION does an action^A + +Receive: +:nick PRIVMSG #chan ^AACTION does an action^A + +pings: + +Receive: + +:nick PRIVMSG nick ^APING ^A diff --git a/src/keybuf.h b/src/keybuf.h new file mode 100644 index 0000000..1430ef4 --- /dev/null +++ b/src/keybuf.h @@ -0,0 +1,26 @@ + +/* Dead simple keyboard buffer mechanism + + Call keybuf_init() at startup + + During busy loops, periodically call keybuf_poll_kbd(), + which will buffer keystrokes as they're pressed. + + When ready to read the keyboard, call keybuf_cgetc() + Return value is 0 for no key pressed and no keys in buffer, + or else the ASCII code of the next key. + + Also, can call keybuf_is_empty() to find out whether the + buffer's got anything in it. + + It would be possible to have the OS periodically call + keybuf_poll_kbd() for us, using one of the countdown timers. + For now, not going to do this, as it adds complexity and + fujichat only has 2 or 3 places that count as busy + loops. + */ + +void __fastcall__ keybuf_init(void); +void __fastcall__ keybuf_poll_kbd(void); +char __fastcall__ keybuf_is_empty(void); +char __fastcall__ keybuf_cgetc(void); diff --git a/src/keybuf.s b/src/keybuf.s new file mode 100644 index 0000000..cf24e77 --- /dev/null +++ b/src/keybuf.s @@ -0,0 +1,94 @@ + .fopt compiler,"cc65 v 2.12.9" + .setcpu "6502" + .smart on + .autoimport on + .case on + .debuginfo off + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .export _keybuf_init, _keybuf_poll_kbd, _keybuf_cgetc + +NO_KEY = $FF +max_buf_len = 12 ; aka buffer size + +BUFFER_BASE = $F0 + +keybuf_head = BUFFER_BASE +keybuf_tail = BUFFER_BASE+1 +keybuf = BUFFER_BASE+2 +keybuf_end = keybuf + max_buf_len + +CH = $02FC + + .segment "CODE" + +; void __fastcall__ keybuf_init(void) +_keybuf_init: + lda #keybuf + sta keybuf_head + sta keybuf_tail + rts + +; void __fastcall__ keybuf_poll_kbd(void) +_keybuf_poll_kbd: + lda CH + cmp #NO_KEY + beq kbpoll_done + + ; got a key, see if room in buffer + ldx keybuf_tail + cpx #keybuf_end+1 + bcs kbpoll_done + + ; buffer not full, so store key in buffer + sta 0,x + inc keybuf_tail + + ; clear keyboard register + lda #NO_KEY + sta CH + +kbpoll_done: + rts + + +; char __fastcall__ keybuf_is_empty(void) +_keybuf_is_empty: + ldx #0 + sec + lda keybuf_tail + sbc keybuf_head + rts + + +; char __fastcall__ keybuf_cgetc(void) + +; Note: 0 means "no key pressed", which means we +; can't return character code 0 (not a big deal). +; If this is a problem, we could change the return +; type to int, and return -1 instead. + +_keybuf_cgetc: + ldx keybuf_head + cpx keybuf_tail + beq check_ch + + ; got a key, stuff it in CH + lda 0,x + sta CH + inc keybuf_head + +call_cgetc: + ; ...and return the ASCII code + jmp _fuji_cgetc + +check_ch: + jsr _keybuf_init + + ldx CH + cpx #NO_KEY + bne call_cgetc + + inx ; was $FF, now 0 + txa ; aka return(0) + rts + diff --git a/src/keybuftest.c b/src/keybuftest.c new file mode 100644 index 0000000..4ea7f12 --- /dev/null +++ b/src/keybuftest.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "keybuf.h" + +#define RTCLOK 0x14 + +void read_input(void) { + char got[20]; + char c, *p = got; + + while( (c = keybuf_cgetc()) ) + putchar(c); + + // *p++ = c; + + /* + *p = '\0'; + + if(p != got) + fputs(got, stdout); + */ +} + +void process(void) { + POKE(RTCLOK, 0); + while(PEEK(RTCLOK) < 30) { + keybuf_poll_kbd(); + } +} + +void idle(void) { + char c; + POKE(RTCLOK, 0); + while(PEEK(RTCLOK) < 30) { + if( (c = keybuf_cgetc()) ) + putchar(c); + } +} + +void main(void) { + cursor(1); + keybuf_init(); + + while(1) { + process(); + read_input(); + idle(); + } +} diff --git a/src/loadchat.dasm b/src/loadchat.dasm new file mode 100644 index 0000000..c63ed41 --- /dev/null +++ b/src/loadchat.dasm @@ -0,0 +1,54 @@ + +; If no R: driver is loaded, load DEFAULT.SER +; Then, load FujiChat + +; This is needed because e.g. Bob-verter loads at $5000, smack in the +; middle of FujiChat's code. This tiny little loader program should be +; small enough and out-of-the-way enough that nothing will stomp on it. + + processor 6502 + include "equates.inc" + +atari_exec = $0600 +main = $2E00 ; same place as cc65 + +; segment header + org main-6 + word $FFFF + word main + word endmain-1 + + org main + +; search handler table for R entry + ldx #0 +tabloop: + lda HATABS,x + cmp #'R + beq load_chat + inx + inx + inx + cpx #$24 ; 12 entries * 3 bytes = 36 + bne tabloop + +; no R: driver found, load one + lda #driver_filename + jsr atari_exec + +; load main fujichat program (does not return) +; (in fact it better not return, it overwrites this program!) +load_chat: + lda #chat_filename + jmp atari_exec + +driver_filename .byte "D:DEFAULT.SER", 0 +chat_filename .byte "D:FUJICHAT.COM", 0 +endmain + +; segment header + word RUNAD + word RUNAD+1 + word main diff --git a/src/loadmenu.dasm b/src/loadmenu.dasm new file mode 100644 index 0000000..71cbdfc --- /dev/null +++ b/src/loadmenu.dasm @@ -0,0 +1,69 @@ + +; Load MENU.COM + +; This will be part of AUTORUN.SYS on the disk. Without it, +; I'd have to make AUTORUN.SYS a copy of MENU.COM :( + + processor 6502 + include "equates.inc" + +atari_exec = $0600 +main = $2E00 ; same place as cc65 + +; segment header + org main-6 + word $FFFF + word main + word endmain-1 + + org main + +; do this so pressing Reset give us DOS +; ldx #1 +; stx BOOTQ +; dex +; stx COLDST + +; remove later: see if FujiChat can work with only 44K +;; lda #$B0 +;; sta RAMTOP +;; lda #12 ; CIO CLOSE +;; sta ICCOM +;; ldx #0 +;; jsr CIOV +;; +;; +;; lda #3 ; Command 3=OPEN +;; sta ICCOM +;; lda #12 ; 12=R/W access +;; sta ICAX1 +;; lda #0 +;; sta ICAX2 +;; lda #e_dev +;; sta ICBAH +;; lda #e_dev_len +;; sta ICBLL +;; lda #0 +;; tax +;; sta ICBLH +;; jsr CIOV ; call CIO + + +; our raison d'etre... + lda #menu_filename + jmp atari_exec + +menu_filename .byte "D:FUJIMENU.COM", 0 + +e_dev byte "E:",0 +e_dev_len equ *-e_dev+1 + +endmain + +; segment header + word RUNAD + word RUNAD+1 + word main diff --git a/src/loadmkau.dasm b/src/loadmkau.dasm new file mode 100644 index 0000000..613be44 --- /dev/null +++ b/src/loadmkau.dasm @@ -0,0 +1,69 @@ + +; Load MENU.COM + +; This will be part of AUTORUN.SYS on the disk. Without it, +; I'd have to make AUTORUN.SYS a copy of MENU.COM :( + + processor 6502 + include "equates.inc" + +atari_exec = $0600 +main = $2E00 ; same place as cc65 + +; segment header + org main-6 + word $FFFF + word main + word endmain-1 + + org main + +; do this so pressing Reset give us DOS +; ldx #1 +; stx BOOTQ +; dex +; stx COLDST + +; remove later: see if FujiChat can work with only 44K +;; lda #$B0 +;; sta RAMTOP +;; lda #12 ; CIO CLOSE +;; sta ICCOM +;; ldx #0 +;; jsr CIOV +;; +;; +;; lda #3 ; Command 3=OPEN +;; sta ICCOM +;; lda #12 ; 12=R/W access +;; sta ICAX1 +;; lda #0 +;; sta ICAX2 +;; lda #e_dev +;; sta ICBAH +;; lda #e_dev_len +;; sta ICBLL +;; lda #0 +;; tax +;; sta ICBLH +;; jsr CIOV ; call CIO + + +; our raison d'etre... + lda #menu_filename + jmp atari_exec + +menu_filename .byte "D:MAKEAUTO.COM", 0 + +e_dev byte "E:",0 +e_dev_len equ *-e_dev+1 + +endmain + +; segment header + word RUNAD + word RUNAD+1 + word main diff --git a/src/loadtest.c b/src/loadtest.c new file mode 100644 index 0000000..cf56627 --- /dev/null +++ b/src/loadtest.c @@ -0,0 +1,12 @@ +#include + +void __fastcall__ (*atari_exec_p)(char *) = (void __fastcall__ (*)(char *))0x600; +#define atari_exec(x) ((*atari_exec_p)(x)) + +int main(int, char **) { + puts("Loading D:RVERT.COM"); + atari_exec("D:RVERT.COM"); + puts("Loading D:FUJICHAT.RAW"); + atari_exec("D:FUJICHAT.RAW"); + puts("Should never get here!"); +} diff --git a/src/logcomptest.pl b/src/logcomptest.pl new file mode 100644 index 0000000..6285f93 --- /dev/null +++ b/src/logcomptest.pl @@ -0,0 +1,229 @@ +#!/usr/bin/perl -w + +# sample session for IRC log compression scheme + +$lastnick = ""; +$textlen = 0; +while() { + $lines++; + $bigtot += length($_); + chomp; + + my ($nick, $text) = split " ", $_, 2; + for($nick, $text) { + s/(.)$/chr(ord($1)|0x80)/e; + } + + if(($nick ne $lastnick) || ($textlen + length($text) > 256)) { + $output .= $nick; + $output .= $text; + $lastnick = $nick; + $textlen = length($text); + } else { + $output .= chr(1) . $text; + $textlen += length($text); + } +} + +print "lines: $lines\n"; +print "old: $bigtot\n"; +print "new: " . length($output) . "\n"; +print "saved: " . ($bigtot - length($output)) . "\n"; +print "compression: " . (1.0 - (length($output) / $bigtot)) . "\n"; + +print STDERR $output; + +__DATA__ +Slor WIDE? +Slor dunno +Redbeard I've seen a 29w7 though. +SteveS who you calling WIDE? +DogWombl i'm not wide, i'm just badly out of proportion +Redbeard Was labeled "video" on the back of a Intergraph machine, back when they had their own unix running on a custom cpu. +Slor where'd urch go, anyway? +Slor ask a question and disappear +SteveS he said he had real work +SteveS be back late, late +BeetlePC hey SteveSI have two 10base2 NICs but I don't need transceivers and I definitely don't want any of those fat ass transceiver cables. +SteveS beetle, how is the 1080 coming? +SteveS bah. I'm going through BSG withdrawal! +Redbeard Transcievers would allow you to put a 10base5 nic onto the same coax network. Or sometimes rackmount switches have a (is it db15?) connector on them. +Slor someone tell me this too - what is a "Modem Eliminator"? Is that just fancy for null modem? +SteveS group shrug +BeetlePC i didn't work on it lately +SteveS grrr. I still can't figure why my MyIDE movie audio player is not playing nice. +SteveS I will order parts for SDrive this week. I will. I will. I will. +Redbeard q +SteveS been saying that for a while now +BeetlePC good, good, good +BeetlePC :) +Slor doesn't buy it +SteveS $7 seems too much for a SD connector though. I might try the floppy cable connector hack on the first try. +BeetlePC you can also cannibalize a dead/cheap SD card reader +SteveS don't have one +ChrisTOS nn +BeetlePC night +SteveS nite +SteveS christos +ChrisTOS q +Slor didn't even see him talk today +SteveS I need to get a working one though +atarixle q +SteveS I didn't know atarixle was here +SteveS Would ask him if there is an English version of the new Boss X. +BeetlePC he told you +SteveS people need better names, btw. XL Boss, Boss XL, and Boss X. +BeetlePC 10.4 will be available in german and english +SteveS oh! +SteveS I missed the answer. +SteveS I thought he ignored me +BeetlePC i remembered it :) +SteveS my mistake. sorry. +BeetlePC np +BeetlePC gets himself a beer +BeetlePC cheers +SteveS has no beer in the house and is not going out in 19 degree weather to get some. +SteveS cheers +SteveS holds up his empty tea mug +BeetlePC :) +BeetlePC *pling* +BeetlePC i scored an IBM thinkpad T42 on ebay today +BeetlePC its for my dad +SteveS Zum Wohl to dad +BeetlePC 1.6 GHz Pentium M, 1 Gig of RAM and a new 160GB HD, plus a new IBM battery (used laptop batterys are most often dead) +BeetlePC should do for his mobile computing needs +SteveS :) +BeetlePC He is some 'car accident expert' i don't know how that job is called in english. He views damaged cars and estimates the cost of repairs. He also reconstructs what happend during the crash. +BeetlePC How the crash happend +BeetlePC happened +SteveS Adjuster? +SteveS Insurance Adjuster, is what we call them. +BeetlePC hmm +BeetlePC he does not work for an insurance +SteveS oh +BeetlePC one-man-company +BeetlePC he is the boss of himself :) +BeetlePC and also the best boy +SteveS I don't think we have a single equivalent for that job. +BeetlePC Kfz-Sachverständiger +BeetlePC lets see what google says +BeetlePC car expert :-/ +SteveS oops when I cut and pasted into babel fish I got my Atari font +SteveS Kfz-Sachverständiger +SteveS looks Ok here +SteveS Atari Extrasmooth +BeetlePC well, he looks at the damaged car, writes down every harmed component and calculates the time to repair it. +SteveS in babel fish +BeetlePC and for this job, a laptop would be nice +SteveS estimates are performed by a representative of your insurance company here. +BeetlePC thats common here, too +SteveS also called Claims Adjuster +BeetlePC but the job has not to be done by someone from the insurance +BeetlePC you are allowed to choose here +SteveS some insurance companines allow you to call to a service shop or even several service shops. +BeetlePC and a 'independend claims adjuster' might get a larger payment form the insurance of your opponent than his insurances representant +BeetlePC from -from +BeetlePC because he doesn't get payed for keeping costs small for the insurance +SteveS Some insurance companies won't even pay for original parts +BeetlePC because of that, if your car gets damaged by someone, you are allowed to choose who will examine you car +rrCurtisP j +SteveS My friend bought a Mini Cooper +SteveS a new one +BeetlePC wow, nice +SteveS I think he is a having a mid-life crisis. Normally a very conservative person. +SteveS I always wanted a Porshe 356 +BeetlePC well, if a car he likes helps - better than leaviing wife and kids as a neighour here does +SteveS ouch +BeetlePC fuse blown - i have no other explanation +SteveS 20 yr-old GF maybe +BeetlePC no - or he does hide it well +BeetlePC :) +charliec j +charliec good evening all +BeetlePC hey charliec +charliec Hiya Beetle +Harlock q +SteveS hey charliec +charliec Hi Steve +SteveS charliie, did I remember to send you MyDOS 3.19? +charliec Nope +SteveS It has the RS232 driver for ATR8000 +charliec didnt know if you caught that.. +SteveS sorry +charliec dont be +SteveS dcc in just a second +charliec hold.. im on fuji +SteveS oh +SteveS that won't work +SteveS not yet +charliec not yet huh +cc_PC j +cc_PC okee +cc_PC ready when you are +Harlock j +cc_PC Thanks! +SteveS welcome +SteveS you will be asked to build a version of DOS. It does it in memory the you must select 'H', Save DOS files. +cc_PC Ok +charliec ever run CP/M on the ATR Steve? +Moloch j +charliec well heading to a surprise b-day party, cant be late for those! +charliec nute +charliec heh.. nite +charliec q +cc_PC q +BeetlePC good night +BeetlePC q +fres j +fres hey, all. +fres and by all I mean, uh... who? +Slor yo +SteveS oops. I fell asleep +Slor heh +SteveS hi fres +SteveS Hot cocoa! BRB... +fres fellas... +Harlock q +Harlock j +SteveS _FujIRC time to backup MyIDE +SteveS _FujIRC q +SteveS damn, it's quiet in here +DogWombl it seems to be quiet in irc channels everywhere +Harlock everyone but us out on friday night +Moloch q +SteveS _FujIRC j +SteveS _FujIRC back +SteveS wb +rrCurtisP q +Woodzy q +DocRotCod j +SteveS _FujIRC q +Velcro_MM q +Velcro_MM j +fres nope +SteveS yup yup yup +SteveS nothing to see here +SteveS Anyone have to travel for Thanksgiving? +SteveS Not me. +DocRotCod q +Urchlay Redb3ard and JellE are driving to Indiana +SteveS oh, is Red from there? +Urchlay think he's from Virginia, but got family there +Redb3ard Grew up in Indiana, only place I'd ever been until I was 18. +Urchlay my grandma (like 88 this year) was going to come up this year +Redb3ard I just happened to be in Virginia, when we started talking. +Urchlay ah +Urchlay grandma can't drive for 4 hours straight (er, way she drives it'd take 8 anyway) +Urchlay the other day my aunt who was gonna do the driving, fell & broke her hip +Urchlay so no aunt, no grandma, no cool cousin +Urchlay (well, maybe cool cousin, she lives in Riverdale IIRC) +SteveS ouch. well, I wish your aunt a fast recovery. +Urchlay the doc says she's doing great +Urchlay I really don't think of her as *old* but she's in her 60s now I guess +Urchlay (if I ask, she'll say she's still 59 I'm sure) +Urchlay wish I had the car, I'd drive down there +Urchlay go see her in the hospital, bring a fake can of peanuts with a snake in it +Urchlay (a fake one!) +Urchlay eh, sorry, the snake thing is like a 20-year running gag I guess +SteveS um +SteveS ok diff --git a/src/logtest.c b/src/logtest.c new file mode 100644 index 0000000..4a22cb4 --- /dev/null +++ b/src/logtest.c @@ -0,0 +1,53 @@ +#include +#include +#include + +/* 0x100 * 32 = 8K (but we likely won't get that much) */ +#define LOG_PAGE_SIZE 0x20 +#define LOG_MAX_PAGES 16 +#define LOG_SCROLL_PAGES 2 + +static char *log_buffer = NULL; +static char *log_buf_end = NULL; +static char *log_buf_current = NULL; +static int log_pages = LOG_MAX_PAGES; + +// static char last_log_nick[NICKLEN + 1]; + +static void alloc_log_buffer() { + log_buffer = malloc(LOG_PAGE_SIZE * log_pages); + log_buf_end = (char *)(log_buffer + log_pages * LOG_PAGE_SIZE - 1); + log_buf_end[1] = 0xaa; + log_buf_current = log_buffer; +} + +static void log_msg(char *msg) { + int len = strlen(msg); + if( (log_buf_current + len + 1) > log_buf_end ) { + memmove(log_buffer, log_buffer + (LOG_SCROLL_PAGES * LOG_PAGE_SIZE), (log_pages - LOG_SCROLL_PAGES) * LOG_PAGE_SIZE); + log_buf_current -= (LOG_SCROLL_PAGES * LOG_PAGE_SIZE); + } + + memcpy(log_buf_current, msg, len); + log_buf_current += (len + 1); + *log_buf_current = '\0'; +} + +static void dump_log_stats(void) { + printf("start: %x, end: %x, cur: %x\n", log_buffer, log_buf_end, log_buf_current); +} + +void main(void) { + char buf[100]; + int i; + + alloc_log_buffer(); + dump_log_stats(); + + for(i=0; i<24; i++) { + sprintf(buf, ":--------------------Iteration #%d\n", i); + log_msg(buf); + dump_log_stats(); + } +HANG: goto HANG; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..2e5ee17 --- /dev/null +++ b/src/main.c @@ -0,0 +1,1184 @@ +/* + * Copyright (c) 2008, Brian Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgements: + * This product includes software developed by Adam Dunkels. + * This product includes software developed by Brian Watson. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the FujiChat IRC client. + * + */ + + +#include +#include +#include +#include "uip.h" +#include "uiplib.h" +#include "rs232dev.h" +#include +#include +#include +#include +#include + +#include "timer.h" + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/* Program name (plain ASCII for network use) */ +#define SELF "FujiChat" +/* inverse video version, used for local prompts: */ +#define SELF_INV "\xc6\xf5\xea\xe9\xc3\xe8\xe1\xf4" + +#define VERSION "0.3.1" +#define BANNER SELF_INV " v" VERSION +#define VERSION_REPLY SELF " v" VERSION + + +#define DEFAULT_NICK SELF + +#define CONF_SIGNATURE "\x03\x0e" +#define CONF_VERSION 4 +#define DEFAULT_CONF_FILE "FUJICHAT.CFG" + +/* TODO: move the non-IRC-related config to a separate SETUP program, + and a separate UIP.CFG file. This will be shared by all apps that + use uIP, such as the planned telnet and FTP clients. Also it means + we don't have to bloat each program with a complete config UI + for things like the local/peer/DNS IP addresses. + + In fact the SETUP utility might resolve IP addresses for us, so + each app might not need its own copy of the resolver... though + that's maybe a bit clumsy to use for FTP, since you generally want + to easily be able to connect to arbitrary servers (unlike, say, IRC + where you usually use the same server all the time). Perhaps SETUP + could resolve arbitrary hostnames, then write them to a /etc/hosts + type of file. Parsing /etc/hosts entries is fairly lightweight, + could be done in all the client programs... + + ...or maybe what should happen is that there should be a RESOLV + program that can resolve hostnames, and read/write them in text + form to a HOSTS.TXT file... and also parses the HOSTS file and + stores the hostname strings and 4-byte IP addresses in a fixed + area of memory. The app programs could just look up hostnames in + this memory area, without having to open & parse HOSTS themselves. + cc65 programs by default start at $2E00. The Bob-verter driver ends + around $2200 (other R: drivers should be comparable), which gives + us around 3K of unallocated memory. Assuming the average hostname/IP + pair is 50 bytes, that'd give us about 60 of them. The RESOLV program + would stop the user from adding more hostnames when there's no space + for them (and let them delete some to make room, maybe commenting them + out so they remain in the HOSTS file for future uncommenting). + + Ultimately there should be a master AUTORUN.SYS file with a menu + that runs the other sub-apps (or lets you exit to DUP). Menu would + have options like "DNS", "IRC", "FTP", "Telnet", and "Network + Setup". Of course I need to write a program loader, there's no + exec* functions in cc65! The Network Setup option would let you + specify the R: driver you want to load, so it wouldn't have to + be prepended to any of the executables, and would be auto-loaded + the first time you try to run any of the apps that need it. It'd + be nice if the main menu program had at least a few DOS functions + as well (delete/copy/rename/lock/unlock, format too?) + + Probably, FujiChat's 1.0 release will be as a standalone IRC client, + with the current config UI stuff as-is. The other stuff would be + released months from now, under the label "FujiNet" or something, and + include a new version of FujiChat as one of several apps. + + The final distibution disk will need at least some documentation in + Atari-readable text format, plus a doc-reader program. + + All the subprograms need to end with RTS to the menu program, which + shold be small and stay resident in addresses not touched by cc65 + (I've got 128 bytes each in the cassette buffer and page 5, also + 256 more in page 6. Should be easy to squeeze into 512 bytes, no?) + + So a disk directory would contain: + + DOS.SYS, DUP.SYS + AUTORUN.SYS - the main menu and subprogram loader + BOBVERT.XEX - the Bob-verter R: driver + A850.XEX - the 850 R: driver (from DOS 2.0S I guess) + MIO.XEX, BLACKBOX.XEX, etc, drivers for other serial ports + HOSTS.TXT - the /etc/hosts file, human-readable and -editable + README.TXT - docs + MORE.XEX - doc reader (should handle ASCII or ATASCII EOLs) + SETUP.XEX - set up global network settings (local/remote/dns IPs, also + things like screen colors, key-repeat rate, etc). + DNS.XEX - lookup hostnames, maintain and parse HOSTS.TXT + FTP.XEX, TELNET.XEX, IRC.XEX, PING.XEX - the apps + FTP.CFG, TELNET.CFG, IRC.CFG, etc - app-specific settings + FUJINET.CFG - global settings + ...if there's room on the disk, a small text editor might be nice + to include. + + The whole thing should be distributed as a bootable, single-density + DOS disk (undecided which DOS, either 2.0S or MyDOS 4.5). + + Alternatively, all the XEX files might be named COM, and the whole + thing could run under a CLI DOS like Sparta (if it'll actually + run). The apps could take optional CLI arguments, also... and the + AUTORUN.SYS would actually be unnecessary! + + */ + +#define BUF_SIZE 256 +#define OUTBUF_SIZE 768 +#define NICKLEN 20 +#define HOSTLEN 64 + +/* fuji_conf_t is stored in the config file verbatim. + Don't forget to update CONF_VERSION when changing this struct! + Also, the first member should never, ever change, and the 2nd + (version) should only ever be set to CONF_VERSION (which can be + changed) + + TODO: + char alt_nick[NICKLEN+1]; + */ +typedef struct { + char signature[2]; + u16_t version; + + /* uIP settings: */ + uip_ipaddr_t local_ip; + uip_ipaddr_t peer_ip; + uip_ipaddr_t resolver_ip; + char baud; + + /* IRC settings: */ + char server[HOSTLEN+1]; + u16_t server_port; + char nick[NICKLEN+1]; + char real_name[NICKLEN+1]; + char channel[NICKLEN+1]; + + /* UI settings: */ + char bg_color; + char fg_color; + u16_t ui_flags; /* bitwise OR of UIFLAG_* constants */ +} fuji_conf_t; + +fuji_conf_t config; + +/* Whether or not to ring the bell on receiving private message */ +#define UIFLAG_MSGBELL 0x8000 + +/* Whether or not to show [PING,PONG] */ +#define UIFLAG_SHOWPING 0x4000 + +/* Visual bell (screen flash) instead of audible */ +#define UIFLAG_VBELL 0x2000 + +/* Hide (don't display) the server MOTD */ +/* TODO: implement */ +#define UIFLAG_HIDEMOTD 0x1000 + +/* Disable bells entirely */ +#define UIFLAG_NOBELL 0x0800 + +char os_version[10] = "XL_XE"; +char channel[BUF_SIZE]; +char input_buf[BUF_SIZE]; +char chan_msg_buf[BUF_SIZE * 2]; +char output_buf[OUTBUF_SIZE + 1]; +char last_msg_nick[NICKLEN+1] = ""; + +int input_buf_len = 0; +int output_buf_len = 0; + +char config_valid = 0; +char done = 0; +char connected = 0; +char joined_channel = 0; /* true if we're in a channel */ +char nick_registered = 0; +char vbell_active = 0; + +static void get_line(char *buf, unsigned char len); +static void handle_keystroke(void); +static void handle_command(void); +static void get_config(void); +static void config_menu(void); +static void send_server_cmd(char *cmd, char *arg); +static void bell(); +void redraw_user_buffer(); + +/* ATASCII characters */ +#define A_EOL 0x9b +#define A_TAB 0x7f +#define A_BS 0x7e +#define A_CLR 0x7d +#define A_BEL 0xfd +#define A_DEL 0x9c + +/* plain ASCII characters */ +#define NL 0x0a +#define CR 0x0d +#define TAB 0x09 + +/* TODO: move these to an external file or otherwise come up with a way + to reuse the memory */ +#define SERVER_LIST_LEN 8 +static char *servers[][2] = { + /* + { "82.165.139.95", "irc.tobug.net (US)" }, + { "63.243.153.235", "irc.carterroadband.com (US)" }, + { "209.133.9.109", "ircd.eyearesee.org (US)" }, + { "89.238.135.210", "london.eyearesee.org (EU)" }, + { "193.23.141.104", "hungary.eyearesee.org (EU)" }, + */ + { "na.newnet.net", "NewNet (North America)" }, + { "eu.newnet.net", "NewNet (Europe)" }, + { "us.undernet.org", "Undernet (US)" }, + { "eu.undernet.org", "Undernet (Europe)" }, + { "irc.freenode.org", "FreeNode" }, + { "kubrick.freenode.net", "FreeNode (US)" }, + { "irc.efnet.org", "Eris Free Net" }, + { "82.165.139.95", "irc.tobug.net (NewNet, US)" }, +}; + +/* uIP API stuff */ +struct timer nick_reg_timer; /* ../uip/timer.h */ +struct timer vbell_timer; +struct telnet_state *tstate; /* ../apps/telnet.h */ + +/*---------------------------------------------------------------------------*/ +int main(void) { + char c; + int i; + uip_ipaddr_t ipaddr; + struct timer periodic_timer; + char cmdbuf[HOSTLEN+1]; + + c = get_ostype() & AT_OS_TYPE_MAIN; + if(c == AT_OS_400800) { + strcpy(os_version, "800"); + } else if(c == AT_OS_1200XL) { + strcpy(os_version, "1200XL"); + } + + cursor(1); /* don't let conio hide the cursor */ + + /* set screen colors to white-on-black initially. They may be + reset by the user's config file, once it's loaded */ + POKE(710, 0); + POKE(709, 12); + + putchar(A_CLR); + puts(BANNER); + putchar('\n'); + + get_config(); + + while(1) { + done = 0; + rs232dev_close(); + + POKE(710, config.bg_color); + POKE(709, config.fg_color); + + printf("Server name/IP, [C]onfig, or e[X]it\n"); + printf("[%s]: ", config.server); + fflush(stdout); + get_line(cmdbuf, HOSTLEN); + + if(strcasecmp(cmdbuf, "x") == 0) { + exit(0); + } else if(strcasecmp(cmdbuf, "c") == 0) { + config_menu(); + continue; + } else if(*cmdbuf) { + strcpy(config.server, cmdbuf); + } + /* else, use the existing config.server */ + + timer_set(&periodic_timer, CLOCK_SECOND / 2); + + rs232dev_init(config.baud); + uip_init(); + + uip_sethostaddr(config.local_ip); + uip_setdraddr(config.peer_ip); + + /* can I use 255.255.255.252 here? Does it matter? */ + uip_ipaddr(ipaddr, 255,255,255,0); + uip_setnetmask(ipaddr); + + if(uiplib_ipaddrconv(config.server, (unsigned char*)&ipaddr)) { + (void)uip_connect(&ipaddr, htons(config.server_port)); + } else { + resolv_init(); + resolv_conf(config.resolver_ip); + resolv_query(config.server); + } + + while(!done) { + /* This part of the while loop is straight from the no-ARP example + code, from the uIP docs. */ + uip_len = rs232dev_poll(); + if(uip_len > 0) { + uip_input(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } else if(timer_expired(&periodic_timer)) { + timer_reset(&periodic_timer); + for(i = 0; i < UIP_CONNS; i++) { + uip_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } + +#if UIP_UDP + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + rs232dev_send(); + } + } +#endif /* UIP_UDP */ + } + + if(vbell_active && timer_expired(&vbell_timer)) { + POKE(710, config.bg_color); + vbell_active = 0; + } + + /* Call the keyboard handler if the user pressed a key. Note that + we're using stdio for printing, but conio for reading, which + works on the Atari but may not work on all other cc65 platforms */ + if(kbhit()) { + handle_keystroke(); + } + + /* Automatically register the nick and userhost after being + connected for a couple seconds. The parameters for the USER + command are ignored by the server (at least the NewNet servers) */ + if(connected && !nick_registered && timer_expired(&nick_reg_timer)) { + puts("Registering nick"); + sprintf(input_buf, "NICK %s%cUSER %s %s %s :%s%c", + config.nick, NL, config.nick, SELF, + config.server, config.real_name, NL); + telnet_send(tstate, input_buf, strlen(input_buf)); + input_buf_len = 0; + nick_registered = 1; + /* TODO: check for failure registering the nick */ + } + + /* + if(PEEK(53279) == 6) { // START pressed + puts("Disconnecting"); + uip_close(); + // done = 1; + } + */ + } + + connected = nick_registered = joined_channel = 0; + } + return 0; +} + +static void bell() { + if(config.ui_flags & UIFLAG_NOBELL) + return; + + if(config.ui_flags & UIFLAG_VBELL) { + vbell_active = 1; + timer_set(&vbell_timer, CLOCK_SECOND / 10); + POKE(710, config.bg_color + 8); + } else { + putchar(A_BEL); + } +} + +/* The err_* functions will probably support "visual bell" (screen flashing) + as an option one day. */ +static void err_missing_arg(void) { + puts("Command requires argument"); + bell(); +} + +static void err_no_channel(void) { + puts("You are not in a channel (use /join #channel)"); + bell(); +} + +static void err_already_joined(void) { + puts("You are already in a channel (use /part to leave)"); + bell(); +} + +static void del_last_word(void) { + int old = input_buf_len, bs = 0; + + while(input_buf_len && input_buf[input_buf_len] == ' ') { + ++bs; + input_buf_len--; + } + + while(input_buf_len && input_buf[input_buf_len] != ' ') { + ++bs; + input_buf_len--; + } + + if(old > 120 && input_buf_len <= 120) { + putchar(0x1c); + putchar(A_DEL); + putchar(A_DEL); + redraw_user_buffer(); + } else do { + putchar(A_BS); + } while(--bs); +} + +/* Keyboard handler. For now, the keyboard macros are hard-coded. */ +static void handle_keystroke(void) { + char i, c, send_buf = 0; + + /* TODO: + ctrl-7 = ` (warning: cgetc() can't read this) + ctrl-, = { + ctrl-. = } + ctrl-; = ~ (don't do ctrl-^, that's left-arrow!) + + Ignore inverse-video key, ATASCII graphics, unwanted + cursor actions, make caps-lock stop freezing the program. + To do this right, we have to examine location 764 for some + of these, and don't call cgetc() at all... or actually, + stuff a valid keycode there, then call cgetc() to make a + keyclick noise (but ignore its return value) + + Make Break act like delete-line + + */ + c = cgetc(); + + /* Keyboard macros, only allowed at the start of a new line */ + if(input_buf_len == 0) { + switch(c) { + case 0x0e: /* ctrl-N */ + if(joined_channel) send_server_cmd("NAMES", channel); + return; + + case 0x17: /* ctrl-W */ + if(joined_channel) send_server_cmd("WHO", channel); + return; + + case A_EOL: + return; /* ignore Return on a line by itself */ + + case A_TAB: + if(last_msg_nick[0]) { + sprintf(input_buf, "/msg %s ", last_msg_nick); + input_buf_len = strlen(input_buf); + for(i=0; i 0) { + input_buf_len--; + putchar(c); + } else { + bell(); + } + + return; + } else if(c == A_DEL || c == 0x15) { + /* shift-backspace or ^U (delete line) */ + input_buf_len = 0; + putchar(A_DEL); + return; + } else if(c == 0x17) { + /* ^W (delete word) */ + del_last_word(); + return; + } + + /* Echo keystroke */ + putchar(c | 0x80); /* inverse video for now */ + + if(c == A_EOL) { + c = NL; + send_buf = 1; + } else if(c == A_TAB) { + c = TAB; + } + + /* Store keystroke in input buffer */ + input_buf[input_buf_len++] = c; + + /* If line too long, ring the "margin" bell */ + if(input_buf_len > BUF_SIZE - 1) + if(!send_buf) { + bell(); + putchar(A_BS); + input_buf_len--; + } + + /* If we've got a complete line of input and user has pressed Return, + send it to the server */ + if(send_buf) { + input_buf[input_buf_len] = '\0'; + + if(*input_buf == '/') { + handle_command(); + } else if(joined_channel) { + sprintf(chan_msg_buf, "PRIVMSG %s :%s", channel, input_buf); + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); + } else { + err_no_channel(); + } + + input_buf_len = 0; + } +} + +static void send_server_cmd(char *cmd, char *arg) { + if(arg) { + sprintf(chan_msg_buf, "%s %s%c", cmd, arg, NL); + } else { + sprintf(chan_msg_buf, "%s%c", cmd, NL); + } + + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); +} + +static void send_ctcp_version(char *arg) { + sprintf(chan_msg_buf, "PRIVMSG %s %cVERSION%c%c", + arg, 1, 1, NL); + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); +} + +static void send_ctcp_ping(char *arg) { + sprintf(chan_msg_buf, "PRIVMSG %s %cPING %c%c", + arg, 1, 1, NL); + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); +} + +static void do_me(char *arg) { /* Do me, baby! */ + sprintf(chan_msg_buf, "PRIVMSG %s :%cACTION %s%c%c", + channel, 1, arg, 1, NL); + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); +} + +static void handle_command(void) { + char *cmd = input_buf + 1, *cend; + char *arg = NULL, *p = cmd; + + /* convert command word to uppercase */ + while((*p != NL) && (*p != ' ')) { + *p = toupper(*p); + ++p; + } + + cend = p; + + /* set arg pointer, nul-terminate arg, if present */ + /* (otherwise, arg remains NULL) */ + if(*p != NL) { + arg = p; + /* skip extra whitespace */ + while(*arg == ' ') + ++arg; + p = arg + 1; + while(*p && (*p != NL)) + ++p; + *p = '\0'; + } + + /* nul-terminate cmd */ + *cend = '\0'; + + /* See if it's a command that needs client-side help */ + if(strcmp(cmd, "ME") == 0) { + if(!joined_channel) + err_no_channel(); + else if(!arg) + err_missing_arg(); + else + do_me(arg); + } else if(strcmp(cmd, "MSG") == 0 || strcmp(cmd, "M") == 0) { + if(!arg) + err_missing_arg(); + else + send_server_cmd("PRIVMSG", arg); + } else if(strcmp(cmd, "JOIN") == 0 || strcmp(cmd, "J") == 0) { + if(joined_channel) { + err_already_joined(); + } else { + joined_channel = 1; + strcpy(channel, arg); + send_server_cmd("JOIN", arg); + } + } else if(strcmp(cmd, "PART") == 0) { + if(!joined_channel) { + err_no_channel(); + } else { + joined_channel = 0; + send_server_cmd("PART", channel); + } + } else if(strcmp(cmd, "VERSION") == 0 || strcmp(cmd, "VER") == 0) { + if(!arg) + err_missing_arg(); + else + send_ctcp_version(arg); + } else if(strcmp(cmd, "PING") == 0) { + if(!arg) + err_missing_arg(); + else + send_ctcp_ping(arg); + } else if(strcmp(cmd, "QUOTE") == 0) { + if(!arg) + err_missing_arg(); + else + send_server_cmd(arg, NULL); + } else { + /* Anything we don't recognize as a client command, we pass + directly to the server. */ + send_server_cmd(cmd, arg); + } +} + +/* The telnet_* functions are uIP application callbacks. */ +void telnet_connected(struct telnet_state *s) { + /* puts("Connected to host, press START to disconnect"); */ + puts("Connected to server"); + tstate = s; + s->text = NULL; + s->textlen = 0; + timer_set(&nick_reg_timer, CLOCK_SECOND); + connected = 1; +} + +void telnet_closed(struct telnet_state *s) { + puts("Connection closed"); + uip_close(); + done = 1; +} + +void telnet_sent(struct telnet_state *s) { +} + +void telnet_aborted(struct telnet_state *s) { + puts("Connection aborted"); + uip_abort(); + done = 1; +} + +void telnet_timedout(struct telnet_state *s) { + puts("Connection timed out"); + uip_abort(); + done = 1; +} + +void do_pong() { + char *p = chan_msg_buf; + + memcpy(chan_msg_buf, output_buf, output_buf_len); + chan_msg_buf[1] = 'O'; + while(*p) { + if(*p == A_EOL) *p = NL; + p++; + } + + telnet_send(tstate, chan_msg_buf, output_buf_len); + if(config.ui_flags & UIFLAG_SHOWPING) + puts("[PING,PONG]"); +} + +/* Handler for text received from the server, responsible for + formatting. TODO: part/join/quit aren't handled correctly. */ +void do_msg() { + char *nick = output_buf, *cmd = output_buf, *chan = NULL, *msg = NULL; + char *bang = NULL; + + while(*cmd != ' ') { + if(*cmd == '!') { + bang = cmd; + } + ++cmd; + } + + /* no ! in nick means a server message or something, just print as-is */ + if(!bang) { + fputs(output_buf, stdout); + fflush(stdout); + return; + } + + *cmd = '\0'; + ++cmd; + chan = cmd; + + while(*chan != ' ') + ++chan; + *chan = '\0'; + ++chan; + msg = chan; + + if(*msg != A_EOL) { + while(*msg && *msg != ' ') + ++msg; + if(*msg) { + *msg = '\0'; + ++msg; + if(*msg == ':') ++msg; + } + } + + /* FIXME: This stuff is hairy, unmaintainable, and probably just wrong + (works OK with the 2 or 3 NewNet servers I test with, not tried + others). It's the result of too much coffee, and needs to be + redesigned. Heck, it needs to be designed in the first place! */ + if(strcmp(cmd, "PRIVMSG") == 0) { + nick[0] = '<'; + bang[0] = '>'; + bang[1] = '\0'; + if(strcasecmp(chan, config.nick) != 0) { + // privmsg, not to our nick, must be channel text + if(memcmp(msg, "\x01" "ACTION ", 8) == 0) { + nick++; + *bang = '\0'; + output_buf[output_buf_len - 2] = A_EOL; + output_buf[output_buf_len - 1] = '\0'; + printf("* %s %s", nick, msg + 8); + } else { + printf("%s %s", nick, msg); + } + } else { + // privmsg, is to our nick + if(memcmp(msg, "\x01" "PING ", 6) == 0) { + nick++; + *bang = '\0'; + output_buf[output_buf_len - 2] = '\0'; + sprintf(chan_msg_buf, "NOTICE %s :\x01PING %s\x01%c", + nick, msg + 6, 0x0a); + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); + printf("* CTCP PING from %s\n", nick); + } else if(memcmp(msg, "\x01" "VERSION\x01", 9) == 0) { + nick++; + *bang = '\0'; + sprintf(chan_msg_buf, "NOTICE %s :\x01VERSION " + VERSION_REPLY " - running on " + "an Atari %s\x01%c", + nick, os_version, 0x0a); + telnet_send(tstate, chan_msg_buf, strlen(chan_msg_buf)); + printf("* CTCP VERSION from %s\n", nick); + } else { + printf("MSG: %s %s", nick, msg); + if(config.ui_flags & UIFLAG_MSGBELL) + bell(); + *bang = '\0'; + strcpy(last_msg_nick, nick + 1); + } + } + } else { + if(*msg) { + printf("%s %s %s %s", nick, cmd, chan, msg); + } else { + printf("%s %s %s", nick, cmd, chan); + } + } + + fflush(stdout); +} + +void del_user_buffer() { + /* delete user edit buffer */ + if(input_buf_len) { + putchar(A_DEL); + if(input_buf_len > 119) { + putchar(0x1c); /* up arrow */ + putchar(A_DEL); + } + } +} + +void redraw_user_buffer() { + int tlen; + static char redraw_buf[BUF_SIZE]; + /* reprint user edit buffer */ + if(input_buf_len) { + tlen = input_buf_len - 1; + do { + redraw_buf[tlen] = input_buf[tlen] | 0x80; + } while(tlen--); + redraw_buf[input_buf_len] = '\0'; + fputs(redraw_buf, stdout); + fflush(stdout); + } +} + +/* Another uIP app callback. This decides whether or not we've received + a complete message from the server (which may be split into multiple + packets, and may end in the middle of a packet) */ +void telnet_newdata(struct telnet_state *s, char *data, u16_t len) { + u16_t tlen = len; + char c, *t = data, buf_done = 0; + + while(tlen-- != 0) { + c = *t++; + if(c == NL) { // swallow NL + continue; + } else if(c == CR) { // CR => EOL + c = A_EOL; + buf_done = 1; + } else if(c == TAB) { // tab + c = A_TAB; + } else if(c == '{') { + c = '[' | 0x80; + } else if(c == '}') { + c = ']' | 0x80; + } else if(c == '~') { + c = '^' | 0x80; + } else if(c == 0x60) { // backtick + c = 0xa7; // inverse quote + } + + output_buf[output_buf_len++] = c; + if(output_buf_len >= OUTBUF_SIZE - 1) { + puts("[buffer overflow]\xfd"); + buf_done = 1; + break; + } + + if(buf_done) { + del_user_buffer(); + output_buf[output_buf_len] = '\0'; + + if(output_buf_len > 4 && (memcmp(output_buf, "PING", 4) == 0)) { + do_pong(); + } else if(output_buf[0] == ':') { + do_msg(); + } else { + fputs(output_buf, stdout); + fflush(stdout); + } + + redraw_user_buffer(); + output_buf_len = 0; + buf_done = 0; + } + } +} + +/* Load config file, offer the user a chance to change the config */ +static void get_config(void) { + // char filename[20]; + FILE *f = fopen(DEFAULT_CONF_FILE, "rb"); + + puts("Loading config from " DEFAULT_CONF_FILE); + + if(f) { + config_valid = + fread(&config, 1, sizeof(fuji_conf_t), f) == sizeof(fuji_conf_t); + fclose(f); + if(!config_valid) + puts("Config file is wrong size"); + } else { + puts("No config file found"); + } + + if(config_valid) { + if(memcmp(config.signature, CONF_SIGNATURE, 2) != 0) { + puts("Not a valid config file"); + config_valid = 0; + } else if(config.version != CONF_VERSION) { + puts("Config is for the wrong version of FujiChat, ignoring"); + config_valid = 0; + } else { + puts("Loaded OK"); + /* + printf("Loaded OK. Use defaults [Y/n]? "); + fflush(stdout); + fgets(input_buf, 10, stdin); + if(*input_buf == 'N' || *input_buf == 'n') + config_menu(); + */ + } + } + + if(!config_valid) + config_menu(); +} + +static void save_config(void) { + FILE *f = fopen(DEFAULT_CONF_FILE, "wb"); + if(f) { + fwrite(&config, sizeof(fuji_conf_t), 1, f); + fclose(f); + puts("Config saved to " DEFAULT_CONF_FILE); + } +} + +static void get_conf_color(char *name, char *color, char dflt) { + char buf[5]; + + printf("%s color [%d]: ", name, dflt); + fgets(buf, 5, stdin); + + if(!(*buf >= '0' && *buf <= '9')) + *color = dflt; + else + *color = atoi(buf); +} + +static void get_line(char *buf, unsigned char len) { + fgets(buf, len, stdin); + while(*buf) { + if(*buf == '\n') + *buf = '\0'; + ++buf; + } +} + +static char get_yesno(char *prompt, char dflt) { + char buf[5]; + + printf("%s [%c/%c]: ", + prompt, + (dflt ? 'Y' : 'y'), + (dflt ? 'n' : 'N')); + + fflush(stdout); + get_line(buf, 4); + switch(*buf) { + case 'y': + case 'Y': + return 1; + + case 'n': + case 'N': + return 0; + + default: + return dflt; + } +} + +static void get_ip_addr(char *prompt, char *dflt, uip_ipaddr_t *addr) { + char ok; + char buf[HOSTLEN+1]; + + do { + printf("%s IP address [%s]: ", prompt, dflt); + fflush(stdout); + get_line(buf, HOSTLEN); + if(!*buf) strcpy(buf, dflt); + ok = uiplib_ipaddrconv(buf, (unsigned char*)addr); + if(!ok) bell(); + } while(!ok); +} + +static char *format_ip(uip_ipaddr_t *ip) { + static char buf[20]; + u16_t *ipaddr = (u16_t *)ip; + sprintf(buf, "%d.%d.%d.%d", + htons(ipaddr[0]) >> 8, + htons(ipaddr[0]) & 0xff, + htons(ipaddr[1]) >> 8, + htons(ipaddr[1]) & 0xff); + return buf; +} + +void set_default_config(void) { + uip_ipaddr(&(config.local_ip), 192,168,0,2); + uip_ipaddr(&(config.peer_ip), 192,168,0,1); + uip_ipaddr(&(config.resolver_ip), 192,168,0,1); + strcpy(config.server, servers[0][0]); + strcpy(config.nick, DEFAULT_NICK); + strcpy(config.real_name, "FujiChat User"); + config.server_port = 6667; + config.ui_flags = 0; + config.bg_color = 0xc0; /* dark green */ + config.fg_color = 0x0c; + config.baud = RS_BAUD_4800; + + config_valid = 1; +} + +int baud_values[] = { 1200, 2400, 4800, 9600 }; +char baud_bytes[] = { RS_BAUD_1200, RS_BAUD_2400, RS_BAUD_4800, RS_BAUD_9600 }; +char max_baud = sizeof(baud_bytes); + +static void get_baudrate(void) { + char i, buf[5]; + + for(i=0; i max_baud); + config.baud = baud_bytes[--i]; +} + +static void config_menu(void) { + char i, buf[HOSTLEN+1], ok = 0; + unsigned int new_value; + + strcpy(config.signature, CONF_SIGNATURE); + config.version = CONF_VERSION; + + if(!config_valid) + set_default_config(); + + do { + get_baudrate(); + get_ip_addr("Local", format_ip(&(config.local_ip)), &(config.local_ip)); + get_ip_addr("Peer", format_ip(&(config.peer_ip)), &(config.peer_ip)); + get_ip_addr("DNS Server", format_ip(&(config.resolver_ip)), &(config.resolver_ip)); + + puts("Server list:"); + for(i=0; i= '1' && buf[0] <= (SERVER_LIST_LEN + '0') && buf[1] == '\n') { + strcpy(buf, servers[buf[0] - '1'][0]); + } + + for(i=0; buf[i] && (buf[i] != '\n'); ++i) + ; + + buf[i] = '\0'; + strcpy(config.server, buf); + + printf("Server port [%d]: ", config.server_port); + get_line(buf, 10); + new_value = atoi(buf); + if(new_value) config.server_port = new_value; + + printf("Your nickname [%s]: ", config.nick); + get_line(buf, NICKLEN); + if(*buf) strcpy(config.nick, buf); + + printf("Your 'real' name [%s]: ", config.real_name); + get_line(buf, NICKLEN); + if(*buf) strcpy(config.real_name, buf); + + // if(!*(config.nick)) strcpy(config.nick, DEFAULT_NICK); + /* TODO: scan for invalid chars */ + + get_conf_color("Background", &(config.bg_color), config.bg_color); + get_conf_color("Foreground", &(config.fg_color), config.fg_color); + + new_value = + (get_yesno("Disable bell", config.ui_flags & UIFLAG_NOBELL) ? UIFLAG_NOBELL : 0); + + if(!(config.ui_flags & UIFLAG_NOBELL)) { + new_value |= + (get_yesno("Visual bell", config.ui_flags & UIFLAG_VBELL) ? UIFLAG_VBELL : 0); + + new_value |= + (get_yesno("Bell on msg", config.ui_flags & UIFLAG_MSGBELL) ? UIFLAG_MSGBELL : 0); + }; + + new_value |= + (get_yesno("Show ping/pong", config.ui_flags & UIFLAG_SHOWPING) ? UIFLAG_SHOWPING : 0); + + config.ui_flags = new_value; + + ok = get_yesno("Is this correct", 1); + } while(!ok); + + if(get_yesno("Save this config", 1)) + save_config(); +} + +/*---------------------------------------------------------------------------*/ + +/* uIP app callback for the resolver */ +void resolv_found(char *name, u16_t *ipaddr) { + if(ipaddr == NULL) { + printf("Host '%s' not found.\n", name); + done = 1; + } else { + printf("Found name '%s' = %d.%d.%d.%d\n", name, + htons(ipaddr[0]) >> 8, + htons(ipaddr[0]) & 0xff, + htons(ipaddr[1]) >> 8, + htons(ipaddr[1]) & 0xff); + if(!connected) + (void)uip_connect((uip_ipaddr_t *)ipaddr, htons(config.server_port)); + } +} diff --git a/src/makeauto.c b/src/makeauto.c new file mode 100644 index 0000000..6e8ff71 --- /dev/null +++ b/src/makeauto.c @@ -0,0 +1,177 @@ +#include +#include +#include + +#include "fujichat.h" +#include "common.h" +#include "features.h" + +#define DRIVER_LIST_LEN (sizeof(rs232_drivers) / sizeof(rs232_drivers[0])) +static char *rs232_drivers[][2] = { + { NULL, "(No driver; manual setup)" }, + { "D:BOBVERT.SER", "SIO2PC or R:Verter" }, + { "D:ATARI850.SER", "Atari 850" }, + { "D:PRCONN.SER", "P:R: Connection" }, +}; + +/* APPEND_BUF_SIZE should be >= the size of the largest .SER file */ +#define APPEND_BUF_SIZE 2048 + +void reboot(void) { + asm("jmp $e477"); +} + +static char get_yesno(char *prompt, char dflt) { + char buf[5]; + + printf("%s [%c/%c]: ", + prompt, + (dflt ? 'Y' : 'y'), + (dflt ? 'n' : 'N')); + + fflush(stdout); + get_line(buf, 4); + switch(*buf) { + case 'y': + case 'Y': + return 1; + + case 'n': + case 'N': + return 0; + + default: + return dflt; + } +} + +//char append_to(FILE *to, char *src) { +// int bytes; +// char ret; +// static char buf[APPEND_BUF_SIZE]; +// FILE *from = fopen(src, "rb"); +// +// printf("append_to: %s\n", src); +// +// if(!from) { +// perror(src); +// return 0; +// } +// +// while( (bytes = fread(buf, 1, APPEND_BUF_SIZE, from)) ) { +// printf("%d bytes in, eof? %d\n", bytes, feof(from)); +// bytes = fwrite(buf, 1, bytes, to); +// printf("%d bytes out\n", bytes); +// } +// +// ret = feof(from); /* 1 = no error */ +// fclose(from); +// +// return ret; +//} + +char append_to(FILE *to, char *src) { + int bytes = 0, c; + char ret; + // static char buf[APPEND_BUF_SIZE]; + FILE *from = fopen(src, "rb"); + + printf("append_to: %s\n", src); + + if(!from) { + perror(src); + return 0; + } + + /* painfully slow, sorry! TODO: figure out why fread() returns + extra bytes after EOF (probably because the file doesn't + end on a sector boundary, or something equally lame) */ + while( (c = fgetc(from)) != EOF ) { + fputc(c, to); + ++bytes; + } + + ret = feof(from); /* 1 = no error */ + fclose(from); + + printf("bytes=%d, ret=%d\n", bytes, ret); + return ret; +} + +char append_files(char *dst, char *src1, char *src2) { + char ret; + FILE *dfile = fopen(dst, "wb"); + + if(dfile) { + ret = (append_to(dfile, src1) && append_to(dfile, src2)); + fclose(dfile); + return ret; + } else { + perror(dst); + return 0; + } +} + +static void rs232_driver_menu() { + static char buf[256]; + int i; + + puts("Select your serial port type\n"); + for(i=0; i= '2' && *buf <= '9') { + i = *buf - '1'; + if(i < DRIVER_LIST_LEN) { + strcpy(buf, rs232_drivers[i][0]); + i = 0; + } else { + putchar(A_BEL); + i = 1; + } + } /* else use whatever they entered as a filename */ + } while(i); + + // if(!rename("D:AUTORUN.SYS", "D:AUTORUN.BAK")) { + // puts("Renamed AUTORUN.SYS to AUTORUN.BAK"); + // } + + do { + printf("\nCreating AUTORUN.SYS from\n%s and LOADMENU.COM\n", buf); + i = !append_files("D:AUTORUN.SYS", buf, "D:LOADMENU.COM"); + if(i) { + i = get_yesno("\xfdRetry", 1); + if(!i) { + puts("Failed to change driver"); + return; + } + } + } while(i); + + puts("You must reboot to use the new driver."); + if(get_yesno("Reboot now", 1)) + reboot(); + + // rs232_already_loaded = scan_hatabs('R'); +} + +void main(int, char **) { + rs232_driver_menu(); + exit(0); +} + diff --git a/src/mkdisk.sh b/src/mkdisk.sh new file mode 100644 index 0000000..5da6985 --- /dev/null +++ b/src/mkdisk.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +set -e + +rm -rf disk +mkdir disk +cp dos_20s.atr disk/fujichat.atr +cp uip fujichat.xex +cp atari850.ser disk/atari850.ser +cp bobvert.com disk/bobvert.ser +cp prconn.ser disk/prconn.ser + +if [ -f about.txt ]; then + perl -pe 's/\n/\x9b/' < about.txt > disk/about.txt +fi + +cd disk +for i in about loadmenu fujimenu makeauto fujiconf fujichat; do + cat ../aexec.xex ../$i.xex > $i.com + axe -w $i.com fujichat.atr +done + +#cat ../bobvert.com fujimenu.com > autorun.sys +#cat fujimenu.com > autorun.sys + +cat ../aexec.xex ../loadmkau.xex > autorun.sys +axe -w autorun.sys fujichat.atr + +axe -w atari850.ser fujichat.atr +axe -w bobvert.ser fujichat.atr +axe -w prconn.ser fujichat.atr + +if [ -f about.txt ]; then + axe -w about.txt fujichat.atr +fi + +cp fujichat.atr .. + +# build my own test disk so I don't have to keep going thru the +# serial port and config every time +if [ "`whoami`" = "urchlay" ]; then + cat bobvert.ser loadmenu.com > autorun.sys + cp ../fujichat.cfg . + cp fujichat.atr fujitest.atr + axe -w autorun.sys fujitest.atr + axe -w fujichat.cfg fujitest.atr + mv fujitest.atr .. +fi diff --git a/src/mkfuji64.sh b/src/mkfuji64.sh new file mode 100644 index 0000000..88ff391 --- /dev/null +++ b/src/mkfuji64.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cat bobvert.com col64.xex disk/fujichat.com > autorun.sys +axe -w autorun.sys fuji80.atr diff --git a/src/mkfuji80.sh b/src/mkfuji80.sh new file mode 100644 index 0000000..c4b7e75 --- /dev/null +++ b/src/mkfuji80.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cat bobvert.com col80_modified/col80_hacked.xex disk/fujichat.com > autorun.sys +axe -w autorun.sys fuji80.atr diff --git a/src/new_format_ip.s b/src/new_format_ip.s new file mode 100644 index 0000000..5fab2ba --- /dev/null +++ b/src/new_format_ip.s @@ -0,0 +1,54 @@ + .fopt compiler,"cc65 v 2.12.9" + .setcpu "6502" + .smart on + .autoimport on + .case on + .debuginfo off + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .export _new_format_ip + + .segment "BSS" +buf: + .res 20,$0 + + .segment "RODATA" +fmt: .byte "%d.%d.%d.%d", 0 + +; unsigned char* __fastcall__ format_ip (__near__ unsigned int[2]*) + .segment "CODE" +_new_format_ip: + sta ptr1 + stx ptr1+1 + + lda #buf + jsr pushax + + lda #fmt + jsr pushax + + ldy #0 + lda (ptr1),y + jsr pusha0 + + ldy #1 + lda (ptr1),y + jsr pusha0 + + ldy #2 + lda (ptr1),y + jsr pusha0 + + ldy #3 + lda (ptr1),y + jsr pusha0 + + ldy #$0c + jsr _sprintf + + lda #buf + + rts diff --git a/src/notes.64x34 b/src/notes.64x34 new file mode 100644 index 0000000..e886760 --- /dev/null +++ b/src/notes.64x34 @@ -0,0 +1,176 @@ + +64x34 software text mode needs GR.8 style screen, at 320x204. This +requires 8160 bytes for screen memory, plus (I think) 214 bytes +for display list. The initial version will probably use the plain +GR.8+16 display, and only support 32 rows. + +Character cells are 5x6, with glyphs being mostly 4x5 with a blank row +at the bottom and blank column on the left. Probably for lowercase and +capital M/m/W/w, I'll hard-code a bit of logic to copy the right-most +bit into the normally-blank left-most column, so these characters will +be fully-formed, though they'll touch the char to the left. Doing it +this way allows packing one row of pixels from 2 different glyphs into +each byte of glyph-definition table, like COL80 does. + +Depending on the design of the final font, it might also be that I can +avoid storing the bottom row (a few characters might need it to be a +copy of the top row, or I might get away with hard-coding zero). If +I'm not storing the bottom row, each 2 glyphs will take up 5 bytes +of table space (for a 128-character font, that's 320 bytes; for an +ASCII-only 96-char font, only 240 bytes! That fits in one page, so +I can simplify the routine that reads it). If I do store the bottom +row, those numbers become 384 and 288 bytes, respectively. Later on +if there's support for UTF-8 or whatever, it still might be better +to use the 240-byte 96-char fonts, but allow for more than one of +them. + +The renderer needs to be able to handle inverse video. It would also be +nice to support underlining (just force the bottom row of each glyph to +all 1's), but then there needs to be a way for the calling application +to set underline mode. Also it might be hard to read... Theoretically +it'd be possible to do italics too (shift the bottom few rows of pixels +left), but I think it would come out too ugly to want to use. + +Writing a glyph to screen RAM involves a 2-byte buffer for each row of +pixels. Extract 4-bit glyph data from glyph table, synthesize the 5th +bit for MmWw, store in the 2-byte buffer (in top 5 bits), then calculate +how many pixels to shift it, based on the cursor position. When actually +writing to RAM, have to load the old data from each of the 2 bytes, mask +off the appropriate bits, OR in the new bits, store back to RAM. This is +kind of an expensive operation, but we're only doing it for 6 scanlines +instead of 8 like COL80 uses, so maybe it'll be fast enough. + +If the right mask is $00, we don't have to touch the 2nd byte at all. The +left mask will never be $00. (algorithm below does touch the 2nd byte though) + +leftbyte = int(COLCRS*5/8), easy enough to calculate, but table lookup +will be faster. If we get tight on space, try it without the table. + +shift amounts will be stored in a table. Only 8 entries needed, lookup +on COLCRS%8. + +; first, calculate or lookup the start address of the current +; screen line, *SAVMSC + (*ROWCRS * 5), and store in rowptr +; next, calculate or lookup the start address of the corrent +; glyph, extract the relevant 4 bits (top or bottom nybble) and +; store in glyphdata bits 2-6 (all other bits 0). Store 0 in glyphdata+1. +; This is the body of the inner loop... rowptr needs to get 40 added to +; it every time through the loop. + lda COLCRS + tax + lda left_byte_table,x + clc + adc rowptr + sta zptr + adc rowptr+1 + sta zptr+1 + ; (zptr) now points to left byte + ldy #0 + lda (zptr),y + sta olddata + iny + lda (zptr),y + sta olddata+1 + ; olddata holds the old screen RAM contents + + lda #$07 + sta mask + lda #$FF + sta mask+1 + + txa + and #$07 ; a%=8 + tay + lda shift_amt_table,y + tay ; Y now holds the shift amount + beq no_shift + +shift_loop: + lsr glyphdata + ror glyphdata+1 + sec + ror mask + ror mask+1 + dey + bpl shift_loop + + iny ; Y = 0 +no_shift: + lda olddata + and mask + ora glyphdata + sta (zptr),y + iny + lda olddata+1 + and mask+1 + ora glyphdata+1 + sta (zptr),y + +To calculate screen bytes to alter... COLCRS ranges 0 to 63: + +COLCRS - leftbyte - shift amount - leftmask - rightmask +0 0 0 $F8 $00 +1 0 5 $07 $C0 +2 1 2 $3E $00 +3 1 7 $01 $F0 +4 2 4 $0F $80 +5 3 1 $7C $00 +6 3 6 $03 $E0 +7 4 3 $1F $00 +8 5 +9 5 +10 6 +11 6 +12 7 +13 8 +14 8 +15 9 +16 10 +17 10 +18 11 +19 11 +20 12 +21 13 +22 13 +23 14 +24 15 +25 15 +26 16 +27 16 +28 17 +29 18 +30 18 +31 19 +32 20 +33 20 +34 21 +35 21 +36 22 +37 23 +38 23 +39 24 +40 25 +41 25 +42 26 +43 26 +44 27 +45 28 +46 28 +47 29 +48 30 +49 30 +50 31 +51 31 +52 32 +53 33 +54 33 +55 34 +56 35 +57 35 +58 36 +59 36 +60 37 +61 38 +62 38 +63 39 + diff --git a/src/prconn.ser b/src/prconn.ser new file mode 100644 index 0000000..8332d4e Binary files /dev/null and b/src/prconn.ser differ diff --git a/src/put.c b/src/put.c new file mode 100644 index 0000000..7425fb3 --- /dev/null +++ b/src/put.c @@ -0,0 +1,12 @@ + +void __fastcall__ fuji_putchar(char); + +void main(void) { + char msg[] = "Test\n"; + char i; + + for(i=0; i<5; ++i) + fuji_putchar(msg[i]); + +HANG: goto HANG; +} diff --git a/src/rs232dev.c b/src/rs232dev.c new file mode 100644 index 0000000..9738fce --- /dev/null +++ b/src/rs232dev.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Dunkels. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: rs232dev.c,v 1.1 2001/11/20 20:49:45 adam Exp $ + * + */ + +/* + * This is a generic implementation of the SLIP protocol over an RS232 + * (serial) device. While initially intented for the C64, the code can + * easily be ported to other platforms as well. + * + * Huge thanks to Ullrich von Bassewitz of cc65 fame for + * and endless supply of bugfixes, insightsful comments and + * suggestions, and improvements to this code! + */ + +#include +#include +#include + + /* This will include the system specific header files as well */ +#if defined(__CBM__) +# include +#elif defined(__ATARI__) +# include +#endif + +#include "uip.h" + +#include "features.h" + +#ifdef FEAT_KEYBOARD_BUFFER +#include "keybuf.h" +#endif + +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + + +#define SIO_RECV(c) while(rs232_get(&c) == RS_ERR_NO_DATA) +#define SIO_POLL(c) (rs232_get(&c) != RS_ERR_NO_DATA) +#define SIO_SEND(c) rs232_put(c) + +#define MAX_SIZE UIP_BUFSIZE + +static u8_t slip_buf[MAX_SIZE]; + +#if MAX_SIZE > 255 +static u16_t len, tmplen; +#else +static u8_t len, tmplen; +#endif /* MAX_SIZE > 255 */ + +#if 0 +#define printf(x) +#else +#include +#endif + +#ifdef FEAT_TRAFFIC_INDICATOR +#include +/* FujiChat screen stuff */ +static u16_t traffic_indicator; +static char old_char; + +#define DOWN_ARROW 0xdd +#define UP_ARROW 0xdc + +#endif + +/*-----------------------------------------------------------------------------------*/ +static void rs232_err(char err) { + switch(err) { + case RS_ERR_OK: + // printf("RS232 OK\n"); + break; + case RS_ERR_NOT_INITIALIZED: + printf("RS232 not initialized\n"); + break; + case RS_ERR_BAUD_TOO_FAST: + printf("RS232 baud too fast\n"); + break; + case RS_ERR_BAUD_NOT_AVAIL: + printf("RS232 baud rate not available\n"); + break; + case RS_ERR_NO_DATA: + printf("RS232 nothing to read\n"); + break; + case RS_ERR_OVERFLOW: + printf("RS232 overflow\n"); + break; + } +} + +/*-----------------------------------------------------------------------------------*/ +/* + * rs232dev_send(): + * + * Sends the packet in the uip_buf and uip_appdata buffers. The first + * 40 bytes of the packet (the IP and TCP headers) are read from the + * uip_buf buffer, and the following bytes (the application data) are + * read from the uip_appdata buffer. + * + */ +/*-----------------------------------------------------------------------------------*/ + +void rs232dev_send(void) { +#if MAX_SIZE > 255 + u16_t i; +#else + u8_t i; +#endif /* MAX_SIZE > 255 */ + volatile u8_t *ptr; + u8_t c; + +#ifdef FEAT_TRAFFIC_INDICATOR + old_char = PEEK(traffic_indicator); + POKE(traffic_indicator, UP_ARROW); +#endif + + SIO_SEND(SLIP_END); + + ptr = uip_buf; + for(i = 0; i < uip_len; ++i) { + if(i == 40) { + ptr = uip_appdata; + } + c = *ptr++; + switch(c) { + case SLIP_END: + SIO_SEND(SLIP_ESC); + SIO_SEND(SLIP_ESC_END); + break; + case SLIP_ESC: + SIO_SEND(SLIP_ESC); + SIO_SEND(SLIP_ESC_ESC); + break; + default: + SIO_SEND(c); + break; + } +#ifdef FEAT_KEYBOARD_BUFFER + keybuf_poll_kbd(); +#endif + } + SIO_SEND(SLIP_END); + +#ifdef FEAT_TRAFFIC_INDICATOR + POKE(traffic_indicator, old_char); +#endif +} + +/*-----------------------------------------------------------------------------------*/ +/* + * rs232dev_poll(): + * + * Read all avaliable bytes from the RS232 interface into the slip_buf + * buffer. If no more bytes are avaliable, it returns with 0 to + * indicate that no packet was immediately ready. When a full packet + * has been read into the buffer, the packet is copied into the + * uip_buf buffer and the length of the packet is returned. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#if MAX_SIZE > 255 +u16_t +#else +u8_t +#endif /* MAX_SIZE > 255 */ +rs232dev_poll(void) { + u8_t c; + static u8_t lastc; + +#ifdef FEAT_TRAFFIC_INDICATOR + old_char = PEEK(traffic_indicator); +#endif + + while(SIO_POLL(c)) { +#ifdef FEAT_TRAFFIC_INDICATOR + POKE(traffic_indicator, DOWN_ARROW); +#endif +#ifdef FEAT_KEYBOARD_BUFFER + keybuf_poll_kbd(); +#endif + switch(c) { + case SLIP_ESC: + lastc = c; + break; + + case SLIP_END: + lastc = c; + /* End marker found, we copy our input buffer to the uip_buf + buffer and return the size of the packet we copied. */ + memcpy(uip_buf, slip_buf, len); + tmplen = len; + len = 0; +#ifdef FEAT_TRAFFIC_INDICATOR + POKE(traffic_indicator, old_char); +#endif + return tmplen; + + default: + if(lastc == SLIP_ESC) { + lastc = c; + /* Previous read byte was an escape byte, so this byte will be + interpreted differently from others. */ + switch(c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + } + } else { + lastc = c; + } + + slip_buf[len] = c; + ++len; + + if(len > MAX_SIZE) { + len = 0; + } + + break; + } + } + +#ifdef FEAT_TRAFFIC_INDICATOR + POKE(traffic_indicator, old_char); +#endif + return 0; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * rs232dev_init(): + * + * Initializes the RS232 device and sets the parameters of the device. + * + */ +/*-----------------------------------------------------------------------------------*/ + +char rs232dev_init(unsigned char baud) { + char err; + +#ifdef FEAT_TRAFFIC_INDICATOR + traffic_indicator = PEEKW(0x58) + 39; /* upper-right corner */ +#endif + + err = rs232_init(0); + rs232_err(err); + err = rs232_params(baud, RS_PAR_NONE); + rs232_err(err); + + len = 0; + + return err; +} +/*-----------------------------------------------------------------------------------*/ + +void rs232dev_close(void) { + rs232_done(); +} diff --git a/src/rs232dev.h b/src/rs232dev.h new file mode 100644 index 0000000..543ab99 --- /dev/null +++ b/src/rs232dev.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Dunkels. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: rs232dev.h,v 1.1 2001/11/20 20:49:45 adam Exp $ + * + */ + +#ifndef __RS232DEV_H__ +#define __RS232DEV_H__ + +#include "uip.h" + +char rs232dev_init(unsigned char baud); +u8_t rs232dev_read(void); +void rs232dev_send(void); +void rs232dev_close(void); + +#if UIP_BUFSIZE > 255 +u16_t rs232dev_poll(void); +#else +u8_t rs232dev_poll(void); +#endif /* UIP_BUFSIZE > 255 */ + +#endif /* __RS232DEV_H__ */ diff --git a/src/rvert.com b/src/rvert.com new file mode 100644 index 0000000..b5aeccc Binary files /dev/null and b/src/rvert.com differ diff --git a/src/slattach_rts.diff b/src/slattach_rts.diff new file mode 100644 index 0000000..d14afe1 --- /dev/null +++ b/src/slattach_rts.diff @@ -0,0 +1,26 @@ +--- net-tools-1.60/slattach.c 2008-11-01 12:29:56.000000000 -0400 ++++ net-tools-1.60.patched/slattach.c 2008-10-31 21:41:43.000000000 -0400 +@@ -347,6 +347,7 @@ + tty->c_cflag |= CLOCAL; + else + tty->c_cflag |= CRTSCTS; ++ tty->c_cflag &= ~CRTSCTS; /* 20081031 bkw: need or not? */ + tty->c_cflag |= speed; /* restore speed */ + return(0); + } +@@ -723,6 +724,15 @@ + (void) signal(SIGQUIT, sig_catch); + (void) signal(SIGTERM, sig_catch); + ++ /* 20081031 bkw: force RTS off (Tucker sio2pc) */ ++ { ++ int tstatus; ++ fprintf(stderr, "slattach: RTS forced off (Tucker SIO2PC)\n"); ++ ioctl(tty_fd, TIOCMGET, &tstatus); ++ tstatus &= ~TIOCM_RTS; ++ ioctl(tty_fd, TIOCMSET, &tstatus); ++ } ++ + /* Wait until we get killed if hanging on a terminal. */ + if (opt_e == 0) { + while(1) { diff --git a/src/slirp_debug b/src/slirp_debug new file mode 100644 index 0000000..7a2f1b5 --- /dev/null +++ b/src/slirp_debug @@ -0,0 +1,2 @@ +Slirp 1.0.16 - Debugging Started. +Debugging Started level 10. diff --git a/src/start_getty.sh b/src/start_getty.sh new file mode 100644 index 0000000..7195d5e --- /dev/null +++ b/src/start_getty.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +ATR_IMAGE=${1-dumb.atr} +TTY=/dev/ttyS0 + +fuser -k $TTY 2&>/dev/null # make sure nobody's using the port... +$DELAY +fuser -k -9 $TTY 2&>/dev/null # Just in case... +$DELAY +modprobe atarisio port=$TTY +$DELAY +atariserver $ATR_IMAGE +#atariserver autorun.sys # fails when run from MyPicoDOS, why? +$DELAY +rmmod atarisio +$DELAY +strace -o/dev/null agetty -L $TTY 4800 vt100 & +$DELAY +./clear_rts diff --git a/src/start_slip.sh b/src/start_slip.sh new file mode 100755 index 0000000..8a9320a --- /dev/null +++ b/src/start_slip.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +# Configurable stuff: + +TTY=/dev/ttyUSB0 # serial port to use +BAUD=9600 # must match compiled-in value in rs232dev.c +SLATTACH=a8_slattach # slattach binary (possibly patched) +SLIP_IFACE=sl0 # probably no need to change this +LOCAL_IP=192.168.0.1 # SLIP IP address for Linux host +REMOTE_IP=192.168.0.2 # SLIP IP address for Atari host +IP_FORWARD=yes # Route packets for the Atari? +IP_MASQUERADE=yes # NAT for the Atari? +MASQ_IFACE=eth1 # if NATing, our main (LAM or internet) interface +DUMP_PACKETS=yes # Run tcpdump on sl0 interface? + +# DELAY may not be needed on all systems... + +# No delay: +#DELAY="true" + +# 1 second: +#DELAY="sleep 1" + +# 1/4 second (may not work on old Linux installs): +DELAY="usleep 250000" + +# End of config section, start of code: + +ifconfig $SLIP_IFACE down 2&>/dev/null +killall $SLATTACH 2&>/dev/null +fuser -k $TTY 2&>/dev/null # make sure nobody's using the port... +$DELAY +fuser -k -9 $TTY 2&>/dev/null # Just in case... +$DELAY + +echo "Starting SLIP on $SLIP_IFACE, local $LOCAL_IP, remote $REMOTE_IP" +$SLATTACH -L -p slip -s $BAUD $TTY & +$DELAY +ifconfig $SLIP_IFACE $LOCAL_IP mtu 576 +ifconfig $SLIP_IFACE $LOCAL_IP pointopoint $REMOTE_IP + +if [ "$IP_MASQUERADE" = "yes" ]; then + echo "IP Masquerading enabled" + iptables -F + iptables -t nat -F + iptables -t nat -A POSTROUTING -o $MASQ_IFACE -j MASQUERADE +fi + +if [ "$IP_FORWARD" = "yes" ]; then + echo "IP Forwarding enabled" + echo "1" > /proc/sys/net/ipv4/ip_forward +fi + +if [ "$DUMP_PACKETS" = "yes" ]; then + tcpdump -i $SLIP_IFACE -X -n -vvv -s 0 +fi diff --git a/src/start_slirp.sh b/src/start_slirp.sh new file mode 100644 index 0000000..4f3ad40 --- /dev/null +++ b/src/start_slirp.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# Configurable stuff: + +TTY=/dev/ttyS0 # serial port to use +BAUD=4800 # must match FujiChat conf + +# This setting is only needed if you're using an AtariMax (Steve Tucker) +# auto-sensing SIO2PC as your serial device. +TUCKER_SIO2PC_HACK="yes" + +# DELAY is needed on some (most?) systems because e.g. atariserver tries +# to run before the atarisio module is fully initialized. Choose one: + +# No delay: +#DELAY="true" + +# 1 second: +#DELAY="sleep 1" + +# 1/4 second (may not work on old Linux installs): +DELAY="usleep 250000" + +slirp "tty $TTY" "mru 576" "mtu 576" "baudrate $BAUD" & + +if [ "$TUCKER_SIO2PC_HACK" = "yes" ]; then + sleep 1 + ./clear_rts +fi diff --git a/src/test.atr b/src/test.atr new file mode 100644 index 0000000..67e0b78 Binary files /dev/null and b/src/test.atr differ diff --git a/src/testip.c b/src/testip.c new file mode 100644 index 0000000..44f1086 --- /dev/null +++ b/src/testip.c @@ -0,0 +1,10 @@ + +#include + +extern unsigned char * __fastcall__ new_format_ip (void *); + +void main(void) { + char ip[4] = { 0xc0, 0xa8, 0x00, 0x01 }; + puts(new_format_ip(ip)); +HANG: goto HANG; +} diff --git a/src/uip-conf.h b/src/uip-conf.h new file mode 100644 index 0000000..1a9e745 --- /dev/null +++ b/src/uip-conf.h @@ -0,0 +1,180 @@ + +/** + * \addtogroup uipopt + * @{ + */ + +/** + * \name Project-specific configuration options + * @{ + * + * uIP has a number of configuration options that can be overridden + * for each project. These are kept in a project-specific uip-conf.h + * file and all configuration names have the prefix UIP_CONF. + */ + +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: uip-conf.h,v 1.6 2006/06/12 08:00:31 adam Exp $ + */ + +/** + * \file + * An example uIP configuration file + * \author + * Adam Dunkels + */ + +#ifndef __UIP_CONF_H__ +#define __UIP_CONF_H__ + +/** + * 8 bit datatype + * + * This typedef defines the 8-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef unsigned char u8_t; + +/** + * 16 bit datatype + * + * This typedef defines the 16-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef unsigned int u16_t; + +/** + * Statistics datatype + * + * This typedef defines the dataype used for keeping statistics in + * uIP. + * + * \hideinitializer + */ +typedef unsigned short uip_stats_t; + +/** + * Maximum number of TCP connections. + * + * \hideinitializer + */ +// #define UIP_CONF_MAX_CONNECTIONS 5 +#define UIP_CONF_MAX_CONNECTIONS 1 +#define UIP_CONF_UDP_CONNS 1 + +/* disable TCP listen support entirely, saves approx. 1K + in the binary + */ +// #define UIP_CONF_TCP_LISTEN +#undef UIP_CONF_TCP_LISTEN + +/** + * Maximum number of listening TCP ports. + * (not used if UIP_CONF_TCP_LISTEN is 0) + * + * \hideinitializer + */ +// #define UIP_CONF_MAX_LISTENPORTS 5 +#define UIP_CONF_MAX_LISTENPORTS 1 + +/** + * uIP buffer size. + * + * \hideinitializer + */ +// #define UIP_CONF_BUFFER_SIZE 160 +#define UIP_CONF_BUFFER_SIZE 576 + +/** + * CPU byte order. + * + * \hideinitializer + */ +#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN + +/** + * Logging on or off + * + * \hideinitializer + */ +#define UIP_CONF_LOGGING 0 + +/** + * UDP support on or off + * + * \hideinitializer + */ +#define UIP_CONF_UDP 1 + +/** + * UDP checksums on or off + * + * \hideinitializer + */ +// #define UIP_CONF_UDP_CHECKSUMS 1 +#define UIP_CONF_UDP_CHECKSUMS 0 + +/** + * uIP statistics on or off + * + * \hideinitializer + */ +#define UIP_CONF_STATISTICS 0 + +/* 0 for SLIP, 14 for Ethernet */ +#define UIP_CONF_LLH_LEN 0 + +/* Here we include the header file for the application(s) we use in + our project. */ +/*#include "smtp.h"*/ +/*#include "hello-world.h"*/ +/*#include "telnetd.h"*/ +// #include "webclient.h" +/*#include "dhcpc.h"*/ +/*#include "webclient.h"*/ + +/* +#ifdef LIB_ONLY +#define uip_tcp_appstate_t int +#undef UIP_CONF_UDP +#else +*/ +#include "resolv.h" +#include "telnet.h" +// #endif + +#endif /* __UIP_CONF_H__ */ + +/** @} */ +/** @} */ diff --git a/src/uip_arch.h b/src/uip_arch.h new file mode 100644 index 0000000..e69de29 diff --git a/src/uip_asm_output.s b/src/uip_asm_output.s new file mode 100644 index 0000000..7f8c38c --- /dev/null +++ b/src/uip_asm_output.s @@ -0,0 +1,5253 @@ +; +; File generated by cc65 v 2.12.9 +; + .fopt compiler,"cc65 v 2.12.9" + .setcpu "6502" + .smart on + .autoimport on + .case on + .debuginfo off + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .import _resolv_appcall + .import _telnet_app + .export _uip_init + .export _uip_setipid + .export _uip_buf + .export _uip_listen + .export _uip_unlisten + .export _uip_connect + .export _uip_send + .export _uip_udp_new + .export _htons + .export _uip_appdata + .export _uip_len + .export _uip_conn + .export _uip_conns + .export _uip_acc32 + .export _uip_udp_conn + .export _uip_udp_conns + .export _uip_flags + .export _uip_process + .export _uip_hostaddr + .export _uip_netmask + .export _uip_draddr + .export _uip_chksum + .export _uip_ipchksum + .export _uip_tcpchksum + .import _memcpy + .import _memset + .export _uip_ethaddr + .export _uip_sappdata + .export _uip_slen + .export _uip_listenports + .export _uip_add32 + +.segment "DATA" + +_all_ones_addr: + .word $FFFF + .word $FFFF +_all_zeroes_addr: + .word $0000 + .word $0000 +_uip_ethaddr: + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + +.segment "BSS" + +_uip_hostaddr: + .res 4,$00 +_uip_draddr: + .res 4,$00 +_uip_netmask: + .res 4,$00 +_uip_buf: + .res 578,$00 +_uip_appdata: + .res 2,$00 +_uip_sappdata: + .res 2,$00 +_uip_len: + .res 2,$00 +_uip_slen: + .res 2,$00 +_uip_flags: + .res 1,$00 +_uip_conn: + .res 2,$00 +_uip_conns: + .res 35,$00 +_uip_listenports: + .res 2,$00 +_uip_udp_conn: + .res 2,$00 +_uip_udp_conns: + .res 11,$00 +_ipid: + .res 2,$00 +_iss: + .res 4,$00 +_lastport: + .res 2,$00 +_uip_acc32: + .res 4,$00 +_c: + .res 1,$00 +_opt: + .res 1,$00 +_tmp16: + .res 2,$00 + +; --------------------------------------------------------------- +; void __near__ uip_init (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_init: near + +.segment "CODE" + +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; + lda #$00 + sta _c +L00BF: lda _c + cmp #$01 + bcs L00C0 +; +; uip_listenports[c] = 0; +; + ldx #$00 + lda _c + jsr aslax1 + clc + adc #<(_uip_listenports) + tay + txa + adc #>(_uip_listenports) + tax + tya + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + iny + sta (sreg),y +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; + inc _c + jmp L00BF +; +; for(c = 0; c < UIP_CONNS; ++c) { +; +L00C0: lda #$00 + sta _c +L00CA: lda _c + cmp #$01 + bcs L00CB +; +; uip_conns[c].tcpstateflags = UIP_CLOSED; +; + lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + tay + txa + adc #>(_uip_conns) + tax + tya + sta sreg + stx sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; for(c = 0; c < UIP_CONNS; ++c) { +; + inc _c + jmp L00CA +; +; lastport = 1024; +; +L00CB: ldx #$04 + lda #$00 + sta _lastport + stx _lastport+1 +; +; for(c = 0; c < UIP_UDP_CONNS; ++c) { +; + sta _c +L00D7: lda _c + cmp #$01 + bcs L00D8 +; +; uip_udp_conns[c].lport = 0; +; + lda _c + jsr pusha0 + lda #$0B + jsr tosmula0 + clc + adc #<(_uip_udp_conns) + tay + txa + adc #>(_uip_udp_conns) + tax + tya + sta sreg + stx sreg+1 + lda #$00 + ldy #$04 + sta (sreg),y + iny + sta (sreg),y +; +; for(c = 0; c < UIP_UDP_CONNS; ++c) { +; + inc _c + jmp L00D7 +; +; } +; +L00D8: rts + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_setipid (unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_setipid: near + +.segment "CODE" + +; +; void uip_setipid(u16_t id) { ipid = id; } +; + jsr ldax0sp + sta _ipid + stx _ipid+1 + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_listen (unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_listen: near + +.segment "CODE" + +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; + lda #$00 + sta _c +L01AF: lda _c + cmp #$01 + jcs incsp2 +; +; if(uip_listenports[c] == 0) { +; + ldx #$00 + lda _c + jsr aslax1 + clc + adc #<(_uip_listenports) + tay + txa + adc #>(_uip_listenports) + tax + tya + jsr ldaxi + cpx #$00 + bne L01B1 + cmp #$00 + bne L01B1 +; +; uip_listenports[c] = port; +; + lda _c + jsr aslax1 + clc + adc #<(_uip_listenports) + tay + txa + adc #>(_uip_listenports) + tax + tya + sta sreg + stx sreg+1 + jsr ldax0sp + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y +; +; return; +; + jmp incsp2 +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; +L01B1: inc _c + jmp L01AF + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_unlisten (unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_unlisten: near + +.segment "CODE" + +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; + lda #$00 + sta _c +L01A0: lda _c + cmp #$01 + jcs incsp2 +; +; if(uip_listenports[c] == port) { +; + ldx #$00 + lda _c + jsr aslax1 + clc + adc #<(_uip_listenports) + tay + txa + adc #>(_uip_listenports) + tax + tya + jsr pushw + ldy #$03 + jsr ldaxysp + jsr tosicmp + bne L01A2 +; +; uip_listenports[c] = 0; +; + ldx #$00 + lda _c + jsr aslax1 + clc + adc #<(_uip_listenports) + tay + txa + adc #>(_uip_listenports) + tax + tya + sta sreg + stx sreg+1 + lda #$00 + tay + sta (sreg),y + iny + sta (sreg),y +; +; return; +; + jmp incsp2 +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; +L01A2: inc _c + jmp L01A0 + +.endproc + +; --------------------------------------------------------------- +; __near__ struct uip_conn* __near__ uip_connect (__near__ unsigned int[2]*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_connect: near + +.segment "CODE" + +; +; again: +; + jsr decsp4 +; +; ++lastport; +; +L00E3: inc _lastport + bne L00E5 + inc _lastport+1 +; +; if(lastport >= 32000) { +; +L00E5: ldx _lastport+1 + cpx #$7D + bcc L00E6 +; +; lastport = 4096; +; + ldx #$10 + lda #$00 + sta _lastport + stx _lastport+1 +; +; for(c = 0; c < UIP_CONNS; ++c) { +; +L00E6: lda #$00 + sta _c +L00EA: lda _c + cmp #$01 + bcs L00EB +; +; conn = &uip_conns[c]; +; + lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + tay + txa + adc #>(_uip_conns) + tax + tya + ldy #$02 + jsr staxysp +; +; if(conn->tcpstateflags != UIP_CLOSED && +; + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L00EC +; +; conn->lport == htons(lastport)) { +; + ldy #$03 + jsr ldaxysp + ldy #$05 + jsr pushwidx + lda _lastport + ldx _lastport+1 + jsr pushax + jsr _htons + jsr tosicmp + beq L00E3 +; +; for(c = 0; c < UIP_CONNS; ++c) { +; +L00EC: inc _c + jmp L00EA +; +; conn = 0; +; +L00EB: ldx #$00 + txa + ldy #$02 + jsr staxysp +; +; for(c = 0; c < UIP_CONNS; ++c) { +; + sta _c +L00FC: lda _c + cmp #$01 + bcs L00FD +; +; cconn = &uip_conns[c]; +; + lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + tay + txa + adc #>(_uip_conns) + tax + tya + jsr stax0sp +; +; if(cconn->tcpstateflags == UIP_CLOSED) { +; + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + bne L0107 +; +; conn = cconn; +; + jsr ldax0sp + ldy #$02 + jsr staxysp +; +; break; +; + jmp L00FD +; +; if(cconn->tcpstateflags == UIP_TIME_WAIT) { +; +L0107: jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$07 + bne L00FE +; +; if(conn == 0 || +; + ldy #$02 + lda (sp),y + iny + ora (sp),y + beq L010E +; +; cconn->timer > conn->timer) { +; + jsr ldax0sp + ldy #$1A + sta ptr1 + stx ptr1+1 + lda (ptr1),y + jsr pusha0 + ldy #$05 + jsr ldaxysp + ldy #$1A + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr tosicmp + beq L00FE + bcc L00FE +; +; conn = cconn; +; +L010E: jsr ldax0sp + ldy #$02 + jsr staxysp +; +; for(c = 0; c < UIP_CONNS; ++c) { +; +L00FE: inc _c + jmp L00FC +; +; if(conn == 0) { +; +L00FD: ldy #$02 + lda (sp),y + iny + ora (sp),y + bne L0113 +; +; return 0; +; + tax + jmp incsp8 +; +; conn->tcpstateflags = UIP_SYN_SENT; +; +L0113: jsr ldaxysp + sta sreg + stx sreg+1 + lda #$02 + ldy #$19 + sta (sreg),y +; +; conn->snd_nxt[0] = iss[0]; +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda _iss + ldy #$0C + sta (sreg),y +; +; conn->snd_nxt[1] = iss[1]; +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda _iss+1 + ldy #$0D + sta (sreg),y +; +; conn->snd_nxt[2] = iss[2]; +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda _iss+2 + ldy #$0E + sta (sreg),y +; +; conn->snd_nxt[3] = iss[3]; +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda _iss+3 + ldy #$0F + sta (sreg),y +; +; conn->initialmss = conn->mss = UIP_TCP_MSS; +; + ldy #$05 + jsr pushwysp + ldy #$07 + jsr pushwysp + ldx #$00 + lda #$78 + ldy #$12 + jsr staxspidx + ldy #$14 + jsr staxspidx +; +; conn->len = 1; /* TCP length of the SYN is one. */ +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$01 + ldy #$10 + sta (sreg),y + iny + lda #$00 + sta (sreg),y +; +; conn->nrtx = 0; +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1B + sta (sreg),y +; +; conn->timer = 1; /* Send the SYN next time around. */ +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$01 + ldy #$1A + sta (sreg),y +; +; conn->rto = UIP_RTO; +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$03 + ldy #$18 + sta (sreg),y +; +; conn->sa = 0; +; + tay + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$00 + ldy #$16 + sta (sreg),y +; +; conn->sv = 16; /* Initial value of the RTT variance. */ +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + lda #$10 + ldy #$17 + sta (sreg),y +; +; conn->lport = htons(lastport); +; + ldy #$05 + jsr pushwysp + lda _lastport + ldx _lastport+1 + jsr pushax + jsr _htons + ldy #$04 + jsr staxspidx +; +; conn->rport = rport; +; + dey + jsr ldaxysp + sta sreg + stx sreg+1 + ldy #$05 + jsr ldaxysp + ldy #$06 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_ipaddr_copy(&conn->ripaddr, ripaddr); +; + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + ldy #$07 + jsr ldaxysp + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + ldy #$03 + jsr ldaxysp + sta sreg + stx sreg+1 + ldy #$07 + jsr ldaxysp + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; return conn; +; + jsr ldaxysp +; +; } +; + jmp incsp8 + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_send (__near__ const void*, int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_send: near + +.segment "CODE" + +; +; if(len > 0) { +; + jsr pushw0sp + lda #$01 + jsr tosgea0 + jeq incsp4 +; +; uip_slen = len; +; + jsr ldax0sp + sta _uip_slen + stx _uip_slen+1 +; +; if(data != uip_sappdata) { +; + ldy #$05 + jsr pushwysp + lda _uip_sappdata + ldx _uip_sappdata+1 + jsr tosicmp + jeq incsp4 +; +; memcpy(uip_sappdata, (data), uip_slen); +; + lda _uip_sappdata + ldx _uip_sappdata+1 + jsr pushax + ldy #$07 + jsr pushwysp + lda _uip_slen + ldx _uip_slen+1 + jsr _memcpy +; +; } +; + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; __near__ struct uip_udp_conn* __near__ uip_udp_new (__near__ unsigned int[2]*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_udp_new: near + +.segment "CODE" + +; +; again: +; + jsr decsp2 +; +; ++lastport; +; +L0151: inc _lastport + bne L0153 + inc _lastport+1 +; +; if(lastport >= 32000) { +; +L0153: ldx _lastport+1 + cpx #$7D + bcc L0154 +; +; lastport = 4096; +; + ldx #$10 + lda #$00 + sta _lastport + stx _lastport+1 +; +; for(c = 0; c < UIP_UDP_CONNS; ++c) { +; +L0154: lda #$00 + sta _c +L0158: lda _c + cmp #$01 + bcs L0159 +; +; if(uip_udp_conns[c].lport == htons(lastport)) { +; + lda _c + jsr pusha0 + lda #$0B + jsr tosmula0 + clc + adc #<(_uip_udp_conns) + tay + txa + adc #>(_uip_udp_conns) + tax + tya + ldy #$05 + jsr pushwidx + lda _lastport + ldx _lastport+1 + jsr pushax + jsr _htons + jsr tosicmp +; +; goto again; +; + beq L0151 +; +; for(c = 0; c < UIP_UDP_CONNS; ++c) { +; + inc _c + jmp L0158 +; +; conn = 0; +; +L0159: ldx #$00 + txa + jsr stax0sp +; +; for(c = 0; c < UIP_UDP_CONNS; ++c) { +; + sta _c +L0166: lda _c + cmp #$01 + bcs L0167 +; +; if(uip_udp_conns[c].lport == 0) { +; + lda _c + jsr pusha0 + lda #$0B + jsr tosmula0 + clc + adc #<(_uip_udp_conns) + tay + txa + adc #>(_uip_udp_conns) + tax + tya + ldy #$05 + jsr ldaxidx + cpx #$00 + bne L0168 + cmp #$00 + bne L0168 +; +; conn = &uip_udp_conns[c]; +; + lda _c + jsr pusha0 + lda #$0B + jsr tosmula0 + clc + adc #<(_uip_udp_conns) + tay + txa + adc #>(_uip_udp_conns) + tax + tya + jsr stax0sp +; +; break; +; + jmp L0167 +; +; for(c = 0; c < UIP_UDP_CONNS; ++c) { +; +L0168: inc _c + jmp L0166 +; +; if(conn == 0) { +; +L0167: ldy #$00 + lda (sp),y + iny + ora (sp),y + bne L0175 +; +; return 0; +; + tax + jmp incsp6 +; +; conn->lport = HTONS(lastport); +; +L0175: jsr ldax0sp + sta ptr1 + stx ptr1+1 + ldx _lastport + stx sreg+1 + ldx #$00 + lda _lastport+1 + sta sreg + txa + ora sreg+1 + tax + lda sreg + ldy #$04 + sta (ptr1),y + iny + txa + sta (ptr1),y +; +; conn->rport = rport; +; + jsr ldax0sp + sta sreg + stx sreg+1 + ldy #$03 + jsr ldaxysp + ldy #$06 + sta (sreg),y + iny + txa + sta (sreg),y +; +; if(ripaddr == NULL) { +; + ldy #$04 + lda (sp),y + iny + ora (sp),y + bne L0184 +; +; memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$03 +L087D: sta (sreg),y + dey + bpl L087D +; +; } else { +; + jmp L018E +; +; uip_ipaddr_copy(&conn->ripaddr, ripaddr); +; +L0184: jsr ldax0sp + sta sreg + stx sreg+1 + ldy #$05 + jsr ldaxysp + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + jsr ldax0sp + sta sreg + stx sreg+1 + ldy #$05 + jsr ldaxysp + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; conn->ttl = UIP_TTL; +; +L018E: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$40 + ldy #$08 + sta (sreg),y +; +; return conn; +; + jsr ldax0sp +; +; } +; + jmp incsp6 + +.endproc + +; --------------------------------------------------------------- +; unsigned int __near__ htons (unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _htons: near + +.segment "CODE" + +; +; return HTONS(val); +; + ldy #$00 + lda (sp),y + tax + stx sreg+1 + ldx #$00 + iny + lda (sp),y + sta sreg + txa + ora sreg+1 + tax + lda sreg +; +; } +; + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_process (unsigned char) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_process: near + +.segment "CODE" + +; +; register struct uip_conn *uip_connr = uip_conn; +; + lda _uip_conn + ldx _uip_conn+1 + jsr pushax +; +; if(flag == UIP_UDP_SEND_CONN) { +; + ldy #$02 + lda (sp),y + cmp #$04 +; +; goto udp_send; +; + jeq L01D6 +; +; uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; +; + lda #<(_uip_buf+40) + ldx #>(_uip_buf+40) + sta _uip_appdata + stx _uip_appdata+1 + sta _uip_sappdata + stx _uip_sappdata+1 +; +; if(flag == UIP_POLL_REQUEST) { +; + lda (sp),y + cmp #$03 + bne L01DC +; +; if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$0F + cmp #$03 + jne L01EA +; +; !uip_outstanding(uip_connr)) { +; + jsr ldax0sp + ldy #$11 + jsr ldaxidx + stx tmp1 + ora tmp1 + jne L01EA +; +; uip_flags = UIP_POLL; +; + lda #$08 + sta _uip_flags +; +; goto appsend; +; + jmp L0888 +; +; } else if(flag == UIP_TIMER) { +; +L01DC: lda (sp),y + cmp #$02 + jne L01EC +; +; if(++iss[3] == 0) { +; + inc _iss+3 + lda _iss+3 + bne L01F4 +; +; if(++iss[2] == 0) { +; + inc _iss+2 + lda _iss+2 + bne L01F4 +; +; if(++iss[1] == 0) { +; + inc _iss+1 + lda _iss+1 + bne L01F4 +; +; ++iss[0]; +; + inc _iss +; +; uip_len = 0; +; +L01F4: lda #$00 + sta _uip_len + sta _uip_len+1 +; +; uip_slen = 0; +; + sta _uip_slen + sta _uip_slen+1 +; +; if(uip_connr->tcpstateflags == UIP_TIME_WAIT || +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$07 + beq L01FE +; +; uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$05 + bne L01FD +; +; ++(uip_connr->timer); +; +L01FE: jsr ldax0sp + sta ptr1 + stx ptr1+1 + ldy #$1A + lda #$01 + clc + adc (ptr1),y + sta (ptr1),y +; +; if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { +; + jsr ldax0sp + ldy #$1A + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$78 + jne L01EA +; +; uip_connr->tcpstateflags = UIP_CLOSED; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; } else if(uip_connr->tcpstateflags != UIP_CLOSED) { +; + jmp L01EA +L01FD: jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + jeq L01EA +; +; if(uip_outstanding(uip_connr)) { +; + jsr ldax0sp + ldy #$10 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + iny + ora (ptr1),y + jeq L0209 +; +; if(uip_connr->timer-- == 0) { +; + jsr ldax0sp + sta sreg + stx sreg+1 + ldy #$1A + sta ptr1 + stx ptr1+1 + lda (ptr1),y + pha + sec + sbc #$01 + sta (sreg),y + pla + jne L01EA +; +; if(uip_connr->nrtx == UIP_MAXRTX || +; + jsr ldax0sp + ldy #$1B + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$08 + beq L0210 +; +; ((uip_connr->tcpstateflags == UIP_SYN_SENT || +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$02 + beq L0212 +; +; uip_connr->tcpstateflags == UIP_SYN_RCVD) && +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$01 + bne L020F +; +; uip_connr->nrtx == UIP_MAXSYNRTX)) { +; +L0212: jsr ldax0sp + ldy #$1B + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$05 + bne L020F +; +; uip_connr->tcpstateflags = UIP_CLOSED; +; +L0210: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; uip_flags = UIP_TIMEDOUT; +; + lda #$80 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; BUF->flags = TCP_RST | TCP_ACK; +; + lda #$14 +; +; goto tcp_send_nodata; +; + jmp L0889 +; +; uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4? +; +L020F: jsr pushw0sp + jsr push3 + ldy #$05 + jsr ldaxysp + ldy #$1B + sta ptr1 + stx ptr1+1 + lda (ptr1),y + cmp #$05 +; +; 4: +; + bcc L0224 + lda #$04 +; +; uip_connr->nrtx); +; + jmp L0226 +L0224: ldy #$05 + jsr ldaxysp + ldy #$1B + sta ptr1 + stx ptr1+1 + lda (ptr1),y +L0226: jsr tosaslax + ldy #$1A + jsr staspidx +; +; ++(uip_connr->nrtx); +; + jsr ldax0sp + sta ptr1 + stx ptr1+1 + ldy #$1B + lda #$01 + clc + adc (ptr1),y + sta (ptr1),y +; +; switch(uip_connr->tcpstateflags & UIP_TS_MASK) { +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$0F +; +; } +; + cmp #$01 + jeq L0230 + cmp #$02 + beq L0232 + cmp #$03 + beq L0239 + cmp #$04 + jeq L0244 + cmp #$06 + jeq L0244 + cmp #$08 + jeq L0244 + jmp L01EA +; +; BUF->flags = 0; +; +L0232: lda #$00 +; +; goto tcp_send_syn; +; + jmp L088A +; +; uip_flags = UIP_REXMIT; +; +L0239: lda #$04 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; goto apprexmit; +; + jmp L023D +; +; } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { +; +L0209: jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$0F + cmp #$03 + jne L01EA +; +; uip_flags = UIP_POLL; +; + lda #$08 + sta _uip_flags +; +; goto appsend; +; + jmp L0888 +; +; if(flag == UIP_UDP_TIMER) { +; +L01EC: lda (sp),y + cmp #$05 + bne L024D +; +; if(uip_udp_conn->lport != 0) { +; + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$05 + jsr ldaxidx + cpx #$00 + bne L0895 + cmp #$00 + jeq L01EA +; +; uip_conn = NULL; +; +L0895: lda #$00 + sta _uip_conn + sta _uip_conn+1 +; +; uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; +; + lda #<(_uip_buf+28) + ldx #>(_uip_buf+28) + sta _uip_appdata + stx _uip_appdata+1 + sta _uip_sappdata + stx _uip_sappdata+1 +; +; uip_len = uip_slen = 0; +; + lda #$00 + sta _uip_slen + sta _uip_slen+1 + sta _uip_len + sta _uip_len+1 +; +; uip_flags = UIP_POLL; +; + lda #$08 + sta _uip_flags +; +; goto udp_send; +; + jmp L088B +; +; if(BUF->vhl != 0x45) { /* IP version and header length. */ +; +L024D: lda _uip_buf + cmp #$45 +; +; goto drop; +; + jne L01EA +; +; if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) { +; + ldx _uip_buf+2 + lda #$00 + clc + adc _uip_buf+3 + bcc L087E + inx +L087E: jsr pushax + lda _uip_len + ldx _uip_len+1 + jsr tosicmp + beq L0891 + jcs L01EA +; +; uip_len = (BUF->len[0] << 8) + BUF->len[1]; +; +L0891: ldx _uip_buf+2 + lda #$00 + clc + adc _uip_buf+3 + bcc L087F + inx +L087F: sta _uip_len + stx _uip_len+1 +; +; if((BUF->ipoffset[0] & 0x3f) != 0 || +; + lda _uip_buf+6 + and #$3F + jne L01EA +; +; BUF->ipoffset[1] != 0) { +; + lda _uip_buf+7 + jne L01EA +; +; if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) { +; + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr pushw + lda #<(_all_zeroes_addr) + ldx #>(_all_zeroes_addr) + jsr ldaxi + jsr tosicmp + bne L0282 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + ldy #$03 + jsr pushwidx + lda #<(_all_zeroes_addr) + ldx #>(_all_zeroes_addr) + ldy #$03 + jsr ldaxidx + jsr tosicmp + beq L0290 +; +; if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) { +; +L0282: lda #<(_uip_buf+16) + ldx #>(_uip_buf+16) + jsr pushw + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr ldaxi + jsr tosicmp + bne L0299 + lda #<(_uip_buf+16) + ldx #>(_uip_buf+16) + ldy #$03 + jsr pushwidx + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + ldy #$03 + jsr ldaxidx + jsr tosicmp + beq L0292 +L0299: lda #$00 + jmp L02A0 +L0292: lda #$01 +L02A0: jsr bnega +; +; goto drop; +; + jne L01EA +; +; checksum. */ +; +L0290: jsr _uip_ipchksum + cpx #$FF + jne L01EA + cmp #$FF +; +; goto drop; +; + jne L01EA +; +; processing. */ +; + lda _uip_buf+9 + cmp #$06 +; +; goto tcp_input; +; + jeq L02A8 +; +; if(BUF->proto == UIP_PROTO_UDP) { +; + lda _uip_buf+9 + cmp #$11 +; +; goto udp_input; +; + jeq L02AD +; +; here. */ +; + lda _uip_buf+9 + cmp #$01 +; +; goto drop; +; + jne L01EA +; +; if(ICMPBUF->type != ICMP_ECHO) { +; + lda _uip_buf+20 + cmp #$08 +; +; goto drop; +; + jne L01EA +; +; ICMPBUF->type = ICMP_ECHO_REPLY; +; + lda #$00 + sta _uip_buf+20 +; +; if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) { +; + lda _uip_buf+22+1 + cmp #$FF + bne L02C7 + lda _uip_buf+22 + cmp #$F7 +L02C7: bcc L02BA +; +; ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1; +; + lda #$09 +; +; } else { +; + jmp L089F +; +; ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8); +; +L02BA: lda #$08 +L089F: clc + adc _uip_buf+22 + sta _uip_buf+22 + bcc L02E0 + inc _uip_buf+22+1 +; +; uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); +; +L02E0: lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); +; + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; goto send; +; + jmp L030D +; +; uip_len = uip_len - UIP_IPUDPH_LEN; +; +L02AD: lda _uip_len + ldx _uip_len+1 + ldy #$1C + jsr decaxy + sta _uip_len + stx _uip_len+1 +; +; for(uip_udp_conn = &uip_udp_conns[0]; +; + lda #<(_uip_udp_conns) + sta _uip_udp_conn + lda #>(_uip_udp_conns) + sta _uip_udp_conn+1 +; +; uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; +; +L0311: lda _uip_udp_conn + ldx _uip_udp_conn+1 + jsr pushax + lda #<(_uip_udp_conns+11) + ldx #>(_uip_udp_conns+11) + jsr tosicmp + jcs L01EA +; +; if(uip_udp_conn->lport != 0 && +; + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$05 + jsr ldaxidx + cpx #$00 + bne L0896 + cmp #$00 + jeq L0313 +; +; UDPBUF->destport == uip_udp_conn->lport && +; +L0896: lda _uip_buf+22 + ldx _uip_buf+22+1 + jsr pushax + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$05 + jsr ldaxidx + jsr tosicmp + jne L0313 +; +; (uip_udp_conn->rport == 0 || +; + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$07 + jsr ldaxidx + cpx #$00 + bne L0897 + cmp #$00 + beq L0322 +; +; UDPBUF->srcport == uip_udp_conn->rport) && +; +L0897: lda _uip_buf+20 + ldx _uip_buf+20+1 + jsr pushax + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$07 + jsr ldaxidx + jsr tosicmp + jne L0313 +; +; (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) || +; +L0322: lda _uip_udp_conn + ldx _uip_udp_conn+1 + jsr pushw + lda #<(_all_zeroes_addr) + ldx #>(_all_zeroes_addr) + jsr ldaxi + jsr tosicmp + bne L0885 + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$03 + jsr pushwidx + lda #<(_all_zeroes_addr) + ldx #>(_all_zeroes_addr) + ldy #$03 + jsr ldaxidx + jsr tosicmp + beq L034F +; +; uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) || +; +L0885: lda _uip_udp_conn + ldx _uip_udp_conn+1 + jsr pushw + lda #<(_all_ones_addr) + ldx #>(_all_ones_addr) + jsr ldaxi + jsr tosicmp + bne L0886 + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$03 + jsr pushwidx + lda #<(_all_ones_addr) + ldx #>(_all_ones_addr) + ldy #$03 + jsr ldaxidx + jsr tosicmp + beq L034F +; +; uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) { +; +L0886: lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + jsr pushw + lda _uip_udp_conn + ldx _uip_udp_conn+1 + jsr ldaxi + jsr tosicmp + bne L0313 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + ldy #$03 + jsr pushwidx + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$03 + jsr ldaxidx + jsr tosicmp + beq L034F +; +; ++uip_udp_conn) { +; +L0313: lda #$0B + clc + adc _uip_udp_conn + sta _uip_udp_conn + jcc L0311 + inc _uip_udp_conn+1 + jmp L0311 +; +; uip_conn = NULL; +; +L034F: lda #$00 + sta _uip_conn + sta _uip_conn+1 +; +; uip_flags = UIP_NEWDATA; +; + lda #$02 + sta _uip_flags +; +; uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; +; + lda #<(_uip_buf+28) + ldx #>(_uip_buf+28) + sta _uip_appdata + stx _uip_appdata+1 + sta _uip_sappdata + stx _uip_sappdata+1 +; +; uip_slen = 0; +; + lda #$00 + sta _uip_slen + sta _uip_slen+1 +; +; UIP_UDP_APPCALL(); +; +L088B: jsr _resolv_appcall +; +; if(uip_slen == 0) { +; +L01D6: lda _uip_slen + ora _uip_slen+1 +; +; goto drop; +; + jeq L01EA +; +; uip_len = uip_slen + UIP_IPUDPH_LEN; +; + lda _uip_slen + ldx _uip_slen+1 + ldy #$1C + jsr incaxy + sta _uip_len + stx _uip_len+1 +; +; BUF->len[0] = (uip_len >> 8); +; + lda _uip_len+1 + sta _uip_buf+2 +; +; BUF->len[1] = (uip_len & 0xff); +; + lda _uip_len + sta _uip_buf+3 +; +; BUF->ttl = uip_udp_conn->ttl; +; + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$08 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+8 +; +; BUF->proto = UIP_PROTO_UDP; +; + lda #$11 + sta _uip_buf+9 +; +; UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN); +; + lda _uip_slen + clc + adc #$08 + tax + lda #$00 + jsr pushax + lda _uip_slen + ldx _uip_slen+1 + jsr incax8 + txa + ldx #$00 + jsr tosorax + sta _uip_buf+24 + stx _uip_buf+24+1 +; +; UDPBUF->udpchksum = 0; +; + lda #$00 + sta _uip_buf+26 + sta _uip_buf+26+1 +; +; BUF->srcport = uip_udp_conn->lport; +; + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$05 + jsr ldaxidx + sta _uip_buf+20 + stx _uip_buf+20+1 +; +; BUF->destport = uip_udp_conn->rport; +; + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$07 + jsr ldaxidx + sta _uip_buf+22 + stx _uip_buf+22+1 +; +; uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); +; + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr); +; + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + lda _uip_udp_conn + ldx _uip_udp_conn+1 + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + lda _uip_udp_conn + ldx _uip_udp_conn+1 + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN]; +; + lda #<(_uip_buf+40) + sta _uip_appdata + lda #>(_uip_buf+40) + sta _uip_appdata+1 +; +; goto ip_send_nolen; +; + jmp L03B9 +; +; checksum. */ +; +L02A8: jsr _uip_tcpchksum + cpx #$FF + jne L01EA + cmp #$FF +; +; goto drop; +; + jne L01EA +; +; for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; +; + lda #<(_uip_conns) + ldx #>(_uip_conns) + jsr stax0sp +L03BD: jsr pushw0sp + lda #<(_uip_conns) + ldx #>(_uip_conns) + jsr tosicmp + beq L0892 + bcs L03BE +; +; if(uip_connr->tcpstateflags != UIP_CLOSED && +; +L0892: jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + beq L03BF +; +; BUF->destport == uip_connr->lport && +; + lda _uip_buf+22 + ldx _uip_buf+22+1 + jsr pushax + ldy #$03 + jsr ldaxysp + ldy #$05 + jsr ldaxidx + jsr tosicmp + bne L03BF +; +; BUF->srcport == uip_connr->rport && +; + lda _uip_buf+20 + ldx _uip_buf+20+1 + jsr pushax + ldy #$03 + jsr ldaxysp + ldy #$07 + jsr ldaxidx + jsr tosicmp + bne L03BF +; +; uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) { +; + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + jsr pushw + ldy #$03 + jsr ldaxysp + jsr ldaxi + jsr tosicmp + bne L03BF + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + ldy #$03 + jsr pushwidx + ldy #$03 + jsr ldaxysp + ldy #$03 + jsr ldaxidx + jsr tosicmp + jeq L03DE +; +; ++uip_connr) { +; +L03BF: ldx #$00 + lda #$23 + jsr addeq0sp + jmp L03BD +; +; if((BUF->flags & TCP_CTL) != TCP_SYN) { +; +L03BE: lda _uip_buf+33 + and #$3F + cmp #$02 +; +; goto reset; +; + bne L03E5 +; +; tmp16 = BUF->destport; +; + lda _uip_buf+22 + sta _tmp16 + lda _uip_buf+22+1 + sta _tmp16+1 +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; + lda #$00 + sta _c +L03EA: lda _c + cmp #$01 + bcs L03E5 +; +; if(tmp16 == uip_listenports[c]) +; + lda _tmp16 + ldx _tmp16+1 + jsr pushax + ldx #$00 + lda _c + jsr aslax1 + clc + adc #<(_uip_listenports) + tay + txa + adc #>(_uip_listenports) + tax + tya + jsr ldaxi + jsr tosicmp +; +; goto found_listen; +; + jeq L03F5 +; +; for(c = 0; c < UIP_LISTENPORTS; ++c) { +; + inc _c + jmp L03EA +; +; if(BUF->flags & TCP_RST) { +; +L03E5: lda _uip_buf+33 + and #$04 +; +; goto drop; +; + jne L01EA +; +; BUF->flags = TCP_RST | TCP_ACK; +; + lda #$14 + sta _uip_buf+33 +; +; uip_len = UIP_IPTCPH_LEN; +; + ldx #$00 + lda #$28 + sta _uip_len + stx _uip_len+1 +; +; BUF->tcpoffset = 5 << 4; +; + lda #$50 + sta _uip_buf+32 +; +; c = BUF->seqno[3]; +; + lda _uip_buf+27 + sta _c +; +; BUF->seqno[3] = BUF->ackno[3]; +; + lda _uip_buf+31 + sta _uip_buf+27 +; +; BUF->ackno[3] = c; +; + lda _c + sta _uip_buf+31 +; +; c = BUF->seqno[2]; +; + lda _uip_buf+26 + sta _c +; +; BUF->seqno[2] = BUF->ackno[2]; +; + lda _uip_buf+30 + sta _uip_buf+26 +; +; BUF->ackno[2] = c; +; + lda _c + sta _uip_buf+30 +; +; c = BUF->seqno[1]; +; + lda _uip_buf+25 + sta _c +; +; BUF->seqno[1] = BUF->ackno[1]; +; + lda _uip_buf+29 + sta _uip_buf+25 +; +; BUF->ackno[1] = c; +; + lda _c + sta _uip_buf+29 +; +; c = BUF->seqno[0]; +; + lda _uip_buf+24 + sta _c +; +; BUF->seqno[0] = BUF->ackno[0]; +; + lda _uip_buf+28 + sta _uip_buf+24 +; +; BUF->ackno[0] = c; +; + lda _c + sta _uip_buf+28 +; +; if(++BUF->ackno[3] == 0) { +; + inc _uip_buf+31 + lda _uip_buf+31 + bne L044D +; +; if(++BUF->ackno[2] == 0) { +; + inc _uip_buf+30 + lda _uip_buf+30 + bne L044D +; +; if(++BUF->ackno[1] == 0) { +; + inc _uip_buf+29 + lda _uip_buf+29 + bne L044D +; +; ++BUF->ackno[0]; +; + inc _uip_buf+28 +; +; tmp16 = BUF->srcport; +; +L044D: lda _uip_buf+20 + sta _tmp16 + lda _uip_buf+20+1 + sta _tmp16+1 +; +; BUF->srcport = BUF->destport; +; + lda _uip_buf+22 + sta _uip_buf+20 + lda _uip_buf+22+1 + sta _uip_buf+20+1 +; +; BUF->destport = tmp16; +; + lda _tmp16 + sta _uip_buf+22 + lda _tmp16+1 + sta _uip_buf+22+1 +; +; uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); +; + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); +; + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; goto tcp_send_noconn; +; + jmp L049A +; +; uip_connr = 0; +; +L03F5: ldx #$00 + txa + jsr stax0sp +; +; for(c = 0; c < UIP_CONNS; ++c) { +; + sta _c +L049D: lda _c + cmp #$01 + jcs L049E +; +; if(uip_conns[c].tcpstateflags == UIP_CLOSED) { +; + lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + sta ptr1 + txa + adc #>(_uip_conns) + sta ptr1+1 + ldy #$19 + lda (ptr1),y + bne L04A5 +; +; uip_connr = &uip_conns[c]; +; + lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + tay + txa + adc #>(_uip_conns) + tax + tya + jsr stax0sp +; +; break; +; + jmp L049E +; +; if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { +; +L04A5: lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + sta ptr1 + txa + adc #>(_uip_conns) + sta ptr1+1 + ldy #$19 + lda (ptr1),y + cmp #$07 + bne L049F +; +; if(uip_connr == 0 || +; + ldy #$00 + lda (sp),y + iny + ora (sp),y + beq L04AF +; +; uip_conns[c].timer > uip_connr->timer) { +; + lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + sta ptr1 + txa + adc #>(_uip_conns) + sta ptr1+1 + ldy #$1A + lda (ptr1),y + jsr pusha0 + ldy #$03 + jsr ldaxysp + ldy #$1A + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr tosicmp + beq L049F + bcc L049F +; +; uip_connr = &uip_conns[c]; +; +L04AF: lda _c + jsr pusha0 + lda #$23 + jsr tosmula0 + clc + adc #<(_uip_conns) + tay + txa + adc #>(_uip_conns) + tax + tya + jsr stax0sp +; +; for(c = 0; c < UIP_CONNS; ++c) { +; +L049F: inc _c + jmp L049D +; +; if(uip_connr == 0) { +; +L049E: ldy #$00 + lda (sp),y + iny + ora (sp),y +; +; goto drop; +; + jeq L01EA +; +; uip_conn = uip_connr; +; + jsr ldax0sp + sta _uip_conn + stx _uip_conn+1 +; +; uip_connr->rto = uip_connr->timer = UIP_RTO; +; + jsr ldax0sp + sta ptr1 + stx ptr1+1 + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$03 + ldy #$1A + sta (sreg),y + ldy #$18 + sta (ptr1),y +; +; uip_connr->sa = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$16 + sta (sreg),y +; +; uip_connr->sv = 4; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$04 + ldy #$17 + sta (sreg),y +; +; uip_connr->nrtx = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1B + sta (sreg),y +; +; uip_connr->lport = BUF->destport; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+22 + ldx _uip_buf+22+1 + ldy #$04 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_connr->rport = BUF->srcport; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+20 + ldx _uip_buf+20+1 + ldy #$06 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr); +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + jsr ldax0sp + sta sreg + stx sreg+1 + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_connr->tcpstateflags = UIP_SYN_RCVD; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$01 + ldy #$19 + sta (sreg),y +; +; uip_connr->snd_nxt[0] = iss[0]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _iss + ldy #$0C + sta (sreg),y +; +; uip_connr->snd_nxt[1] = iss[1]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _iss+1 + ldy #$0D + sta (sreg),y +; +; uip_connr->snd_nxt[2] = iss[2]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _iss+2 + ldy #$0E + sta (sreg),y +; +; uip_connr->snd_nxt[3] = iss[3]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _iss+3 + ldy #$0F + sta (sreg),y +; +; uip_connr->len = 1; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$01 + ldy #$10 + sta (sreg),y + iny + lda #$00 + sta (sreg),y +; +; uip_connr->rcv_nxt[3] = BUF->seqno[3]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+27 + ldy #$0B + sta (sreg),y +; +; uip_connr->rcv_nxt[2] = BUF->seqno[2]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+26 + ldy #$0A + sta (sreg),y +; +; uip_connr->rcv_nxt[1] = BUF->seqno[1]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+25 + ldy #$09 + sta (sreg),y +; +; uip_connr->rcv_nxt[0] = BUF->seqno[0]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+24 + ldy #$08 + sta (sreg),y +; +; uip_add_rcv_nxt(1); +; + jsr push1 + jsr _uip_add_rcv_nxt +; +; if((BUF->tcpoffset & 0xf0) > 0x50) { +; + lda _uip_buf+32 + and #$F0 + cmp #$51 + jcc L0230 +; +; for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { +; + lda #$00 +L088C: sta _c +L0514: lda _c + jsr pusha0 + lda _uip_buf+32 + jsr asrax4 + jsr decax5 + jsr aslax2 + jsr tosicmp + jcs L0230 +; +; opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; +; + ldx #$00 + lda _c + ldy #$28 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + sta _opt +; +; if(opt == TCP_OPT_END) { +; + lda _opt +; +; break; +; + jeq L0230 +; +; } else if(opt == TCP_OPT_NOOP) { +; + lda _opt + cmp #$01 + bne L0526 +; +; ++c; +; + inc _c +; +; } else if(opt == TCP_OPT_MSS && +; + jmp L0514 +L0526: lda _opt + cmp #$02 + jne L052A +; +; uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { +; + ldx #$00 + lda _c + ldy #$29 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + cmp #$04 + bne L052A +; +; tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | +; + ldx #$00 + lda _c + ldy #$2A + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + tax + tya +; +; (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; +; + jsr pushax + tax + lda _c + ldy #$2B + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + ldx #$00 + lda (ptr1),y + jsr tosorax + sta _tmp16 + stx _tmp16+1 +; +; uip_connr->initialmss = uip_connr->mss = +; + jsr pushw0sp + ldy #$05 +; +; tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; +; + jsr pushwysp + lda _tmp16+1 + cmp #$00 + bne L053C + lda _tmp16 + cmp #$79 +L053C: bcc L053D + ldx #$00 + lda #$78 + jmp L0541 +L053D: lda _tmp16 + ldx _tmp16+1 +L0541: ldy #$12 + jsr staxspidx + ldy #$14 + jsr staxspidx +; +; break; +; + jmp L0230 +; +; if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { +; +L052A: ldx #$00 + lda _c + ldy #$29 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y +; +; break; +; + beq L0230 +; +; c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; +; + ldx #$00 + lda _c + ldy #$29 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + clc + adc _c +; +; } +; + jmp L088C +; +; BUF->flags = TCP_ACK; +; +L0230: lda #$10 +L088A: sta _uip_buf+33 +; +; BUF->flags |= TCP_SYN; +; + ora #$02 + sta _uip_buf+33 +; +; BUF->optdata[0] = TCP_OPT_MSS; +; + lda #$02 + sta _uip_buf+40 +; +; BUF->optdata[1] = TCP_OPT_MSS_LEN; +; + lda #$04 + sta _uip_buf+41 +; +; BUF->optdata[2] = (UIP_TCP_MSS) / 256; +; + lda #$00 + sta _uip_buf+42 +; +; BUF->optdata[3] = (UIP_TCP_MSS) & 255; +; + lda #$78 + sta _uip_buf+43 +; +; uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; +; + ldx #$00 + lda #$2C + sta _uip_len + stx _uip_len+1 +; +; BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; +; + lda #$60 +; +; goto tcp_send; +; + jmp L088D +; +; uip_conn = uip_connr; +; +L03DE: jsr ldax0sp + sta _uip_conn + stx _uip_conn+1 +; +; uip_flags = 0; +; + lda #$00 + sta _uip_flags +; +; if(BUF->flags & TCP_RST) { +; + lda _uip_buf+33 + and #$04 + beq L057D +; +; uip_connr->tcpstateflags = UIP_CLOSED; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; uip_flags = UIP_ABORT; +; + lda #$20 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; goto drop; +; + jmp L01EA +; +; c = (BUF->tcpoffset >> 4) << 2; +; +L057D: tax + lda _uip_buf+32 + jsr asrax4 + asl a + asl a + sta _c +; +; uip_len = uip_len - c - UIP_IPH_LEN; +; + lda _uip_len + ldx _uip_len+1 + jsr pushax + lda _c + jsr tossuba0 + ldy #$14 + jsr decaxy + sta _uip_len + stx _uip_len+1 +; +; if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$0F + cmp #$02 + bne L0593 +; +; ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) { +; + lda _uip_buf+33 + and #$3F + cmp #$12 + beq L058F +L0593: lda #$00 + jmp L059A +L058F: lda #$01 +L059A: jsr bnega + jeq L058D +; +; if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) && +; + lda _uip_len + ora _uip_len+1 + bne L059D + lda _uip_buf+33 + and #$03 + beq L058D +; +; (BUF->seqno[0] != uip_connr->rcv_nxt[0] || +; +L059D: lda _uip_buf+24 + jsr pusha0 + ldy #$03 + jsr ldaxysp + ldy #$08 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr tosicmp + jne L05BA +; +; BUF->seqno[1] != uip_connr->rcv_nxt[1] || +; + lda _uip_buf+25 + jsr pusha0 + ldy #$03 + jsr ldaxysp + ldy #$09 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr tosicmp + jne L05BA +; +; BUF->seqno[2] != uip_connr->rcv_nxt[2] || +; + lda _uip_buf+26 + jsr pusha0 + ldy #$03 + jsr ldaxysp + ldy #$0A + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr tosicmp + jne L05BA +; +; BUF->seqno[3] != uip_connr->rcv_nxt[3])) { +; + lda _uip_buf+27 + jsr pusha0 + ldy #$03 + jsr ldaxysp + ldy #$0B + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr tosicmp + jne L05BA +; +; if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) { +; +L058D: lda _uip_buf+33 + and #$10 + jeq L05C7 + jsr ldax0sp + ldy #$10 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + iny + ora (ptr1),y + jeq L05C7 +; +; uip_add32(uip_connr->snd_nxt, uip_connr->len); +; + jsr ldax0sp + ldy #$0C + jsr incaxy + jsr pushax + ldy #$03 + jsr ldaxysp + ldy #$11 + jsr pushwidx + jsr _uip_add32 +; +; if(BUF->ackno[0] == uip_acc32[0] && +; + lda _uip_buf+28 + jsr pusha0 + lda _uip_acc32 + jsr tosicmp + jne L05C7 +; +; BUF->ackno[1] == uip_acc32[1] && +; + lda _uip_buf+29 + jsr pusha0 + lda _uip_acc32+1 + jsr tosicmp + jne L05C7 +; +; BUF->ackno[2] == uip_acc32[2] && +; + lda _uip_buf+30 + jsr pusha0 + lda _uip_acc32+2 + jsr tosicmp + jne L05C7 +; +; BUF->ackno[3] == uip_acc32[3]) { +; + lda _uip_buf+31 + jsr pusha0 + lda _uip_acc32+3 + jsr tosicmp + jne L05C7 +; +; uip_connr->snd_nxt[0] = uip_acc32[0]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_acc32 + ldy #$0C + sta (sreg),y +; +; uip_connr->snd_nxt[1] = uip_acc32[1]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_acc32+1 + ldy #$0D + sta (sreg),y +; +; uip_connr->snd_nxt[2] = uip_acc32[2]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_acc32+2 + ldy #$0E + sta (sreg),y +; +; uip_connr->snd_nxt[3] = uip_acc32[3]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_acc32+3 + ldy #$0F + sta (sreg),y +; +; if(uip_connr->nrtx == 0) { +; + jsr ldax0sp + ldy #$1B + sta ptr1 + stx ptr1+1 + lda (ptr1),y + jne L05EB +; +; m = uip_connr->rto - uip_connr->timer; +; + jsr decsp1 + ldy #$02 + jsr ldaxysp + ldy #$18 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + jsr pusha0 + ldy #$04 + jsr ldaxysp + ldy #$1A + sta ptr1 + stx ptr1+1 + lda (ptr1),y + jsr tossuba0 + ldy #$00 + sta (sp),y +; +; m = m - (uip_connr->sa >> 3); +; + ldx #$00 + lda (sp),y + bpl L05F1 + dex +L05F1: jsr pushax + ldy #$04 + jsr ldaxysp + ldy #$16 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr asrax3 + jsr tossubax + ldy #$00 + sta (sp),y +; +; uip_connr->sa += m; +; + ldy #$02 + jsr ldaxysp + sta ptr2 + stx ptr2+1 + ldy #$16 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta sreg + ldy #$00 + lda (sp),y + clc + adc sreg + ldy #$16 + sta (ptr2),y +; +; if(m < 0) { +; + ldy #$00 + lda (sp),y + tax + bpl L05F6 +; +; m = -m; +; + ldx #$00 + lda (sp),y + bpl L05FB + dex +L05FB: jsr negax + sta (sp),y +; +; m = m - (uip_connr->sv >> 2); +; +L05F6: ldx #$00 + lda (sp),y + bpl L05FE + dex +L05FE: jsr pushax + ldy #$04 + jsr ldaxysp + ldy #$17 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr asrax2 + jsr tossubax + ldy #$00 + sta (sp),y +; +; uip_connr->sv += m; +; + ldy #$02 + jsr ldaxysp + sta ptr2 + stx ptr2+1 + ldy #$17 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta sreg + ldy #$00 + lda (sp),y + clc + adc sreg + ldy #$17 + sta (ptr2),y +; +; uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv; +; + ldy #$04 + jsr pushwysp + ldy #$04 + jsr ldaxysp + ldy #$16 + sta ptr1 + stx ptr1+1 + ldx #$00 + lda (ptr1),y + jsr asrax3 + sta sreg + ldy #$04 + jsr ldaxysp + ldy #$17 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + clc + adc sreg + iny + jsr staspidx +; +; } +; + jsr incsp1 +; +; uip_flags = UIP_ACKDATA; +; +L05EB: lda #$01 + sta _uip_flags +; +; uip_connr->timer = uip_connr->rto; +; + jsr ldax0sp + sta sreg + stx sreg+1 + jsr ldax0sp + ldy #$18 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + ldy #$1A + sta (sreg),y +; +; uip_connr->len = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$10 + sta (sreg),y + iny + sta (sreg),y +; +; switch(uip_connr->tcpstateflags & UIP_TS_MASK) { +; +L05C7: jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$0F +; +; goto drop; +; + cmp #$01 + beq L0610 + cmp #$02 + beq L0624 + cmp #$03 + jeq L0699 + cmp #$04 + jeq L0746 + cmp #$05 + jeq L076B + cmp #$06 + jeq L0784 + cmp #$07 + jeq L05BA + cmp #$08 + jeq L073D + jmp L01EA +; +; if(uip_flags & UIP_ACKDATA) { +; +L0610: lda _uip_flags + and #$01 + jeq L01EA +; +; uip_connr->tcpstateflags = UIP_ESTABLISHED; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$03 + ldy #$19 + sta (sreg),y +; +; uip_flags = UIP_CONNECTED; +; + lda #$40 + sta _uip_flags +; +; uip_connr->len = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$10 + sta (sreg),y + iny + sta (sreg),y +; +; if(uip_len > 0) { +; + lda _uip_len + ora _uip_len+1 + jeq L089D +; +; uip_flags |= UIP_NEWDATA; +; + lda _uip_flags + ora #$02 + sta _uip_flags +; +; uip_add_rcv_nxt(uip_len); +; + lda _uip_len + ldx _uip_len+1 + jsr pushax + jsr _uip_add_rcv_nxt +; +; goto appsend; +; + jmp L089D +; +; if((uip_flags & UIP_ACKDATA) && +; +L0624: lda _uip_flags + and #$01 + jeq L0625 +; +; (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { +; + lda _uip_buf+33 + and #$3F + cmp #$12 + jne L0625 +; +; if((BUF->tcpoffset & 0xf0) > 0x50) { +; + lda _uip_buf+32 + and #$F0 + cmp #$51 + jcc L0636 +; +; for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { +; + lda #$00 +L088E: sta _c +L0635: lda _c + jsr pusha0 + lda _uip_buf+32 + jsr asrax4 + jsr decax5 + jsr aslax2 + jsr tosicmp + jcs L0636 +; +; opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; +; + ldx #$00 + lda _c + ldy #$28 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + sta _opt +; +; if(opt == TCP_OPT_END) { +; + lda _opt +; +; break; +; + jeq L0636 +; +; } else if(opt == TCP_OPT_NOOP) { +; + lda _opt + cmp #$01 + bne L0647 +; +; ++c; +; + inc _c +; +; } else if(opt == TCP_OPT_MSS && +; + jmp L0635 +L0647: lda _opt + cmp #$02 + jne L064B +; +; uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { +; + ldx #$00 + lda _c + ldy #$29 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + cmp #$04 + bne L064B +; +; tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | +; + ldx #$00 + lda _c + ldy #$2A + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + tax + tya +; +; uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; +; + jsr pushax + tax + lda _c + ldy #$2B + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + ldx #$00 + lda (ptr1),y + jsr tosorax + sta _tmp16 + stx _tmp16+1 +; +; uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; +; + jsr pushw0sp + ldy #$05 + jsr pushwysp + lda _tmp16+1 + cmp #$00 + bne L065D + lda _tmp16 + cmp #$79 +L065D: bcc L065E + ldx #$00 + lda #$78 + jmp L0662 +L065E: lda _tmp16 + ldx _tmp16+1 +L0662: ldy #$12 + jsr staxspidx + ldy #$14 + jsr staxspidx +; +; break; +; + jmp L0636 +; +; if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { +; +L064B: ldx #$00 + lda _c + ldy #$29 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y +; +; break; +; + beq L0636 +; +; c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; +; + ldx #$00 + lda _c + ldy #$29 + jsr incaxy + clc + adc #<(_uip_buf) + sta ptr1 + txa + adc #>(_uip_buf) + sta ptr1+1 + ldy #$00 + lda (ptr1),y + clc + adc _c +; +; } +; + jmp L088E +; +; uip_connr->tcpstateflags = UIP_ESTABLISHED; +; +L0636: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$03 + ldy #$19 + sta (sreg),y +; +; uip_connr->rcv_nxt[0] = BUF->seqno[0]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+24 + ldy #$08 + sta (sreg),y +; +; uip_connr->rcv_nxt[1] = BUF->seqno[1]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+25 + ldy #$09 + sta (sreg),y +; +; uip_connr->rcv_nxt[2] = BUF->seqno[2]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+26 + ldy #$0A + sta (sreg),y +; +; uip_connr->rcv_nxt[3] = BUF->seqno[3]; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_buf+27 + ldy #$0B + sta (sreg),y +; +; uip_add_rcv_nxt(1); +; + jsr push1 + jsr _uip_add_rcv_nxt +; +; uip_flags = UIP_CONNECTED | UIP_NEWDATA; +; + lda #$42 + sta _uip_flags +; +; uip_connr->len = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$10 + sta (sreg),y + iny + sta (sreg),y +; +; uip_len = 0; +; + sta _uip_len + sta _uip_len+1 +; +; goto appsend; +; + jmp L089B +; +; uip_flags = UIP_ABORT; +; +L0625: lda #$20 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; uip_conn->tcpstateflags = UIP_CLOSED; +; + lda _uip_conn + sta sreg + lda _uip_conn+1 + sta sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; goto reset; +; + jmp L03E5 +; +; if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) { +; +L0699: lda _uip_buf+33 + and #$01 + beq L069A + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$10 + bne L069A +; +; if(uip_outstanding(uip_connr)) { +; + jsr ldax0sp + ldy #$10 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + iny + ora (ptr1),y +; +; goto drop; +; + jne L01EA +; +; uip_add_rcv_nxt(1 + uip_len); +; + lda _uip_len + ldx _uip_len+1 + jsr incax1 + jsr pushax + jsr _uip_add_rcv_nxt +; +; uip_flags |= UIP_CLOSE; +; + lda _uip_flags + ora #$10 + sta _uip_flags +; +; if(uip_len > 0) { +; + lda _uip_len + ora _uip_len+1 + beq L06A9 +; +; uip_flags |= UIP_NEWDATA; +; + lda _uip_flags + ora #$02 + sta _uip_flags +; +; UIP_APPCALL(); +; +L06A9: jsr _telnet_app +; +; uip_connr->len = 1; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$01 + ldy #$10 + sta (sreg),y + iny + lda #$00 + sta (sreg),y +; +; uip_connr->tcpstateflags = UIP_LAST_ACK; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$08 + ldy #$19 + sta (sreg),y +; +; uip_connr->nrtx = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1B + sta (sreg),y +; +; BUF->flags = TCP_FIN | TCP_ACK; +; +L0244: lda #$11 +; +; goto tcp_send_nodata; +; + jmp L0889 +; +; if((BUF->flags & TCP_URG) != 0) { +; +L069A: lda _uip_buf+33 + and #$20 + beq L06B9 +; +; uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]); +; + lda _uip_appdata + sta ptr1 + lda _uip_appdata+1 + sta ptr1+1 + ldx _uip_buf+38 + stx sreg+1 + ldx #$00 + lda _uip_buf+39 + sta sreg + txa + ora sreg+1 + tax + lda sreg + clc + adc ptr1 + sta ptr1 + txa + adc ptr1+1 + tax + lda ptr1 + sta _uip_appdata + stx _uip_appdata+1 +; +; uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1]; +; + ldx _uip_buf+38 + stx sreg+1 + ldx #$00 + lda _uip_buf+39 + sta sreg + txa + ora sreg+1 + tax + lda sreg + sec + eor #$FF + adc _uip_len + sta _uip_len + txa + eor #$FF + adc _uip_len+1 + sta _uip_len+1 +; +; if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) { +; +L06B9: lda _uip_len + ora _uip_len+1 + beq L06D3 + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$10 + bne L06D3 +; +; uip_flags |= UIP_NEWDATA; +; + lda _uip_flags + ora #$02 + sta _uip_flags +; +; uip_add_rcv_nxt(uip_len); +; + lda _uip_len + ldx _uip_len+1 + jsr pushax + jsr _uip_add_rcv_nxt +; +; tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1]; +; +L06D3: ldx _uip_buf+34 + lda #$00 + clc + adc _uip_buf+35 + bcc L0880 + inx +L0880: sta _tmp16 + stx _tmp16+1 +; +; if(tmp16 > uip_connr->initialmss || +; + jsr pushax + ldy #$03 + jsr ldaxysp + ldy #$15 + jsr ldaxidx + jsr tosicmp + beq L0894 + bcs L06E7 +; +; tmp16 == 0) { +; +L0894: lda _tmp16 + ora _tmp16+1 + bne L06E6 +; +; tmp16 = uip_connr->initialmss; +; +L06E7: jsr ldax0sp + ldy #$15 + jsr ldaxidx + sta _tmp16 + stx _tmp16+1 +; +; uip_connr->mss = tmp16; +; +L06E6: jsr ldax0sp + sta sreg + stx sreg+1 + lda _tmp16 + ldx _tmp16+1 + ldy #$12 + sta (sreg),y + iny + txa + sta (sreg),y +; +; if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) { +; + lda _uip_flags + and #$03 + jeq L01EA +; +; uip_slen = 0; +; +L089D: lda #$00 +L089B: sta _uip_slen + sta _uip_slen+1 +; +; UIP_APPCALL(); +; +L0888: jsr _telnet_app +; +; if(uip_flags & UIP_ABORT) { +; + lda _uip_flags + and #$20 + beq L06F4 +; +; uip_slen = 0; +; + lda #$00 + sta _uip_slen + sta _uip_slen+1 +; +; uip_connr->tcpstateflags = UIP_CLOSED; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; BUF->flags = TCP_RST | TCP_ACK; +; + lda #$14 +; +; goto tcp_send_nodata; +; + jmp L0889 +; +; if(uip_flags & UIP_CLOSE) { +; +L06F4: lda _uip_flags + and #$10 + beq L06FE +; +; uip_slen = 0; +; + lda #$00 + sta _uip_slen + sta _uip_slen+1 +; +; uip_connr->len = 1; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$01 + ldy #$10 + sta (sreg),y + iny + lda #$00 + sta (sreg),y +; +; uip_connr->tcpstateflags = UIP_FIN_WAIT_1; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$04 + ldy #$19 + sta (sreg),y +; +; uip_connr->nrtx = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1B + sta (sreg),y +; +; BUF->flags = TCP_FIN | TCP_ACK; +; + lda #$11 +; +; goto tcp_send_nodata; +; + jmp L0889 +; +; if(uip_slen > 0) { +; +L06FE: lda _uip_slen + ora _uip_slen+1 + beq L071E +; +; if((uip_flags & UIP_ACKDATA) != 0) { +; + lda _uip_flags + and #$01 + beq L070F +; +; uip_connr->len = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$10 + sta (sreg),y + iny + sta (sreg),y +; +; if(uip_connr->len == 0) { +; +L070F: jsr ldax0sp + ldy #$11 + jsr ldaxidx + cpx #$00 + bne L0715 + cmp #$00 + bne L0715 +; +; if(uip_slen > uip_connr->mss) { +; + lda _uip_slen + ldx _uip_slen+1 + jsr pushax + ldy #$03 + jsr ldaxysp + ldy #$13 + jsr ldaxidx + jsr tosicmp + bcc L0718 + beq L0718 +; +; uip_slen = uip_connr->mss; +; + jsr ldax0sp + ldy #$13 + jsr ldaxidx + sta _uip_slen + stx _uip_slen+1 +; +; uip_connr->len = uip_slen; +; +L0718: jsr ldax0sp + sta sreg + stx sreg+1 + lda _uip_slen + ldx _uip_slen+1 + ldy #$10 + sta (sreg),y + iny + txa + sta (sreg),y +; +; } else { +; + jmp L071E +; +; uip_slen = uip_connr->len; +; +L0715: jsr ldax0sp + ldy #$11 + jsr ldaxidx + sta _uip_slen + stx _uip_slen+1 +; +; uip_connr->nrtx = 0; +; +L071E: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1B + sta (sreg),y +; +; uip_appdata = uip_sappdata; +; +L023D: lda _uip_sappdata + sta _uip_appdata + lda _uip_sappdata+1 + sta _uip_appdata+1 +; +; if(uip_slen > 0 && uip_connr->len > 0) { +; + lda _uip_slen + ora _uip_slen+1 + beq L0725 + jsr ldax0sp + ldy #$11 + jsr ldaxidx + cpx #$00 + bne L0726 + cmp #$00 + beq L0725 +; +; uip_len = uip_connr->len + UIP_TCPIP_HLEN; +; +L0726: jsr ldax0sp + ldy #$11 + jsr ldaxidx + ldy #$28 + jsr incaxy + sta _uip_len + stx _uip_len+1 +; +; BUF->flags = TCP_ACK | TCP_PSH; +; + lda #$18 + sta _uip_buf+33 +; +; goto tcp_send_noopts; +; + jmp L0732 +; +; if(uip_flags & UIP_NEWDATA) { +; +L0725: lda _uip_flags + and #$02 + jeq L01EA +; +; uip_len = UIP_TCPIP_HLEN; +; + ldx #$00 + lda #$28 + sta _uip_len + stx _uip_len+1 +; +; BUF->flags = TCP_ACK; +; + lda #$10 + sta _uip_buf+33 +; +; goto tcp_send_noopts; +; + jmp L0732 +; +; if(uip_flags & UIP_ACKDATA) { +; +L073D: lda _uip_flags + and #$01 + jeq L01EA +; +; uip_connr->tcpstateflags = UIP_CLOSED; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$19 + sta (sreg),y +; +; uip_flags = UIP_CLOSE; +; + lda #$10 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; break; +; + jmp L01EA +; +; if(uip_len > 0) { +; +L0746: lda _uip_len + ora _uip_len+1 + beq L0747 +; +; uip_add_rcv_nxt(uip_len); +; + lda _uip_len + ldx _uip_len+1 + jsr pushax + jsr _uip_add_rcv_nxt +; +; if(BUF->flags & TCP_FIN) { +; +L0747: lda _uip_buf+33 + and #$01 + beq L074C +; +; if(uip_flags & UIP_ACKDATA) { +; + lda _uip_flags + and #$01 + beq L0750 +; +; uip_connr->tcpstateflags = UIP_TIME_WAIT; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$07 + ldy #$19 + sta (sreg),y +; +; uip_connr->timer = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1A + sta (sreg),y +; +; uip_connr->len = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$10 + sta (sreg),y + iny +; +; } else { +; + jmp L088F +; +; uip_connr->tcpstateflags = UIP_CLOSING; +; +L0750: jsr ldax0sp + sta sreg + stx sreg+1 + lda #$06 + ldy #$19 +L088F: sta (sreg),y +; +; uip_add_rcv_nxt(1); +; + jsr push1 + jsr _uip_add_rcv_nxt +; +; uip_flags = UIP_CLOSE; +; + lda #$10 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; goto tcp_send_ack; +; + jmp L05BA +; +; } else if(uip_flags & UIP_ACKDATA) { +; +L074C: lda _uip_flags + and #$01 + beq L0761 +; +; uip_connr->tcpstateflags = UIP_FIN_WAIT_2; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$05 + ldy #$19 + sta (sreg),y +; +; uip_connr->len = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$10 + sta (sreg),y + iny + sta (sreg),y +; +; goto drop; +; + jmp L01EA +; +; if(uip_len > 0) { +; +L0761: lda _uip_len + ora _uip_len+1 + jeq L01EA +; +; goto tcp_send_ack; +; + jmp L05BA +; +; if(uip_len > 0) { +; +L076B: lda _uip_len + ora _uip_len+1 + beq L076C +; +; uip_add_rcv_nxt(uip_len); +; + lda _uip_len + ldx _uip_len+1 + jsr pushax + jsr _uip_add_rcv_nxt +; +; if(BUF->flags & TCP_FIN) { +; +L076C: lda _uip_buf+33 + and #$01 + beq L0771 +; +; uip_connr->tcpstateflags = UIP_TIME_WAIT; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$07 + ldy #$19 + sta (sreg),y +; +; uip_connr->timer = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1A + sta (sreg),y +; +; uip_add_rcv_nxt(1); +; + jsr push1 + jsr _uip_add_rcv_nxt +; +; uip_flags = UIP_CLOSE; +; + lda #$10 + sta _uip_flags +; +; UIP_APPCALL(); +; + jsr _telnet_app +; +; goto tcp_send_ack; +; + jmp L05BA +; +; if(uip_len > 0) { +; +L0771: lda _uip_len + ora _uip_len+1 + jeq L01EA +; +; goto tcp_send_ack; +; + jmp L05BA +; +; if(uip_flags & UIP_ACKDATA) { +; +L0784: lda _uip_flags + and #$01 + jeq L01EA +; +; uip_connr->tcpstateflags = UIP_TIME_WAIT; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$07 + ldy #$19 + sta (sreg),y +; +; uip_connr->timer = 0; +; + jsr ldax0sp + sta sreg + stx sreg+1 + lda #$00 + ldy #$1A + sta (sreg),y +; +; goto drop; +; + jmp L01EA +; +; BUF->flags = TCP_ACK; +; +L05BA: lda #$10 +L0889: sta _uip_buf+33 +; +; uip_len = UIP_IPTCPH_LEN; +; + ldx #$00 + lda #$28 + sta _uip_len + stx _uip_len+1 +; +; BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; +; +L0732: lda #$50 +L088D: sta _uip_buf+32 +; +; BUF->ackno[0] = uip_connr->rcv_nxt[0]; +; + jsr ldax0sp + ldy #$08 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+28 +; +; BUF->ackno[1] = uip_connr->rcv_nxt[1]; +; + jsr ldax0sp + ldy #$09 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+29 +; +; BUF->ackno[2] = uip_connr->rcv_nxt[2]; +; + jsr ldax0sp + ldy #$0A + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+30 +; +; BUF->ackno[3] = uip_connr->rcv_nxt[3]; +; + jsr ldax0sp + ldy #$0B + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+31 +; +; BUF->seqno[0] = uip_connr->snd_nxt[0]; +; + jsr ldax0sp + ldy #$0C + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+24 +; +; BUF->seqno[1] = uip_connr->snd_nxt[1]; +; + jsr ldax0sp + ldy #$0D + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+25 +; +; BUF->seqno[2] = uip_connr->snd_nxt[2]; +; + jsr ldax0sp + ldy #$0E + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+26 +; +; BUF->seqno[3] = uip_connr->snd_nxt[3]; +; + jsr ldax0sp + ldy #$0F + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_buf+27 +; +; BUF->proto = UIP_PROTO_TCP; +; + lda #$06 + sta _uip_buf+9 +; +; BUF->srcport = uip_connr->lport; +; + jsr ldax0sp + ldy #$05 + jsr ldaxidx + sta _uip_buf+20 + stx _uip_buf+20+1 +; +; BUF->destport = uip_connr->rport; +; + jsr ldax0sp + ldy #$07 + jsr ldaxidx + sta _uip_buf+22 + stx _uip_buf+22+1 +; +; uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); +; + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+12) + sta sreg + lda #>(_uip_buf+12) + sta sreg+1 + lda #<(_uip_hostaddr) + ldx #>(_uip_hostaddr) + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr); +; + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + jsr ldax0sp + jsr ldaxi + ldy #$00 + sta (sreg),y + iny + txa + sta (sreg),y + lda #<(_uip_buf+16) + sta sreg + lda #>(_uip_buf+16) + sta sreg+1 + jsr ldax0sp + ldy #$03 + jsr ldaxidx + ldy #$02 + sta (sreg),y + iny + txa + sta (sreg),y +; +; if(uip_connr->tcpstateflags & UIP_STOPPED) { +; + jsr ldax0sp + ldy #$19 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + and #$10 + beq L07FB +; +; BUF->wnd[0] = BUF->wnd[1] = 0; +; + lda #$00 + sta _uip_buf+35 + sta _uip_buf+34 +; +; } else { +; + jmp L049A +; +; BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); +; +L07FB: sta _uip_buf+34 +; +; BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); +; + lda #$78 + sta _uip_buf+35 +; +; BUF->ttl = UIP_TTL; +; +L049A: lda #$40 + sta _uip_buf+8 +; +; BUF->len[0] = (uip_len >> 8); +; + lda _uip_len+1 + sta _uip_buf+2 +; +; BUF->len[1] = (uip_len & 0xff); +; + lda _uip_len + sta _uip_buf+3 +; +; BUF->urgp[0] = BUF->urgp[1] = 0; +; + lda #$00 + sta _uip_buf+39 + sta _uip_buf+38 +; +; BUF->tcpchksum = 0; +; + sta _uip_buf+36 + sta _uip_buf+36+1 +; +; BUF->tcpchksum = ~(uip_tcpchksum()); +; + jsr _uip_tcpchksum + jsr complax + sta _uip_buf+36 + stx _uip_buf+36+1 +; +; BUF->vhl = 0x45; +; +L03B9: lda #$45 + sta _uip_buf +; +; BUF->tos = 0; +; + lda #$00 + sta _uip_buf+1 +; +; BUF->ipoffset[0] = BUF->ipoffset[1] = 0; +; + sta _uip_buf+7 + sta _uip_buf+6 +; +; ++ipid; +; + inc _ipid + bne L084D + inc _ipid+1 +; +; BUF->ipid[0] = ipid >> 8; +; +L084D: lda _ipid+1 + sta _uip_buf+4 +; +; BUF->ipid[1] = ipid & 0xff; +; + lda _ipid + sta _uip_buf+5 +; +; BUF->ipchksum = 0; +; + lda #$00 + sta _uip_buf+10 + sta _uip_buf+10+1 +; +; BUF->ipchksum = ~(uip_ipchksum()); +; + jsr _uip_ipchksum + jsr complax + sta _uip_buf+10 + stx _uip_buf+10+1 +; +; uip_flags = 0; +; +L030D: lda #$00 +; +; return; +; + jmp L0890 +; +; uip_len = 0; +; +L01EA: lda #$00 + sta _uip_len + sta _uip_len+1 +; +; uip_flags = 0; +; +L0890: sta _uip_flags +; +; } +; + jmp incsp3 + +.endproc + +; --------------------------------------------------------------- +; unsigned int __near__ uip_chksum (__near__ unsigned int*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_chksum: near + +.segment "CODE" + +; +; return htons(chksum(0, (u8_t *)data, len)); +; + jsr push0 + ldy #$07 + jsr pushwysp + ldy #$07 + jsr pushwysp + jsr _chksum + jsr pushax + jsr _htons +; +; } +; + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; unsigned int __near__ uip_ipchksum (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_ipchksum: near + +.segment "CODE" + +; +; sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); +; + jsr decsp2 + jsr push0 + lda #<(_uip_buf) + ldx #>(_uip_buf) + jsr pushax + lda #$14 + jsr pusha0 + jsr _chksum + jsr stax0sp +; +; return (sum == 0) ? 0xffff : htons(sum); +; + cpx #$00 + bne L0090 + cmp #$00 + bne L0090 + dex + txa + jmp incsp2 +L0090: jsr pushw0sp + jsr _htons + jmp incsp2 + +.endproc + +; --------------------------------------------------------------- +; unsigned int __near__ uip_tcpchksum (void) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_tcpchksum: near + +.segment "CODE" + +; +; return upper_layer_chksum(UIP_PROTO_TCP); +; + lda #$06 + jsr pusha + jmp _upper_layer_chksum + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_add32 (__near__ unsigned char*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_add32: near + +.segment "CODE" + +; +; uip_acc32[3] = op32[3] + (op16 & 0xff); +; + ldy #$03 + jsr ldaxysp + ldy #$03 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta sreg + ldy #$00 + lda (sp),y + clc + adc sreg + sta _uip_acc32+3 +; +; uip_acc32[2] = op32[2] + (op16 >> 8); +; + ldy #$03 + jsr ldaxysp + ldy #$02 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta sreg + dey + lda (sp),y + clc + adc sreg + sta _uip_acc32+2 +; +; uip_acc32[1] = op32[1]; +; + ldy #$03 + jsr ldaxysp + ldy #$01 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_acc32+1 +; +; uip_acc32[0] = op32[0]; +; + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + sta _uip_acc32 +; +; if(uip_acc32[2] < (op16 >> 8)) { +; + lda _uip_acc32+2 + jsr pusha0 + ldy #$03 + lda (sp),y + jsr tosicmp + bcs L0045 +; +; ++uip_acc32[1]; +; + inc _uip_acc32+1 +; +; if(uip_acc32[1] == 0) { +; + lda _uip_acc32+1 + bne L0045 +; +; ++uip_acc32[0]; +; + inc _uip_acc32 +; +; if(uip_acc32[3] < (op16 & 0xff)) { +; +L0045: lda _uip_acc32+3 + jsr pusha0 + ldy #$02 + lda (sp),y + jsr tosicmp + jcs incsp4 +; +; ++uip_acc32[2]; +; + inc _uip_acc32+2 +; +; if(uip_acc32[2] == 0) { +; + lda _uip_acc32+2 + jne incsp4 +; +; ++uip_acc32[1]; +; + inc _uip_acc32+1 +; +; if(uip_acc32[1] == 0) { +; + lda _uip_acc32+1 + jne incsp4 +; +; ++uip_acc32[0]; +; + inc _uip_acc32 +; +; } +; + jmp incsp4 + +.endproc + +; --------------------------------------------------------------- +; unsigned int __near__ chksum (unsigned int, __near__ const unsigned char*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _chksum: near + +.segment "CODE" + +; +; dataptr = data; +; + jsr decsp6 + ldy #$09 + jsr ldaxysp + ldy #$02 + jsr staxysp +; +; last_byte = data + len - 1; +; + ldy #$09 + jsr ldaxysp + sta sreg + stx sreg+1 + ldy #$07 + jsr ldaxysp + clc + adc sreg + sta sreg + txa + adc sreg+1 + tax + lda sreg + jsr decax1 + jsr stax0sp +; +; while(dataptr < last_byte) { /* At least two more bytes */ +; +L0065: ldy #$05 + jsr pushwysp + ldy #$03 + jsr ldaxysp + jsr tosicmp + bcs L0066 +; +; t = (dataptr[0] << 8) + dataptr[1]; +; + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + tax + stx sreg+1 + ldy #$03 + jsr ldaxysp + ldy #$01 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + clc + adc #$00 + ldx sreg+1 + bcc L08A2 + inx +L08A2: ldy #$04 + jsr staxysp +; +; sum += t; +; + ldy #$0A + jsr addeqysp +; +; if(sum < t) { +; + ldy #$0D + jsr pushwysp + ldy #$07 + jsr ldaxysp + jsr tosicmp + bcs L006F +; +; sum++; /* carry */ +; + ldy #$0B + jsr ldaxysp + jsr incax1 + ldy #$0A + jsr staxysp +; +; dataptr += 2; +; +L006F: ldy #$02 + ldx #$00 + tya + jsr addeqysp +; +; } +; + jmp L0065 +; +; if(dataptr == last_byte) { +; +L0066: ldy #$05 + jsr pushwysp + ldy #$03 + jsr ldaxysp + jsr tosicmp + bne L007C +; +; t = (dataptr[0] << 8) + 0; +; + ldy #$03 + jsr ldaxysp + ldy #$00 + sta ptr1 + stx ptr1+1 + lda (ptr1),y + tax + tya + ldy #$04 + jsr staxysp +; +; sum += t; +; + ldy #$0A + jsr addeqysp +; +; if(sum < t) { +; + ldy #$0D + jsr pushwysp + ldy #$07 + jsr ldaxysp + jsr tosicmp + bcs L007C +; +; sum++; /* carry */ +; + ldy #$0B + jsr ldaxysp + jsr incax1 + ldy #$0A + jsr staxysp +; +; return sum; +; +L007C: ldy #$0B + jsr ldaxysp +; +; } +; + ldy #$0C + jmp addysp + +.endproc + +; --------------------------------------------------------------- +; unsigned int __near__ upper_layer_chksum (unsigned char) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _upper_layer_chksum: near + +.segment "CODE" + +; +; upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +; + jsr decsp4 + ldx _uip_buf+2 + lda #$00 + clc + adc _uip_buf+3 + bcc L08A3 + inx +L08A3: ldy #$14 + jsr decaxy + ldy #$02 + jsr staxysp +; +; sum = upper_layer_len + proto; +; + sta sreg + stx sreg+1 + ldy #$04 + lda (sp),y + clc + adc sreg + ldx sreg+1 + bcc L08A4 + inx +L08A4: jsr stax0sp +; +; sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); +; + jsr pushax + lda #<(_uip_buf+12) + ldx #>(_uip_buf+12) + jsr pushax + lda #$08 + jsr pusha0 + jsr _chksum + jsr stax0sp +; +; sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], +; + jsr pushax + lda #<(_uip_buf+20) + ldx #>(_uip_buf+20) + jsr pushax +; +; upper_layer_len); +; + ldy #$09 + jsr pushwysp + jsr _chksum + jsr stax0sp +; +; return (sum == 0) ? 0xffff : htons(sum); +; + cpx #$00 + bne L00B5 + cmp #$00 + bne L00B5 + dex + txa + jmp incsp5 +L00B5: jsr pushw0sp + jsr _htons + jmp incsp5 + +.endproc + +; --------------------------------------------------------------- +; void __near__ uip_add_rcv_nxt (unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _uip_add_rcv_nxt: near + +.segment "CODE" + +; +; uip_add32(uip_conn->rcv_nxt, n); +; + lda _uip_conn + ldx _uip_conn+1 + jsr incax8 + jsr pushax + ldy #$05 + jsr pushwysp + jsr _uip_add32 +; +; uip_conn->rcv_nxt[0] = uip_acc32[0]; +; + lda _uip_conn + sta sreg + lda _uip_conn+1 + sta sreg+1 + lda _uip_acc32 + ldy #$08 + sta (sreg),y +; +; uip_conn->rcv_nxt[1] = uip_acc32[1]; +; + lda _uip_conn + sta sreg + lda _uip_conn+1 + sta sreg+1 + lda _uip_acc32+1 + iny + sta (sreg),y +; +; uip_conn->rcv_nxt[2] = uip_acc32[2]; +; + lda _uip_conn + sta sreg + lda _uip_conn+1 + sta sreg+1 + lda _uip_acc32+2 + iny + sta (sreg),y +; +; uip_conn->rcv_nxt[3] = uip_acc32[3]; +; + lda _uip_conn + sta sreg + lda _uip_conn+1 + sta sreg+1 + lda _uip_acc32+3 + iny + sta (sreg),y +; +; } +; + jmp incsp2 + +.endproc + diff --git a/uip/README.uIP b/uip/README.uIP new file mode 100644 index 0000000..b501538 --- /dev/null +++ b/uip/README.uIP @@ -0,0 +1,13 @@ +uIP is a very small implementation of the TCP/IP stack that is written +by Adam Dunkels . More information can be obtained +at the uIP homepage at http://www.sics.se/~adam/uip/. + +This is version $Name: uip-1-0 $. + +The directory structure look as follows: + +apps/ - Example applications +doc/ - Documentation +lib/ - Library code used by some applications +uip/ - uIP TCP/IP stack code +unix/ - uIP as a user space process under FreeBSD or Linux diff --git a/uip/apps/README b/uip/apps/README new file mode 100644 index 0000000..0096c4e --- /dev/null +++ b/uip/apps/README @@ -0,0 +1,2 @@ +This directory contains a few example applications. They are not all +heavily tested, however. diff --git a/uip/apps/dhcpc/Makefile.dhcpc b/uip/apps/dhcpc/Makefile.dhcpc new file mode 100644 index 0000000..f84c84f --- /dev/null +++ b/uip/apps/dhcpc/Makefile.dhcpc @@ -0,0 +1 @@ +APP_SOURCES += dhcpc.c timer.c diff --git a/uip/apps/dhcpc/dhcpc.c b/uip/apps/dhcpc/dhcpc.c new file mode 100644 index 0000000..ac738e7 --- /dev/null +++ b/uip/apps/dhcpc/dhcpc.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $ + */ + +#include +#include + +#include "uip.h" +#include "dhcpc.h" +#include "timer.h" +#include "pt.h" + +#define STATE_INITIAL 0 +#define STATE_SENDING 1 +#define STATE_OFFER_RECEIVED 2 +#define STATE_CONFIG_RECEIVED 3 + +static struct dhcpc_state s; + +struct dhcp_msg { + u8_t op, htype, hlen, hops; + u8_t xid[4]; + u16_t secs, flags; + u8_t ciaddr[4]; + u8_t yiaddr[4]; + u8_t siaddr[4]; + u8_t giaddr[4]; + u8_t chaddr[16]; +#ifndef UIP_CONF_DHCP_LIGHT + u8_t sname[64]; + u8_t file[128]; +#endif + u8_t options[312]; +}; + +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPC_SERVER_PORT 67 +#define DHCPC_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; +static const u8_t magic_cookie[4] = {99, 130, 83, 99}; +/*---------------------------------------------------------------------------*/ +static u8_t * +add_msg_type(u8_t *optptr, u8_t type) +{ + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_server_id(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + memcpy(optptr, s.serverid, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_req_ipaddr(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_IPADDR; + *optptr++ = 4; + memcpy(optptr, s.ipaddr, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_req_options(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_LIST; + *optptr++ = 3; + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = DHCP_OPTION_DNS_SERVER; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_end(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_END; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static void +create_msg(register struct dhcp_msg *m) +{ + m->op = DHCP_REQUEST; + m->htype = DHCP_HTYPE_ETHERNET; + m->hlen = s.mac_len; + m->hops = 0; + memcpy(m->xid, xid, sizeof(m->xid)); + m->secs = 0; + m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */ + /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/ + memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr)); + memset(m->yiaddr, 0, sizeof(m->yiaddr)); + memset(m->siaddr, 0, sizeof(m->siaddr)); + memset(m->giaddr, 0, sizeof(m->giaddr)); + memcpy(m->chaddr, s.mac_addr, s.mac_len); + memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len); +#ifndef UIP_CONF_DHCP_LIGHT + memset(m->sname, 0, sizeof(m->sname)); + memset(m->file, 0, sizeof(m->file)); +#endif + + memcpy(m->options, magic_cookie, sizeof(magic_cookie)); +} +/*---------------------------------------------------------------------------*/ +static void +send_discover(void) +{ + u8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPDISCOVER); + end = add_req_options(end); + end = add_end(end); + + uip_send(uip_appdata, end - (u8_t *)uip_appdata); +} +/*---------------------------------------------------------------------------*/ +static void +send_request(void) +{ + u8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPREQUEST); + end = add_server_id(end); + end = add_req_ipaddr(end); + end = add_end(end); + + uip_send(uip_appdata, end - (u8_t *)uip_appdata); +} +/*---------------------------------------------------------------------------*/ +static u8_t +parse_options(u8_t *optptr, int len) +{ + u8_t *end = optptr + len; + u8_t type = 0; + + while(optptr < end) { + switch(*optptr) { + case DHCP_OPTION_SUBNET_MASK: + memcpy(s.netmask, optptr + 2, 4); + break; + case DHCP_OPTION_ROUTER: + memcpy(s.default_router, optptr + 2, 4); + break; + case DHCP_OPTION_DNS_SERVER: + memcpy(s.dnsaddr, optptr + 2, 4); + break; + case DHCP_OPTION_MSG_TYPE: + type = *(optptr + 2); + break; + case DHCP_OPTION_SERVER_ID: + memcpy(s.serverid, optptr + 2, 4); + break; + case DHCP_OPTION_LEASE_TIME: + memcpy(s.lease_time, optptr + 2, 4); + break; + case DHCP_OPTION_END: + return type; + } + + optptr += optptr[1] + 2; + } + return type; +} +/*---------------------------------------------------------------------------*/ +static u8_t +parse_msg(void) +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + if(m->op == DHCP_REPLY && + memcmp(m->xid, xid, sizeof(xid)) == 0 && + memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) { + memcpy(s.ipaddr, m->yiaddr, 4); + return parse_options(&m->options[4], uip_datalen()); + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_dhcp(void)) +{ + PT_BEGIN(&s.pt); + + /* try_again:*/ + s.state = STATE_SENDING; + s.ticks = CLOCK_SECOND; + + do { + send_discover(); + timer_set(&s.timer, s.ticks); + PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer)); + + if(uip_newdata() && parse_msg() == DHCPOFFER) { + s.state = STATE_OFFER_RECEIVED; + break; + } + + if(s.ticks < CLOCK_SECOND * 60) { + s.ticks *= 2; + } + } while(s.state != STATE_OFFER_RECEIVED); + + s.ticks = CLOCK_SECOND; + + do { + send_request(); + timer_set(&s.timer, s.ticks); + PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer)); + + if(uip_newdata() && parse_msg() == DHCPACK) { + s.state = STATE_CONFIG_RECEIVED; + break; + } + + if(s.ticks <= CLOCK_SECOND * 10) { + s.ticks += CLOCK_SECOND; + } else { + PT_RESTART(&s.pt); + } + } while(s.state != STATE_CONFIG_RECEIVED); + +#if 0 + printf("Got IP address %d.%d.%d.%d\n", + uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr), + uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr)); + printf("Got netmask %d.%d.%d.%d\n", + uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask), + uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask)); + printf("Got DNS server %d.%d.%d.%d\n", + uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr), + uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr)); + printf("Got default router %d.%d.%d.%d\n", + uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router), + uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router)); + printf("Lease expires in %ld seconds\n", + ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1])); +#endif + + dhcpc_configured(&s); + + /* timer_stop(&s.timer);*/ + + /* + * PT_END restarts the thread so we do this instead. Eventually we + * should reacquire expired leases here. + */ + while(1) { + PT_YIELD(&s.pt); + } + + PT_END(&s.pt); +} +/*---------------------------------------------------------------------------*/ +void +dhcpc_init(const void *mac_addr, int mac_len) +{ + uip_ipaddr_t addr; + + s.mac_addr = mac_addr; + s.mac_len = mac_len; + + s.state = STATE_INITIAL; + uip_ipaddr(addr, 255,255,255,255); + s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT)); + if(s.conn != NULL) { + uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT)); + } + PT_INIT(&s.pt); +} +/*---------------------------------------------------------------------------*/ +void +dhcpc_appcall(void) +{ + handle_dhcp(); +} +/*---------------------------------------------------------------------------*/ +void +dhcpc_request(void) +{ + u16_t ipaddr[2]; + + if(s.state == STATE_INITIAL) { + uip_ipaddr(ipaddr, 0,0,0,0); + uip_sethostaddr(ipaddr); + /* handle_dhcp(PROCESS_EVENT_NONE, NULL);*/ + } +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/dhcpc/dhcpc.h b/uip/apps/dhcpc/dhcpc.h new file mode 100644 index 0000000..c6550ec --- /dev/null +++ b/uip/apps/dhcpc/dhcpc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * @(#)$Id: dhcpc.h,v 1.3 2006/06/11 21:46:37 adam Exp $ + */ +#ifndef __DHCPC_H__ +#define __DHCPC_H__ + +#include "timer.h" +#include "pt.h" + +struct dhcpc_state { + struct pt pt; + char state; + struct uip_udp_conn *conn; + struct timer timer; + u16_t ticks; + const void *mac_addr; + int mac_len; + + u8_t serverid[4]; + + u16_t lease_time[2]; + u16_t ipaddr[2]; + u16_t netmask[2]; + u16_t dnsaddr[2]; + u16_t default_router[2]; +}; + +void dhcpc_init(const void *mac_addr, int mac_len); +void dhcpc_request(void); + +void dhcpc_appcall(void); + +void dhcpc_configured(const struct dhcpc_state *s); + +typedef struct dhcpc_state uip_udp_appstate_t; +#define UIP_UDP_APPCALL dhcpc_appcall + + +#endif /* __DHCPC_H__ */ diff --git a/uip/apps/hello-world/Makefile.hello-world b/uip/apps/hello-world/Makefile.hello-world new file mode 100644 index 0000000..e34aaf5 --- /dev/null +++ b/uip/apps/hello-world/Makefile.hello-world @@ -0,0 +1 @@ +APP_SOURCES += hello-world.c diff --git a/uip/apps/hello-world/hello-world.c b/uip/apps/hello-world/hello-world.c new file mode 100644 index 0000000..7d0697c --- /dev/null +++ b/uip/apps/hello-world/hello-world.c @@ -0,0 +1,100 @@ +/** + * \addtogroup helloworld + * @{ + */ + +/** + * \file + * An example of how to write uIP applications + * with protosockets. + * \author + * Adam Dunkels + */ + +/* + * This is a short example of how to write uIP applications using + * protosockets. + */ + +/* + * We define the application state (struct hello_world_state) in the + * hello-world.h file, so we need to include it here. We also include + * uip.h (since this cannot be included in hello-world.h) and + * , since we use the memcpy() function in the code. + */ +#include "hello-world.h" +#include "uip.h" +#include + +/* + * Declaration of the protosocket function that handles the connection + * (defined at the end of the code). + */ +static int handle_connection(struct hello_world_state *s); +/*---------------------------------------------------------------------------*/ +/* + * The initialization function. We must explicitly call this function + * from the system initialization code, some time after uip_init() is + * called. + */ +void +hello_world_init(void) +{ + /* We start to listen for connections on TCP port 1000. */ + uip_listen(HTONS(1000)); +} +/*---------------------------------------------------------------------------*/ +/* + * In hello-world.h we have defined the UIP_APPCALL macro to + * hello_world_appcall so that this funcion is uIP's application + * function. This function is called whenever an uIP event occurs + * (e.g. when a new connection is established, new data arrives, sent + * data is acknowledged, data needs to be retransmitted, etc.). + */ +void +hello_world_appcall(void) +{ + /* + * The uip_conn structure has a field called "appstate" that holds + * the application state of the connection. We make a pointer to + * this to access it easier. + */ + struct hello_world_state *s = &(uip_conn->appstate); + + /* + * If a new connection was just established, we should initialize + * the protosocket in our applications' state structure. + */ + if(uip_connected()) { + PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer)); + } + + /* + * Finally, we run the protosocket function that actually handles + * the communication. We pass it a pointer to the application state + * of the current connection. + */ + handle_connection(s); +} +/*---------------------------------------------------------------------------*/ +/* + * This is the protosocket function that handles the communication. A + * protosocket function must always return an int, but must never + * explicitly return - all return statements are hidden in the PSOCK + * macros. + */ +static int +handle_connection(struct hello_world_state *s) +{ + PSOCK_BEGIN(&s->p); + + PSOCK_SEND_STR(&s->p, "Hello. What is your name?\n"); + PSOCK_READTO(&s->p, '\n'); + strncpy(s->name, s->inputbuffer, sizeof(s->name)); + PSOCK_SEND_STR(&s->p, "Hello "); + PSOCK_SEND_STR(&s->p, s->name); + PSOCK_CLOSE(&s->p); + + PSOCK_END(&s->p); +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/hello-world/hello-world.h b/uip/apps/hello-world/hello-world.h new file mode 100644 index 0000000..5ef333b --- /dev/null +++ b/uip/apps/hello-world/hello-world.h @@ -0,0 +1,52 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup helloworld Hello, world + * @{ + * + * A small example showing how to write applications with + * \ref psock "protosockets". + */ + +/** + * \file + * Header file for an example of how to write uIP applications + * with protosockets. + * \author + * Adam Dunkels + */ + +#ifndef __HELLO_WORLD_H__ +#define __HELLO_WORLD_H__ + +/* Since this file will be included by uip.h, we cannot include uip.h + here. But we might need to include uipopt.h if we need the u8_t and + u16_t datatypes. */ +#include "uipopt.h" + +#include "psock.h" + +/* Next, we define the uip_tcp_appstate_t datatype. This is the state + of our application, and the memory required for this state is + allocated together with each TCP connection. One application state + for each TCP connection. */ +typedef struct hello_world_state { + struct psock p; + char inputbuffer[10]; + char name[40]; +} uip_tcp_appstate_t; + +/* Finally we define the application function to be called by uIP. */ +void hello_world_appcall(void); +#ifndef UIP_APPCALL +#define UIP_APPCALL hello_world_appcall +#endif /* UIP_APPCALL */ + +void hello_world_init(void); + +#endif /* __HELLO_WORLD_H__ */ +/** @} */ +/** @} */ diff --git a/uip/apps/resolv/Makefile.resolv b/uip/apps/resolv/Makefile.resolv new file mode 100644 index 0000000..94c37d8 --- /dev/null +++ b/uip/apps/resolv/Makefile.resolv @@ -0,0 +1 @@ +APP_SOURCES += resolv.c diff --git a/uip/apps/resolv/resolv.c b/uip/apps/resolv/resolv.c new file mode 100644 index 0000000..30c8fb2 --- /dev/null +++ b/uip/apps/resolv/resolv.c @@ -0,0 +1,464 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup resolv DNS resolver + * @{ + * + * The uIP DNS resolver functions are used to lookup a hostname and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the resolv_lookup() + * function. New hostnames can be resolved using the resolv_query() + * function. + * + * When a hostname has been resolved (or found to be non-existant), + * the resolver code calls a callback function called resolv_found() + * that must be implemented by the module that uses the resolver. + */ + +/** + * \file + * DNS host name to IP address resolver. + * \author Adam Dunkels + * + * This file implements a DNS host name to IP address resolver. + */ + +/* + * Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: resolv.c,v 1.5 2006/06/11 21:46:37 adam Exp $ + * + */ + +#include "resolv.h" +#include "uip.h" + +#include + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/** \internal The maximum number of retries when asking for a name. */ +#define MAX_RETRIES 8 + +/** \internal The DNS message header. */ +struct dns_hdr { + u16_t id; + u8_t flags1, flags2; +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + u16_t numquestions; + u16_t numanswers; + u16_t numauthrr; + u16_t numextrarr; +}; + +/** \internal The DNS answer message structure. */ +struct dns_answer { + /* DNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t class; + u16_t ttl[2]; + u16_t len; + uip_ipaddr_t ipaddr; +}; + +struct namemap { +#define STATE_UNUSED 0 +#define STATE_NEW 1 +#define STATE_ASKING 2 +#define STATE_DONE 3 +#define STATE_ERROR 4 + u8_t state; + u8_t tmr; + u8_t retries; + u8_t seqno; + u8_t err; + char name[32]; + uip_ipaddr_t ipaddr; +}; + +#ifndef UIP_CONF_RESOLV_ENTRIES +#define RESOLV_ENTRIES 4 +#else /* UIP_CONF_RESOLV_ENTRIES */ +#define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES +#endif /* UIP_CONF_RESOLV_ENTRIES */ + + +static struct namemap names[RESOLV_ENTRIES]; + +static u8_t seqno; + +static struct uip_udp_conn *resolv_conn = NULL; + + +/*---------------------------------------------------------------------------*/ +/** \internal + * Walk through a compact encoded DNS name and return the end of it. + * + * \return The end of the name. + */ +/*---------------------------------------------------------------------------*/ +static unsigned char * +parse_name(unsigned char *query) +{ + unsigned char n; + + do { + n = *query++; + + while(n > 0) { + /* printf("%c", *query);*/ + ++query; + --n; + }; + /* printf(".");*/ + } while(*query != 0); + /* printf("\n");*/ + return query + 1; +} +/*---------------------------------------------------------------------------*/ +/** \internal + * Runs through the list of names to see if there are any that have + * not yet been queried and, if so, sends out a query. + */ +/*---------------------------------------------------------------------------*/ +static void +check_entries(void) +{ + register struct dns_hdr *hdr; + char *query, *nptr, *nameptr; + static u8_t i; + static u8_t n; + register struct namemap *namemapptr; + + for(i = 0; i < RESOLV_ENTRIES; ++i) { + namemapptr = &names[i]; + if(namemapptr->state == STATE_NEW || + namemapptr->state == STATE_ASKING) { + if(namemapptr->state == STATE_ASKING) { + if(--namemapptr->tmr == 0) { + if(++namemapptr->retries == MAX_RETRIES) { + namemapptr->state = STATE_ERROR; + resolv_found(namemapptr->name, NULL); + continue; + } + namemapptr->tmr = namemapptr->retries; + } else { + /* printf("Timer %d\n", namemapptr->tmr);*/ + /* Its timer has not run out, so we move on to next + entry. */ + continue; + } + } else { + namemapptr->state = STATE_ASKING; + namemapptr->tmr = 1; + namemapptr->retries = 0; + } + hdr = (struct dns_hdr *)uip_appdata; + memset(hdr, 0, sizeof(struct dns_hdr)); + hdr->id = htons(i); + hdr->flags1 = DNS_FLAG1_RD; + hdr->numquestions = HTONS(1); + query = (char *)uip_appdata + 12; + nameptr = namemapptr->name; + --nameptr; + /* Convert hostname into suitable query format. */ + do { + ++nameptr; + nptr = query; + ++query; + for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) { + *query = *nameptr; + ++query; + ++n; + } + *nptr = n; + } while(*nameptr != 0); + { + static unsigned char endquery[] = + {0,0,1,0,1}; + memcpy(query, endquery, 5); + } + uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata)); + break; + } + } +} +/*---------------------------------------------------------------------------*/ +/** \internal + * Called when new UDP data arrives. + */ +/*---------------------------------------------------------------------------*/ +static void +newdata(void) +{ + char *nameptr; + struct dns_answer *ans; + struct dns_hdr *hdr; + static u8_t nquestions, nanswers; + static u8_t i; + register struct namemap *namemapptr; + + hdr = (struct dns_hdr *)uip_appdata; + /* printf("ID %d\n", htons(hdr->id)); + printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE); + printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK); + printf("Num questions %d, answers %d, authrr %d, extrarr %d\n", + htons(hdr->numquestions), + htons(hdr->numanswers), + htons(hdr->numauthrr), + htons(hdr->numextrarr)); + */ + + /* The ID in the DNS header should be our entry into the name + table. */ + i = htons(hdr->id); + namemapptr = &names[i]; + if(i < RESOLV_ENTRIES && + namemapptr->state == STATE_ASKING) { + + /* This entry is now finished. */ + namemapptr->state = STATE_DONE; + namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; + + /* Check for error. If so, call callback to inform. */ + if(namemapptr->err != 0) { + namemapptr->state = STATE_ERROR; + resolv_found(namemapptr->name, NULL); + return; + } + + /* We only care about the question(s) and the answers. The authrr + and the extrarr are simply discarded. */ + nquestions = htons(hdr->numquestions); + nanswers = htons(hdr->numanswers); + + /* Skip the name in the question. XXX: This should really be + checked agains the name in the question, to be sure that they + match. */ + nameptr = parse_name((char *)uip_appdata + 12) + 4; + + while(nanswers > 0) { + /* The first byte in the answer resource record determines if it + is a compressed record or a normal one. */ + if(*nameptr & 0xc0) { + /* Compressed name. */ + nameptr +=2; + /* printf("Compressed anwser\n");*/ + } else { + /* Not compressed name. */ + nameptr = parse_name((char *)nameptr); + } + + ans = (struct dns_answer *)nameptr; + /* printf("Answer: type %x, class %x, ttl %x, length %x\n", + htons(ans->type), htons(ans->class), (htons(ans->ttl[0]) + << 16) | htons(ans->ttl[1]), htons(ans->len));*/ + + /* Check for IP address type and Internet class. Others are + discarded. */ + if(ans->type == HTONS(1) && + ans->class == HTONS(1) && + ans->len == HTONS(4)) { + /* printf("IP address %d.%d.%d.%d\n", + htons(ans->ipaddr[0]) >> 8, + htons(ans->ipaddr[0]) & 0xff, + htons(ans->ipaddr[1]) >> 8, + htons(ans->ipaddr[1]) & 0xff);*/ + /* XXX: we should really check that this IP address is the one + we want. */ + namemapptr->ipaddr[0] = ans->ipaddr[0]; + namemapptr->ipaddr[1] = ans->ipaddr[1]; + + resolv_found(namemapptr->name, namemapptr->ipaddr); + return; + } else { + nameptr = nameptr + 10 + htons(ans->len); + } + --nanswers; + } + } + +} +/*---------------------------------------------------------------------------*/ +/** \internal + * The main UDP function. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_appcall(void) +{ + if(uip_udp_conn->rport == HTONS(53)) { + if(uip_poll()) { + check_entries(); + } + if(uip_newdata()) { + newdata(); + } + } +} +/*---------------------------------------------------------------------------*/ +/** + * Queues a name so that a question for the name will be sent out. + * + * \param name The hostname that is to be queried. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_query(char *name) +{ + static u8_t i; + static u8_t lseq, lseqi; + register struct namemap *nameptr; + + lseq = lseqi = 0; + + for(i = 0; i < RESOLV_ENTRIES; ++i) { + nameptr = &names[i]; + if(nameptr->state == STATE_UNUSED) { + break; + } + if(seqno - nameptr->seqno > lseq) { + lseq = seqno - nameptr->seqno; + lseqi = i; + } + } + + if(i == RESOLV_ENTRIES) { + i = lseqi; + nameptr = &names[i]; + } + + /* printf("Using entry %d\n", i);*/ + + strcpy(nameptr->name, name); + nameptr->state = STATE_NEW; + nameptr->seqno = seqno; + ++seqno; +} +/*---------------------------------------------------------------------------*/ +/** + * Look up a hostname in the array of known hostnames. + * + * \note This function only looks in the internal array of known + * hostnames, it does not send out a query for the hostname if none + * was found. The function resolv_query() can be used to send a query + * for a hostname. + * + * \return A pointer to a 4-byte representation of the hostname's IP + * address, or NULL if the hostname was not found in the array of + * hostnames. + */ +/*---------------------------------------------------------------------------*/ +u16_t * +resolv_lookup(char *name) +{ + static u8_t i; + struct namemap *nameptr; + + /* Walk through the list to see if the name is in there. If it is + not, we return NULL. */ + for(i = 0; i < RESOLV_ENTRIES; ++i) { + nameptr = &names[i]; + if(nameptr->state == STATE_DONE && + strcmp(name, nameptr->name) == 0) { + return nameptr->ipaddr; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +/** + * Obtain the currently configured DNS server. + * + * \return A pointer to a 4-byte representation of the IP address of + * the currently configured DNS server or NULL if no DNS server has + * been configured. + */ +/*---------------------------------------------------------------------------*/ +u16_t * +resolv_getserver(void) +{ + if(resolv_conn == NULL) { + return NULL; + } + return resolv_conn->ripaddr; +} +/*---------------------------------------------------------------------------*/ +/** + * Configure which DNS server to use for queries. + * + * \param dnsserver A pointer to a 4-byte representation of the IP + * address of the DNS server to be configured. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_conf(u16_t *dnsserver) +{ + if(resolv_conn != NULL) { + uip_udp_remove(resolv_conn); + } + + resolv_conn = uip_udp_new((uip_ipaddr_t *)dnsserver, HTONS(53)); +} +/*---------------------------------------------------------------------------*/ +/** + * Initalize the resolver. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_init(void) +{ + static u8_t i; + + for(i = 0; i < RESOLV_ENTRIES; ++i) { + names[i].state = STATE_DONE; + } + +} +/*---------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/uip/apps/resolv/resolv.h b/uip/apps/resolv/resolv.h new file mode 100644 index 0000000..abab34e --- /dev/null +++ b/uip/apps/resolv/resolv.h @@ -0,0 +1,75 @@ +/** + * \addtogroup resolv + * @{ + */ +/** + * \file + * DNS resolver code header file. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: resolv.h,v 1.4 2006/06/11 21:46:37 adam Exp $ + * + */ +#ifndef __RESOLV_H__ +#define __RESOLV_H__ + +typedef int uip_udp_appstate_t; +void resolv_appcall(void); +#define UIP_UDP_APPCALL resolv_appcall + +#include "uipopt.h" + +/** + * Callback function which is called when a hostname is found. + * + * This function must be implemented by the module that uses the DNS + * resolver. It is called when a hostname is found, or when a hostname + * was not found. + * + * \param name A pointer to the name that was looked up. \param + * ipaddr A pointer to a 4-byte array containing the IP address of the + * hostname, or NULL if the hostname could not be found. + */ +void resolv_found(char *name, u16_t *ipaddr); + +/* Functions. */ +void resolv_conf(u16_t *dnsserver); +u16_t *resolv_getserver(void); +void resolv_init(void); +u16_t *resolv_lookup(char *name); +void resolv_query(char *name); + +#endif /* __RESOLV_H__ */ + +/** @} */ diff --git a/uip/apps/smtp/Makefile.smtp b/uip/apps/smtp/Makefile.smtp new file mode 100644 index 0000000..8b3a5aa --- /dev/null +++ b/uip/apps/smtp/Makefile.smtp @@ -0,0 +1 @@ +APP_SOURCES += smtp.c smtp-strings.c memb.c diff --git a/uip/apps/smtp/makestrings b/uip/apps/smtp/makestrings new file mode 100755 index 0000000..bea18a6 --- /dev/null +++ b/uip/apps/smtp/makestrings @@ -0,0 +1,40 @@ +#!/usr/bin/perl + + +sub stringify { + my $name = shift(@_); + open(OUTPUTC, "> $name.c"); + open(OUTPUTH, "> $name.h"); + + open(FILE, "$name"); + + while() { + if(/(.+) "(.+)"/) { + $var = $1; + $data = $2; + + $datan = $data; + $datan =~ s/\\r/\r/g; + $datan =~ s/\\n/\n/g; + $datan =~ s/\\01/\01/g; + $datan =~ s/\\0/\0/g; + + printf(OUTPUTC "const char $var\[%d] = \n", length($datan) + 1); + printf(OUTPUTC "/* \"$data\" */\n"); + printf(OUTPUTC "{"); + for($j = 0; $j < length($datan); $j++) { + printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1))); + } + printf(OUTPUTC "};\n"); + + printf(OUTPUTH "extern const char $var\[%d];\n", length($datan) + 1); + + } + } + close(OUTPUTC); + close(OUTPUTH); +} +stringify("smtp-strings"); + +exit 0; + diff --git a/uip/apps/smtp/smtp-strings b/uip/apps/smtp/smtp-strings new file mode 100644 index 0000000..27f639c --- /dev/null +++ b/uip/apps/smtp/smtp-strings @@ -0,0 +1,11 @@ +smtp_220 "220" +smtp_helo "HELO " +smtp_mail_from "MAIL FROM: " +smtp_rcpt_to "RCPT TO: " +smtp_data "DATA\r\n" +smtp_to "To: " +smtp_from "From: " +smtp_subject "Subject: " +smtp_quit "QUIT\r\n" +smtp_crnl "\r\n" +smtp_crnlperiodcrnl "\r\n.\r\n" \ No newline at end of file diff --git a/uip/apps/smtp/smtp-strings.c b/uip/apps/smtp/smtp-strings.c new file mode 100644 index 0000000..f3981a1 --- /dev/null +++ b/uip/apps/smtp/smtp-strings.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: smtp-strings.c,v 1.3 2006/06/11 21:46:37 adam Exp $ + */ +const char smtp_220[4] = +/* "220" */ +{0x32, 0x32, 0x30, }; +const char smtp_helo[6] = +/* "HELO " */ +{0x48, 0x45, 0x4c, 0x4f, 0x20, }; +const char smtp_mail_from[12] = +/* "MAIL FROM: " */ +{0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x20, }; +const char smtp_rcpt_to[10] = +/* "RCPT TO: " */ +{0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x20, }; +const char smtp_data[7] = +/* "DATA\r\n" */ +{0x44, 0x41, 0x54, 0x41, 0xd, 0xa, }; +const char smtp_to[5] = +/* "To: " */ +{0x54, 0x6f, 0x3a, 0x20, }; +const char smtp_cc[5] = +/* "Cc: " */ +{0x43, 0x63, 0x3a, 0x20, }; +const char smtp_from[7] = +/* "From: " */ +{0x46, 0x72, 0x6f, 0x6d, 0x3a, 0x20, }; +const char smtp_subject[10] = +/* "Subject: " */ +{0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, }; +const char smtp_quit[7] = +/* "QUIT\r\n" */ +{0x51, 0x55, 0x49, 0x54, 0xd, 0xa, }; +const char smtp_crnl[3] = +/* "\r\n" */ +{0xd, 0xa, }; +const char smtp_crnlperiodcrnl[6] = +/* "\r\n.\r\n" */ +{0xd, 0xa, 0x2e, 0xd, 0xa, }; diff --git a/uip/apps/smtp/smtp-strings.h b/uip/apps/smtp/smtp-strings.h new file mode 100644 index 0000000..f5ae68c --- /dev/null +++ b/uip/apps/smtp/smtp-strings.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: smtp-strings.h,v 1.3 2006/06/11 21:46:37 adam Exp $ + */ +extern const char smtp_220[4]; +extern const char smtp_helo[6]; +extern const char smtp_mail_from[12]; +extern const char smtp_rcpt_to[10]; +extern const char smtp_data[7]; +extern const char smtp_to[5]; +extern const char smtp_cc[5]; +extern const char smtp_from[7]; +extern const char smtp_subject[10]; +extern const char smtp_quit[7]; +extern const char smtp_crnl[3]; +extern const char smtp_crnlperiodcrnl[6]; diff --git a/uip/apps/smtp/smtp.c b/uip/apps/smtp/smtp.c new file mode 100644 index 0000000..a860006 --- /dev/null +++ b/uip/apps/smtp/smtp.c @@ -0,0 +1,262 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup smtp SMTP E-mail sender + * @{ + * + * The Simple Mail Transfer Protocol (SMTP) as defined by RFC821 is + * the standard way of sending and transfering e-mail on the + * Internet. This simple example implementation is intended as an + * example of how to implement protocols in uIP, and is able to send + * out e-mail but has not been extensively tested. + */ + +/** + * \file + * SMTP example implementation + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2004, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * $Id: smtp.c,v 1.4 2006/06/11 21:46:37 adam Exp $ + */ +#include "smtp.h" + +#include "smtp-strings.h" +#include "psock.h" +#include "uip.h" + +#include + +static struct smtp_state s; + +static char *localhostname; +static uip_ipaddr_t smtpserver; + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +#define ISO_period 0x2e + +#define ISO_2 0x32 +#define ISO_3 0x33 +#define ISO_4 0x34 +#define ISO_5 0x35 + + +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(smtp_thread(void)) +{ + PSOCK_BEGIN(&s.psock); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(strncmp(s.inputbuffer, smtp_220, 3) != 0) { + PSOCK_CLOSE(&s.psock); + smtp_done(2); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_helo); + PSOCK_SEND_STR(&s.psock, localhostname); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(3); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_mail_from); + PSOCK_SEND_STR(&s.psock, s.from); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(4); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_rcpt_to); + PSOCK_SEND_STR(&s.psock, s.to); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(5); + PSOCK_EXIT(&s.psock); + } + + if(s.cc != 0) { + PSOCK_SEND_STR(&s.psock, (char *)smtp_rcpt_to); + PSOCK_SEND_STR(&s.psock, s.cc); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(6); + PSOCK_EXIT(&s.psock); + } + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_data); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_3) { + PSOCK_CLOSE(&s.psock); + smtp_done(7); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_to); + PSOCK_SEND_STR(&s.psock, s.to); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + if(s.cc != 0) { + PSOCK_SEND_STR(&s.psock, (char *)smtp_cc); + PSOCK_SEND_STR(&s.psock, s.cc); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_from); + PSOCK_SEND_STR(&s.psock, s.from); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_SEND_STR(&s.psock, (char *)smtp_subject); + PSOCK_SEND_STR(&s.psock, s.subject); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_SEND(&s.psock, s.msg, s.msglen); + + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnlperiodcrnl); + + PSOCK_READTO(&s.psock, ISO_nl); + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(8); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_quit); + smtp_done(SMTP_ERR_OK); + PSOCK_END(&s.psock); +} +/*---------------------------------------------------------------------------*/ +void +smtp_appcall(void) +{ + if(uip_closed()) { + s.connected = 0; + return; + } + if(uip_aborted() || uip_timedout()) { + s.connected = 0; + smtp_done(1); + return; + } + smtp_thread(); +} +/*---------------------------------------------------------------------------*/ +/** + * Specificy an SMTP server and hostname. + * + * This function is used to configure the SMTP module with an SMTP + * server and the hostname of the host. + * + * \param lhostname The hostname of the uIP host. + * + * \param server A pointer to a 4-byte array representing the IP + * address of the SMTP server to be configured. + */ +void +smtp_configure(char *lhostname, void *server) +{ + localhostname = lhostname; + uip_ipaddr_copy(smtpserver, server); +} +/*---------------------------------------------------------------------------*/ +/** + * Send an e-mail. + * + * \param to The e-mail address of the receiver of the e-mail. + * \param cc The e-mail address of the CC: receivers of the e-mail. + * \param from The e-mail address of the sender of the e-mail. + * \param subject The subject of the e-mail. + * \param msg The actual e-mail message. + * \param msglen The length of the e-mail message. + */ +unsigned char +smtp_send(char *to, char *cc, char *from, + char *subject, char *msg, u16_t msglen) +{ + struct uip_conn *conn; + + conn = uip_connect(smtpserver, HTONS(25)); + if(conn == NULL) { + return 0; + } + s.connected = 1; + s.to = to; + s.cc = cc; + s.from = from; + s.subject = subject; + s.msg = msg; + s.msglen = msglen; + + PSOCK_INIT(&s.psock, s.inputbuffer, sizeof(s.inputbuffer)); + + return 1; +} +/*---------------------------------------------------------------------------*/ +void +smtp_init(void) +{ + s.connected = 0; +} +/*---------------------------------------------------------------------------*/ +/** @} */ +/** @} */ diff --git a/uip/apps/smtp/smtp.h b/uip/apps/smtp/smtp.h new file mode 100644 index 0000000..44d0766 --- /dev/null +++ b/uip/apps/smtp/smtp.h @@ -0,0 +1,103 @@ + +/** + * \addtogroup smtp + * @{ + */ + + +/** + * \file + * SMTP header file + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: smtp.h,v 1.4 2006/06/11 21:46:37 adam Exp $ + * + */ +#ifndef __SMTP_H__ +#define __SMTP_H__ + +#include "uipopt.h" + +/** + * Error number that signifies a non-error condition. + */ +#define SMTP_ERR_OK 0 + +/** + * Callback function that is called when an e-mail transmission is + * done. + * + * This function must be implemented by the module that uses the SMTP + * module. + * + * \param error The number of the error if an error occured, or + * SMTP_ERR_OK. + */ +void smtp_done(unsigned char error); + +void smtp_init(void); + +/* Functions. */ +void smtp_configure(char *localhostname, u16_t *smtpserver); +unsigned char smtp_send(char *to, char *from, + char *subject, char *msg, + u16_t msglen); +#define SMTP_SEND(to, cc, from, subject, msg) \ + smtp_send(to, cc, from, subject, msg, strlen(msg)) + +void smtp_appcall(void); + +struct smtp_state { + u8_t state; + char *to; + char *from; + char *subject; + char *msg; + u16_t msglen; + + u16_t sentlen, textlen; + u16_t sendptr; + +}; + + +#ifndef UIP_APPCALL +#define UIP_APPCALL smtp_appcall +#endif +typedef struct smtp_state uip_tcp_appstate_t; + + +#endif /* __SMTP_H__ */ + +/** @} */ diff --git a/uip/apps/telnet/Makefile.telnet b/uip/apps/telnet/Makefile.telnet new file mode 100644 index 0000000..8b94786 --- /dev/null +++ b/uip/apps/telnet/Makefile.telnet @@ -0,0 +1 @@ +APP_SOURCES += telnet.c diff --git a/uip/apps/telnet/telnet.c b/uip/apps/telnet/telnet.c new file mode 100644 index 0000000..f72b6fc --- /dev/null +++ b/uip/apps/telnet/telnet.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: telnet.c,v 1.1.2.3 2003/10/06 11:20:45 adam Exp $ + * + */ + +#include "uip.h" + +#include "telnet.h" + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +#define FLAG_CLOSE 1 +#define FLAG_ABORT 2 +/*-----------------------------------------------------------------------------------*/ +unsigned char +telnet_send(struct telnet_state *s, char *text, u16_t len) +{ + if(s->text != NULL) { + return 1; + } + s->text = text; + s->textlen = len; + s->sentlen = 0; + return 0; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char +telnet_close(struct telnet_state *s) +{ + s->flags = FLAG_CLOSE; + if(s->text != NULL) { + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char +telnet_abort(struct telnet_state *s) +{ + s->flags = FLAG_ABORT; + if(s->text != NULL) { + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +static void +acked(struct telnet_state *s) +{ + s->textlen -= s->sentlen; + if(s->textlen == 0) { + s->text = NULL; + telnet_sent(s); + } else { + s->text += s->sentlen; + } + s->sentlen = 0; +} +/*-----------------------------------------------------------------------------------*/ +static void +senddata(struct telnet_state *s) +{ + if(s->text == NULL) { + uip_send(s->text, 0); + return; + } + if(s->textlen > uip_mss()) { + s->sentlen = uip_mss(); + } else { + s->sentlen = s->textlen; + } + uip_send(s->text, s->sentlen); +} +/*-----------------------------------------------------------------------------------*/ +void telnet_app(void) +{ + struct telnet_state *s = (struct telnet_state *)uip_conn->appstate; + + if(uip_connected()) { + s->flags = 0; + telnet_connected(s); + senddata(s); + return; + } + + if(uip_closed()) { + telnet_closed(s); + } + + if(uip_aborted()) { + telnet_aborted(s); + } + if(uip_timedout()) { + telnet_timedout(s); + } + + + if(s->flags & FLAG_CLOSE) { + uip_close(); + return; + } + if(s->flags & FLAG_ABORT) { + uip_abort(); + return; + } + if(uip_acked()) { + acked(s); + } + if(uip_newdata()) { + telnet_newdata(s, (char *)uip_appdata, uip_datalen()); + } + if(uip_rexmit() || + uip_newdata() || + uip_acked()) { + senddata(s); + } else if(uip_poll()) { + senddata(s); + } +} +/*-----------------------------------------------------------------------------------*/ diff --git a/uip/apps/telnet/telnet.h b/uip/apps/telnet/telnet.h new file mode 100644 index 0000000..a48c8ee --- /dev/null +++ b/uip/apps/telnet/telnet.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: telnet.h,v 1.1.2.4 2003/10/06 22:56:45 adam Exp $ + * + */ +#ifndef __TELNET_H__ +#define __TELNET_H__ + +struct telnet_state { + unsigned char flags; + char *text; + u16_t textlen; + u16_t sentlen; +}; + +typedef struct telnet_state uip_tcp_appstate_t; +void telnet_app(void); + +#ifndef UIP_APPCALL +#define UIP_APPCALL telnet_app +#endif + +#ifndef UIP_APPSTATE_SIZE +#define UIP_APPSTATE_SIZE (sizeof(struct telnet_state)) +#endif + + +unsigned char telnet_send(struct telnet_state *s, char *text, u16_t len); +unsigned char telnet_close(struct telnet_state *s); +unsigned char telnet_abort(struct telnet_state *s); + +/* Callbacks, must be implemented by the caller. */ +void telnet_connected(struct telnet_state *s); +void telnet_closed(struct telnet_state *s); +void telnet_sent(struct telnet_state *s); +void telnet_aborted(struct telnet_state *s); +void telnet_timedout(struct telnet_state *s); +void telnet_newdata(struct telnet_state *s, char *data, u16_t len); +#endif /* __TELNET_H__ */ diff --git a/uip/apps/telnetd/Makefile.telnetd b/uip/apps/telnetd/Makefile.telnetd new file mode 100644 index 0000000..afb1b59 --- /dev/null +++ b/uip/apps/telnetd/Makefile.telnetd @@ -0,0 +1 @@ +APP_SOURCES += telnetd.c shell.c memb.c diff --git a/uip/apps/telnetd/shell.c b/uip/apps/telnetd/shell.c new file mode 100644 index 0000000..9345cae --- /dev/null +++ b/uip/apps/telnetd/shell.c @@ -0,0 +1,123 @@ + /* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: shell.c,v 1.1 2006/06/07 09:43:54 adam Exp $ + * + */ + +#include "shell.h" + +#include + +struct ptentry { + char *commandstr; + void (* pfunc)(char *str); +}; + +#define SHELL_PROMPT "uIP 1.0> " + +/*---------------------------------------------------------------------------*/ +static void +parse(register char *str, struct ptentry *t) +{ + struct ptentry *p; + for(p = t; p->commandstr != NULL; ++p) { + if(strncmp(p->commandstr, str, strlen(p->commandstr)) == 0) { + break; + } + } + + p->pfunc(str); +} +/*---------------------------------------------------------------------------*/ +static void +inttostr(register char *str, unsigned int i) +{ + str[0] = '0' + i / 100; + if(str[0] == '0') { + str[0] = ' '; + } + str[1] = '0' + (i / 10) % 10; + if(str[0] == ' ' && str[1] == '0') { + str[1] = ' '; + } + str[2] = '0' + i % 10; + str[3] = ' '; + str[4] = 0; +} +/*---------------------------------------------------------------------------*/ +static void +help(char *str) +{ + shell_output("Available commands:", ""); + shell_output("stats - show network statistics", ""); + shell_output("conn - show TCP connections", ""); + shell_output("help, ? - show help", ""); + shell_output("exit - exit shell", ""); +} +/*---------------------------------------------------------------------------*/ +static void +unknown(char *str) +{ + if(strlen(str) > 0) { + shell_output("Unknown command: ", str); + } +} +/*---------------------------------------------------------------------------*/ +static struct ptentry parsetab[] = + {{"stats", help}, + {"conn", help}, + {"help", help}, + {"exit", shell_quit}, + {"?", help}, + + /* Default action */ + {NULL, unknown}}; +/*---------------------------------------------------------------------------*/ +void +shell_init(void) +{ +} +/*---------------------------------------------------------------------------*/ +void +shell_start(void) +{ + shell_output("uIP command shell", ""); + shell_output("Type '?' and return for help", ""); + shell_prompt(SHELL_PROMPT); +} +/*---------------------------------------------------------------------------*/ +void +shell_input(char *cmd) +{ + parse(cmd, parsetab); + shell_prompt(SHELL_PROMPT); +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/telnetd/shell.h b/uip/apps/telnetd/shell.h new file mode 100644 index 0000000..b57d7be --- /dev/null +++ b/uip/apps/telnetd/shell.h @@ -0,0 +1,104 @@ +/** + * \file + * Interface for the Contiki shell. + * \author Adam Dunkels + * + * Some of the functions declared in this file must be implemented as + * a shell back-end in the architecture specific files of a Contiki + * port. + */ + + +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki desktop OS. + * + * $Id: shell.h,v 1.1 2006/06/07 09:43:54 adam Exp $ + * + */ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +/** + * Initialize the shell. + * + * Called when the shell front-end process starts. This function may + * be used to start listening for signals. + */ +void shell_init(void); + +/** + * Start the shell back-end. + * + * Called by the front-end when a new shell is started. + */ +void shell_start(void); + +/** + * Process a shell command. + * + * This function will be called by the shell GUI / telnet server whan + * a command has been entered that should be processed by the shell + * back-end. + * + * \param command The command to be processed. + */ +void shell_input(char *command); + +/** + * Quit the shell. + * + */ +void shell_quit(char *); + + +/** + * Print a string to the shell window. + * + * This function is implemented by the shell GUI / telnet server and + * can be called by the shell back-end to output a string in the + * shell window. The string is automatically appended with a linebreak. + * + * \param str1 The first half of the string to be output. + * \param str2 The second half of the string to be output. + */ +void shell_output(char *str1, char *str2); + +/** + * Print a prompt to the shell window. + * + * This function can be used by the shell back-end to print out a + * prompt to the shell window. + * + * \param prompt The prompt to be printed. + * + */ +void shell_prompt(char *prompt); + +#endif /* __SHELL_H__ */ diff --git a/uip/apps/telnetd/telnetd.c b/uip/apps/telnetd/telnetd.c new file mode 100644 index 0000000..7a5ae85 --- /dev/null +++ b/uip/apps/telnetd/telnetd.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $ + * + */ + +#include "uip.h" +#include "telnetd.h" +#include "memb.h" +#include "shell.h" + +#include + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +struct telnetd_line { + char line[TELNETD_CONF_LINELEN]; +}; +MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); + +#define STATE_NORMAL 0 +#define STATE_IAC 1 +#define STATE_WILL 2 +#define STATE_WONT 3 +#define STATE_DO 4 +#define STATE_DONT 5 +#define STATE_CLOSE 6 + +static struct telnetd_state s; + +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 +/*---------------------------------------------------------------------------*/ +static char * +alloc_line(void) +{ + return memb_alloc(&linemem); +} +/*---------------------------------------------------------------------------*/ +static void +dealloc_line(char *line) +{ + memb_free(&linemem, line); +} +/*---------------------------------------------------------------------------*/ +void +shell_quit(char *str) +{ + s.state = STATE_CLOSE; +} +/*---------------------------------------------------------------------------*/ +static void +sendline(char *line) +{ + static unsigned int i; + + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + if(s.lines[i] == NULL) { + s.lines[i] = line; + break; + } + } + if(i == TELNETD_CONF_NUMLINES) { + dealloc_line(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_prompt(char *str) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + strncpy(line, str, TELNETD_CONF_LINELEN); + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_output(char *str1, char *str2) +{ + static unsigned len; + char *line; + + line = alloc_line(); + if(line != NULL) { + len = strlen(str1); + strncpy(line, str1, TELNETD_CONF_LINELEN); + if(len < TELNETD_CONF_LINELEN) { + strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); + } + len = strlen(line); + if(len < TELNETD_CONF_LINELEN - 2) { + line[len] = ISO_cr; + line[len+1] = ISO_nl; + line[len+2] = 0; + } + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +telnetd_init(void) +{ + uip_listen(HTONS(23)); + memb_init(&linemem); + shell_init(); +} +/*---------------------------------------------------------------------------*/ +static void +acked(void) +{ + static unsigned int i; + + while(s.numsent > 0) { + dealloc_line(s.lines[0]); + for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) { + s.lines[i - 1] = s.lines[i]; + } + s.lines[TELNETD_CONF_NUMLINES - 1] = NULL; + --s.numsent; + } +} +/*---------------------------------------------------------------------------*/ +static void +senddata(void) +{ + static char *bufptr, *lineptr; + static int buflen, linelen; + + bufptr = uip_appdata; + buflen = 0; + for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES && + s.lines[s.numsent] != NULL ; ++s.numsent) { + lineptr = s.lines[s.numsent]; + linelen = strlen(lineptr); + if(linelen > TELNETD_CONF_LINELEN) { + linelen = TELNETD_CONF_LINELEN; + } + if(buflen + linelen < uip_mss()) { + memcpy(bufptr, lineptr, linelen); + bufptr += linelen; + buflen += linelen; + } else { + break; + } + } + uip_send(uip_appdata, buflen); +} +/*---------------------------------------------------------------------------*/ +static void +closed(void) +{ + static unsigned int i; + + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + if(s.lines[i] != NULL) { + dealloc_line(s.lines[i]); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +get_char(u8_t c) +{ + if(c == ISO_cr) { + return; + } + + s.buf[(int)s.bufptr] = c; + if(s.buf[(int)s.bufptr] == ISO_nl || + s.bufptr == sizeof(s.buf) - 1) { + if(s.bufptr > 0) { + s.buf[(int)s.bufptr] = 0; + /* petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/ + } + shell_input(s.buf); + s.bufptr = 0; + } else { + ++s.bufptr; + } +} +/*---------------------------------------------------------------------------*/ +static void +sendopt(u8_t option, u8_t value) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + line[0] = TELNET_IAC; + line[1] = option; + line[2] = value; + line[3] = 0; + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +static void +newdata(void) +{ + u16_t len; + u8_t c; + char *dataptr; + + + len = uip_datalen(); + dataptr = (char *)uip_appdata; + + while(len > 0 && s.bufptr < sizeof(s.buf)) { + c = *dataptr; + ++dataptr; + --len; + switch(s.state) { + case STATE_IAC: + if(c == TELNET_IAC) { + get_char(c); + s.state = STATE_NORMAL; + } else { + switch(c) { + case TELNET_WILL: + s.state = STATE_WILL; + break; + case TELNET_WONT: + s.state = STATE_WONT; + break; + case TELNET_DO: + s.state = STATE_DO; + break; + case TELNET_DONT: + s.state = STATE_DONT; + break; + default: + s.state = STATE_NORMAL; + break; + } + } + break; + case STATE_WILL: + /* Reply with a DONT */ + sendopt(TELNET_DONT, c); + s.state = STATE_NORMAL; + break; + + case STATE_WONT: + /* Reply with a DONT */ + sendopt(TELNET_DONT, c); + s.state = STATE_NORMAL; + break; + case STATE_DO: + /* Reply with a WONT */ + sendopt(TELNET_WONT, c); + s.state = STATE_NORMAL; + break; + case STATE_DONT: + /* Reply with a WONT */ + sendopt(TELNET_WONT, c); + s.state = STATE_NORMAL; + break; + case STATE_NORMAL: + if(c == TELNET_IAC) { + s.state = STATE_IAC; + } else { + get_char(c); + } + break; + } + + + } + +} +/*---------------------------------------------------------------------------*/ +void +telnetd_appcall(void) +{ + static unsigned int i; + if(uip_connected()) { + /* tcp_markconn(uip_conn, &s);*/ + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + s.lines[i] = NULL; + } + s.bufptr = 0; + s.state = STATE_NORMAL; + + shell_start(); + } + + if(s.state == STATE_CLOSE) { + s.state = STATE_NORMAL; + uip_close(); + return; + } + + if(uip_closed() || + uip_aborted() || + uip_timedout()) { + closed(); + } + + if(uip_acked()) { + acked(); + } + + if(uip_newdata()) { + newdata(); + } + + if(uip_rexmit() || + uip_newdata() || + uip_acked() || + uip_connected() || + uip_poll()) { + senddata(); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/telnetd/telnetd.h b/uip/apps/telnetd/telnetd.h new file mode 100644 index 0000000..2ee8acd --- /dev/null +++ b/uip/apps/telnetd/telnetd.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: telnetd.h,v 1.2 2006/06/07 09:43:54 adam Exp $ + * + */ +#ifndef __TELNETD_H__ +#define __TELNETD_H__ + +#include "uipopt.h" + +void telnetd_appcall(void); + +#ifndef TELNETD_CONF_LINELEN +#define TELNETD_CONF_LINELEN 40 +#endif +#ifndef TELNETD_CONF_NUMLINES +#define TELNETD_CONF_NUMLINES 16 +#endif + +struct telnetd_state { + char *lines[TELNETD_CONF_NUMLINES]; + char buf[TELNETD_CONF_LINELEN]; + char bufptr; + u8_t numsent; + u8_t state; +}; + +typedef struct telnetd_state uip_tcp_appstate_t; + +#ifndef UIP_APPCALL +#define UIP_APPCALL telnetd_appcall +#endif + +#endif /* __TELNETD_H__ */ diff --git a/uip/apps/webclient/Makefile.webclient b/uip/apps/webclient/Makefile.webclient new file mode 100644 index 0000000..e6e7f08 --- /dev/null +++ b/uip/apps/webclient/Makefile.webclient @@ -0,0 +1 @@ +APP_SOURCES += webclient-strings.c webclient.c diff --git a/uip/apps/webclient/makestrings b/uip/apps/webclient/makestrings new file mode 100755 index 0000000..6dec075 --- /dev/null +++ b/uip/apps/webclient/makestrings @@ -0,0 +1,40 @@ +#!/usr/bin/perl + + +sub stringify { + my $name = shift(@_); + open(OUTPUTC, "> $name.c"); + open(OUTPUTH, "> $name.h"); + + open(FILE, "$name"); + + while() { + if(/(.+) "(.+)"/) { + $var = $1; + $data = $2; + + $datan = $data; + $datan =~ s/\\r/\r/g; + $datan =~ s/\\n/\n/g; + $datan =~ s/\\01/\01/g; + $datan =~ s/\\0/\0/g; + + printf(OUTPUTC "const char $var\[%d] = \n", length($datan) + 1); + printf(OUTPUTC "/* \"$data\" */\n"); + printf(OUTPUTC "{"); + for($j = 0; $j < length($datan); $j++) { + printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1))); + } + printf(OUTPUTC "0 };\n"); + + printf(OUTPUTH "extern const char $var\[%d];\n", length($datan) + 1); + + } + } + close(OUTPUTC); + close(OUTPUTH); +} +stringify("webclient-strings"); + +exit 0; + diff --git a/uip/apps/webclient/webclient-strings b/uip/apps/webclient/webclient-strings new file mode 100644 index 0000000..a331397 --- /dev/null +++ b/uip/apps/webclient/webclient-strings @@ -0,0 +1,31 @@ +http_http "http://" +http_200 "200 " +http_301 "301 " +http_302 "302 " +http_get "GET " +http_10 "HTTP/1.0" +http_11 "HTTP/1.1" +http_content_type "content-type: " +http_texthtml "text/html" +http_location "location: " +http_host "host: " +http_crnl "\r\n" +http_index_html "/index.html" +http_404_html "/404.html" +http_content_type_html "Content-type: text/html\r\n\r\n" +http_content_type_css "Content-type: text/css\r\n\r\n" +http_content_type_text "Content-type: text/text\r\n\r\n" +http_content_type_png "Content-type: image/png\r\n\r\n" +http_content_type_gif "Content-type: image/gif\r\n\r\n" +http_content_type_jpg "Content-type: image/jpeg\r\n\r\n" +http_content_type_binary "Content-type: application/octet-stream\r\n\r\n" +http_html ".html" +http_shtml ".shtml" +http_htm ".htm" +http_css ".css" +http_png ".png" +http_gif ".gif" +http_jpg ".jpg" +http_text ".text" +http_txt ".txt" +http_user_agent_fields "Connection: close\r\nUser-Agent: uIP/1.0 (; http://www.sics.se/~adam/uip/)\r\n\r\n" diff --git a/uip/apps/webclient/webclient-strings.c b/uip/apps/webclient/webclient-strings.c new file mode 100644 index 0000000..9472330 --- /dev/null +++ b/uip/apps/webclient/webclient-strings.c @@ -0,0 +1,93 @@ +const char http_http[8] = +/* "http://" */ +{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0 }; +const char http_200[5] = +/* "200 " */ +{0x32, 0x30, 0x30, 0x20, 0 }; +const char http_301[5] = +/* "301 " */ +{0x33, 0x30, 0x31, 0x20, 0 }; +const char http_302[5] = +/* "302 " */ +{0x33, 0x30, 0x32, 0x20, 0 }; +const char http_get[5] = +/* "GET " */ +{0x47, 0x45, 0x54, 0x20, 0 }; +const char http_10[9] = +/* "HTTP/1.0" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0 }; +const char http_11[9] = +/* "HTTP/1.1" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0 }; +const char http_content_type[15] = +/* "content-type: " */ +{0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0 }; +const char http_texthtml[10] = +/* "text/html" */ +{0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_location[11] = +/* "location: " */ +{0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0 }; +const char http_host[7] = +/* "host: " */ +{0x68, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0 }; +const char http_crnl[3] = +/* "\r\n" */ +{0xd, 0xa, 0 }; +const char http_index_html[12] = +/* "/index.html" */ +{0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_404_html[10] = +/* "/404.html" */ +{0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_content_type_html[28] = +/* "Content-type: text/html\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_css [27] = +/* "Content-type: text/css\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_text[28] = +/* "Content-type: text/text\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x65, 0x78, 0x74, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_png [28] = +/* "Content-type: image/png\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_gif [28] = +/* "Content-type: image/gif\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_jpg [29] = +/* "Content-type: image/jpeg\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_binary[43] = +/* "Content-type: application/octet-stream\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_html[6] = +/* ".html" */ +{0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_shtml[7] = +/* ".shtml" */ +{0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_htm[5] = +/* ".htm" */ +{0x2e, 0x68, 0x74, 0x6d, 0 }; +const char http_css[5] = +/* ".css" */ +{0x2e, 0x63, 0x73, 0x73, 0 }; +const char http_png[5] = +/* ".png" */ +{0x2e, 0x70, 0x6e, 0x67, 0 }; +const char http_gif[5] = +/* ".gif" */ +{0x2e, 0x67, 0x69, 0x66, 0 }; +const char http_jpg[5] = +/* ".jpg" */ +{0x2e, 0x6a, 0x70, 0x67, 0 }; +const char http_text[6] = +/* ".text" */ +{0x2e, 0x74, 0x65, 0x78, 0x74, 0 }; +const char http_txt[5] = +/* ".txt" */ +{0x2e, 0x74, 0x78, 0x74, 0 }; +const char http_user_agent_fields[77] = +/* "Connection: close\r\nUser-Agent: uIP/1.0 (; http://www.sics.se/~adam/uip/)\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x28, 0x3b, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0x29, 0xd, 0xa, 0xd, 0xa, 0 }; diff --git a/uip/apps/webclient/webclient-strings.h b/uip/apps/webclient/webclient-strings.h new file mode 100644 index 0000000..9e3ec93 --- /dev/null +++ b/uip/apps/webclient/webclient-strings.h @@ -0,0 +1,31 @@ +extern const char http_http[8]; +extern const char http_200[5]; +extern const char http_301[5]; +extern const char http_302[5]; +extern const char http_get[5]; +extern const char http_10[9]; +extern const char http_11[9]; +extern const char http_content_type[15]; +extern const char http_texthtml[10]; +extern const char http_location[11]; +extern const char http_host[7]; +extern const char http_crnl[3]; +extern const char http_index_html[12]; +extern const char http_404_html[10]; +extern const char http_content_type_html[28]; +extern const char http_content_type_css [27]; +extern const char http_content_type_text[28]; +extern const char http_content_type_png [28]; +extern const char http_content_type_gif [28]; +extern const char http_content_type_jpg [29]; +extern const char http_content_type_binary[43]; +extern const char http_html[6]; +extern const char http_shtml[7]; +extern const char http_htm[5]; +extern const char http_css[5]; +extern const char http_png[5]; +extern const char http_gif[5]; +extern const char http_jpg[5]; +extern const char http_text[6]; +extern const char http_txt[5]; +extern const char http_user_agent_fields[77]; diff --git a/uip/apps/webclient/webclient.c b/uip/apps/webclient/webclient.c new file mode 100644 index 0000000..746c008 --- /dev/null +++ b/uip/apps/webclient/webclient.c @@ -0,0 +1,439 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup webclient Web client + * @{ + * + * This example shows a HTTP client that is able to download web pages + * and files from web servers. It requires a number of callback + * functions to be implemented by the module that utilizes the code: + * webclient_datahandler(), webclient_connected(), + * webclient_timedout(), webclient_aborted(), webclient_closed(). + */ + +/** + * \file + * Implementation of the HTTP client. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: webclient.c,v 1.2 2006/06/11 21:46:37 adam Exp $ + * + */ + +#include "uip.h" +#include "uiplib.h" +#include "webclient.h" +#include "resolv.h" + +#include + +#define WEBCLIENT_TIMEOUT 100 + +#define WEBCLIENT_STATE_STATUSLINE 0 +#define WEBCLIENT_STATE_HEADERS 1 +#define WEBCLIENT_STATE_DATA 2 +#define WEBCLIENT_STATE_CLOSE 3 + +#define HTTPFLAG_NONE 0 +#define HTTPFLAG_OK 1 +#define HTTPFLAG_MOVED 2 +#define HTTPFLAG_ERROR 3 + + +#define ISO_nl 0x0a +#define ISO_cr 0x0d +#define ISO_space 0x20 + + +static struct webclient_state s; + +/*-----------------------------------------------------------------------------------*/ +char * +webclient_mimetype(void) +{ + return s.mimetype; +} +/*-----------------------------------------------------------------------------------*/ +char * +webclient_filename(void) +{ + return s.file; +} +/*-----------------------------------------------------------------------------------*/ +char * +webclient_hostname(void) +{ + return s.host; +} +/*-----------------------------------------------------------------------------------*/ +unsigned short +webclient_port(void) +{ + return s.port; +} +/*-----------------------------------------------------------------------------------*/ +void +webclient_init(void) +{ + +} +/*-----------------------------------------------------------------------------------*/ +static void +init_connection(void) +{ + s.state = WEBCLIENT_STATE_STATUSLINE; + + s.getrequestleft = sizeof(http_get) - 1 + 1 + + sizeof(http_10) - 1 + + sizeof(http_crnl) - 1 + + sizeof(http_host) - 1 + + sizeof(http_crnl) - 1 + + strlen(http_user_agent_fields) + + strlen(s.file) + strlen(s.host); + s.getrequestptr = 0; + + s.httpheaderlineptr = 0; +} +/*-----------------------------------------------------------------------------------*/ +void +webclient_close(void) +{ + s.state = WEBCLIENT_STATE_CLOSE; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char +webclient_get(char *host, u16_t port, char *file) +{ + struct uip_conn *conn; + uip_ipaddr_t *ipaddr; + static uip_ipaddr_t addr; + + /* First check if the host is an IP address. */ + ipaddr = &addr; + if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) { + ipaddr = (uip_ipaddr_t *)resolv_lookup(host); + + if(ipaddr == NULL) { + return 0; + } + } + + conn = uip_connect(ipaddr, htons(port)); + + if(conn == NULL) { + return 0; + } + + s.port = port; + strncpy(s.file, file, sizeof(s.file)); + strncpy(s.host, host, sizeof(s.host)); + + init_connection(); + return 1; +} +/*-----------------------------------------------------------------------------------*/ +static unsigned char * +copy_string(unsigned char *dest, + const unsigned char *src, unsigned char len) +{ + strncpy(dest, src, len); + return dest + len; +} +/*-----------------------------------------------------------------------------------*/ +static void +senddata(void) +{ + u16_t len; + char *getrequest; + char *cptr; + + if(s.getrequestleft > 0) { + cptr = getrequest = (char *)uip_appdata; + + cptr = copy_string(cptr, http_get, sizeof(http_get) - 1); + cptr = copy_string(cptr, s.file, strlen(s.file)); + *cptr++ = ISO_space; + cptr = copy_string(cptr, http_10, sizeof(http_10) - 1); + + cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1); + + cptr = copy_string(cptr, http_host, sizeof(http_host) - 1); + cptr = copy_string(cptr, s.host, strlen(s.host)); + cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1); + + cptr = copy_string(cptr, http_user_agent_fields, + strlen(http_user_agent_fields)); + + len = s.getrequestleft > uip_mss()? + uip_mss(): + s.getrequestleft; + uip_send(&(getrequest[s.getrequestptr]), len); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +acked(void) +{ + u16_t len; + + if(s.getrequestleft > 0) { + len = s.getrequestleft > uip_mss()? + uip_mss(): + s.getrequestleft; + s.getrequestleft -= len; + s.getrequestptr += len; + } +} +/*-----------------------------------------------------------------------------------*/ +static u16_t +parse_statusline(u16_t len) +{ + char *cptr; + + while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) { + s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata; + ++((char *)uip_appdata); + --len; + if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) { + + if((strncmp(s.httpheaderline, http_10, + sizeof(http_10) - 1) == 0) || + (strncmp(s.httpheaderline, http_11, + sizeof(http_11) - 1) == 0)) { + cptr = &(s.httpheaderline[9]); + s.httpflag = HTTPFLAG_NONE; + if(strncmp(cptr, http_200, sizeof(http_200) - 1) == 0) { + /* 200 OK */ + s.httpflag = HTTPFLAG_OK; + } else if(strncmp(cptr, http_301, sizeof(http_301) - 1) == 0 || + strncmp(cptr, http_302, sizeof(http_302) - 1) == 0) { + /* 301 Moved permanently or 302 Found. Location: header line + will contain thw new location. */ + s.httpflag = HTTPFLAG_MOVED; + } else { + s.httpheaderline[s.httpheaderlineptr - 1] = 0; + } + } else { + uip_abort(); + webclient_aborted(); + return 0; + } + + /* We're done parsing the status line, so we reset the pointer + and start parsing the HTTP headers.*/ + s.httpheaderlineptr = 0; + s.state = WEBCLIENT_STATE_HEADERS; + break; + } else { + ++s.httpheaderlineptr; + } + } + return len; +} +/*-----------------------------------------------------------------------------------*/ +static char +casecmp(char *str1, const char *str2, char len) +{ + static char c; + + while(len > 0) { + c = *str1; + /* Force lower-case characters. */ + if(c & 0x40) { + c |= 0x20; + } + if(*str2 != c) { + return 1; + } + ++str1; + ++str2; + --len; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +static u16_t +parse_headers(u16_t len) +{ + char *cptr; + static unsigned char i; + + while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) { + s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata; + ++((char *)uip_appdata); + --len; + if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) { + /* We have an entire HTTP header line in s.httpheaderline, so + we parse it. */ + if(s.httpheaderline[0] == ISO_cr) { + /* This was the last header line (i.e., and empty "\r\n"), so + we are done with the headers and proceed with the actual + data. */ + s.state = WEBCLIENT_STATE_DATA; + return len; + } + + s.httpheaderline[s.httpheaderlineptr - 1] = 0; + /* Check for specific HTTP header fields. */ + if(casecmp(s.httpheaderline, http_content_type, + sizeof(http_content_type) - 1) == 0) { + /* Found Content-type field. */ + cptr = strchr(s.httpheaderline, ';'); + if(cptr != NULL) { + *cptr = 0; + } + strncpy(s.mimetype, s.httpheaderline + + sizeof(http_content_type) - 1, sizeof(s.mimetype)); + } else if(casecmp(s.httpheaderline, http_location, + sizeof(http_location) - 1) == 0) { + cptr = s.httpheaderline + + sizeof(http_location) - 1; + + if(strncmp(cptr, http_http, 7) == 0) { + cptr += 7; + for(i = 0; i < s.httpheaderlineptr - 7; ++i) { + if(*cptr == 0 || + *cptr == '/' || + *cptr == ' ' || + *cptr == ':') { + s.host[i] = 0; + break; + } + s.host[i] = *cptr; + ++cptr; + } + } + strncpy(s.file, cptr, sizeof(s.file)); + /* s.file[s.httpheaderlineptr - i] = 0;*/ + } + + + /* We're done parsing, so we reset the pointer and start the + next line. */ + s.httpheaderlineptr = 0; + } else { + ++s.httpheaderlineptr; + } + } + return len; +} +/*-----------------------------------------------------------------------------------*/ +static void +newdata(void) +{ + u16_t len; + + len = uip_datalen(); + + if(s.state == WEBCLIENT_STATE_STATUSLINE) { + len = parse_statusline(len); + } + + if(s.state == WEBCLIENT_STATE_HEADERS && len > 0) { + len = parse_headers(len); + } + + if(len > 0 && s.state == WEBCLIENT_STATE_DATA && + s.httpflag != HTTPFLAG_MOVED) { + webclient_datahandler((char *)uip_appdata, len); + } +} +/*-----------------------------------------------------------------------------------*/ +void +webclient_appcall(void) +{ + if(uip_connected()) { + s.timer = 0; + s.state = WEBCLIENT_STATE_STATUSLINE; + senddata(); + webclient_connected(); + return; + } + + if(s.state == WEBCLIENT_STATE_CLOSE) { + webclient_closed(); + uip_abort(); + return; + } + + if(uip_aborted()) { + webclient_aborted(); + } + if(uip_timedout()) { + webclient_timedout(); + } + + + if(uip_acked()) { + s.timer = 0; + acked(); + } + if(uip_newdata()) { + s.timer = 0; + newdata(); + } + if(uip_rexmit() || + uip_newdata() || + uip_acked()) { + senddata(); + } else if(uip_poll()) { + ++s.timer; + if(s.timer == WEBCLIENT_TIMEOUT) { + webclient_timedout(); + uip_abort(); + return; + } + /* senddata();*/ + } + + if(uip_closed()) { + if(s.httpflag != HTTPFLAG_MOVED) { + /* Send NULL data to signal EOF. */ + webclient_datahandler(NULL, 0); + } else { + if(resolv_lookup(s.host) == NULL) { + resolv_query(s.host); + } + webclient_get(s.host, s.port, s.file); + } + } +} +/*-----------------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/uip/apps/webclient/webclient.h b/uip/apps/webclient/webclient.h new file mode 100644 index 0000000..44cb95c --- /dev/null +++ b/uip/apps/webclient/webclient.h @@ -0,0 +1,228 @@ +/** + * \addtogroup webclient + * @{ + */ + +/** + * \file + * Header file for the HTTP client. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: webclient.h,v 1.2 2006/06/11 21:46:37 adam Exp $ + * + */ +#ifndef __WEBCLIENT_H__ +#define __WEBCLIENT_H__ + + +#include "webclient-strings.h" +#include "uipopt.h" + +#define WEBCLIENT_CONF_MAX_URLLEN 100 + +struct webclient_state { + u8_t timer; + u8_t state; + u8_t httpflag; + + u16_t port; + char host[40]; + char file[WEBCLIENT_CONF_MAX_URLLEN]; + u16_t getrequestptr; + u16_t getrequestleft; + + char httpheaderline[200]; + u16_t httpheaderlineptr; + + char mimetype[32]; +}; + +typedef struct webclient_state uip_tcp_appstate_t; +#define UIP_APPCALL webclient_appcall + +/** + * Callback function that is called from the webclient code when HTTP + * data has been received. + * + * This function must be implemented by the module that uses the + * webclient code. The function is called from the webclient module + * when HTTP data has been received. The function is not called when + * HTTP headers are received, only for the actual data. + * + * \note This function is called many times, repetedly, when data is + * being received, and not once when all data has been received. + * + * \param data A pointer to the data that has been received. + * \param len The length of the data that has been received. + */ +void webclient_datahandler(char *data, u16_t len); + +/** + * Callback function that is called from the webclient code when the + * HTTP connection has been connected to the web server. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_connected(void); + +/** + * Callback function that is called from the webclient code if the + * HTTP connection to the web server has timed out. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_timedout(void); + +/** + * Callback function that is called from the webclient code if the + * HTTP connection to the web server has been aborted by the web + * server. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_aborted(void); + +/** + * Callback function that is called from the webclient code when the + * HTTP connection to the web server has been closed. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_closed(void); + + + +/** + * Initialize the webclient module. + */ +void webclient_init(void); + +/** + * Open an HTTP connection to a web server and ask for a file using + * the GET method. + * + * This function opens an HTTP connection to the specified web server + * and requests the specified file using the GET method. When the HTTP + * connection has been connected, the webclient_connected() callback + * function is called and when the HTTP data arrives the + * webclient_datahandler() callback function is called. + * + * The callback function webclient_timedout() is called if the web + * server could not be contacted, and the webclient_aborted() callback + * function is called if the HTTP connection is aborted by the web + * server. + * + * When the HTTP request has been completed and the HTTP connection is + * closed, the webclient_closed() callback function will be called. + * + * \note If the function is passed a host name, it must already be in + * the resolver cache in order for the function to connect to the web + * server. It is therefore up to the calling module to implement the + * resolver calls and the signal handler used for reporting a resolv + * query answer. + * + * \param host A pointer to a string containing either a host name or + * a numerical IP address in dotted decimal notation (e.g., 192.168.23.1). + * + * \param port The port number to which to connect, in host byte order. + * + * \param file A pointer to the name of the file to get. + * + * \retval 0 if the host name could not be found in the cache, or + * if a TCP connection could not be created. + * + * \retval 1 if the connection was initiated. + */ +unsigned char webclient_get(char *host, u16_t port, char *file); + +/** + * Close the currently open HTTP connection. + */ +void webclient_close(void); +void webclient_appcall(void); + +/** + * Obtain the MIME type of the current HTTP data stream. + * + * \return A pointer to a string contaning the MIME type. The string + * may be empty if no MIME type was reported by the web server. + */ +char *webclient_mimetype(void); + +/** + * Obtain the filename of the current HTTP data stream. + * + * The filename of an HTTP request may be changed by the web server, + * and may therefore not be the same as when the original GET request + * was made with webclient_get(). This function is used for obtaining + * the current filename. + * + * \return A pointer to the current filename. + */ +char *webclient_filename(void); + +/** + * Obtain the hostname of the current HTTP data stream. + * + * The hostname of the web server of an HTTP request may be changed + * by the web server, and may therefore not be the same as when the + * original GET request was made with webclient_get(). This function + * is used for obtaining the current hostname. + * + * \return A pointer to the current hostname. + */ +char *webclient_hostname(void); + +/** + * Obtain the port number of the current HTTP data stream. + * + * The port number of an HTTP request may be changed by the web + * server, and may therefore not be the same as when the original GET + * request was made with webclient_get(). This function is used for + * obtaining the current port number. + * + * \return The port number of the current HTTP data stream, in host byte order. + */ +unsigned short webclient_port(void); + + + +#endif /* __WEBCLIENT_H__ */ + +/** @} */ diff --git a/uip/apps/webserver/Makefile.webserver b/uip/apps/webserver/Makefile.webserver new file mode 100644 index 0000000..7d3e086 --- /dev/null +++ b/uip/apps/webserver/Makefile.webserver @@ -0,0 +1 @@ +APP_SOURCES += httpd.c http-strings.c httpd-fs.c httpd-cgi.c diff --git a/uip/apps/webserver/http-strings b/uip/apps/webserver/http-strings new file mode 100644 index 0000000..d0b9121 --- /dev/null +++ b/uip/apps/webserver/http-strings @@ -0,0 +1,35 @@ +http_http "http://" +http_200 "200 " +http_301 "301 " +http_302 "302 " +http_get "GET " +http_10 "HTTP/1.0" +http_11 "HTTP/1.1" +http_content_type "content-type: " +http_texthtml "text/html" +http_location "location: " +http_host "host: " +http_crnl "\r\n" +http_index_html "/index.html" +http_404_html "/404.html" +http_referer "Referer:" +http_header_200 "HTTP/1.0 200 OK\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" +http_header_404 "HTTP/1.0 404 Not found\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" +http_content_type_plain "Content-type: text/plain\r\n\r\n" +http_content_type_html "Content-type: text/html\r\n\r\n" +http_content_type_css "Content-type: text/css\r\n\r\n" +http_content_type_text "Content-type: text/text\r\n\r\n" +http_content_type_png "Content-type: image/png\r\n\r\n" +http_content_type_gif "Content-type: image/gif\r\n\r\n" +http_content_type_jpg "Content-type: image/jpeg\r\n\r\n" +http_content_type_binary "Content-type: application/octet-stream\r\n\r\n" +http_html ".html" +http_shtml ".shtml" +http_htm ".htm" +http_css ".css" +http_png ".png" +http_gif ".gif" +http_jpg ".jpg" +http_text ".txt" +http_txt ".txt" + diff --git a/uip/apps/webserver/http-strings.c b/uip/apps/webserver/http-strings.c new file mode 100644 index 0000000..0d822ba --- /dev/null +++ b/uip/apps/webserver/http-strings.c @@ -0,0 +1,102 @@ +const char http_http[8] = +/* "http://" */ +{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, }; +const char http_200[5] = +/* "200 " */ +{0x32, 0x30, 0x30, 0x20, }; +const char http_301[5] = +/* "301 " */ +{0x33, 0x30, 0x31, 0x20, }; +const char http_302[5] = +/* "302 " */ +{0x33, 0x30, 0x32, 0x20, }; +const char http_get[5] = +/* "GET " */ +{0x47, 0x45, 0x54, 0x20, }; +const char http_10[9] = +/* "HTTP/1.0" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, }; +const char http_11[9] = +/* "HTTP/1.1" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, }; +const char http_content_type[15] = +/* "content-type: " */ +{0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, }; +const char http_texthtml[10] = +/* "text/html" */ +{0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_location[11] = +/* "location: " */ +{0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, }; +const char http_host[7] = +/* "host: " */ +{0x68, 0x6f, 0x73, 0x74, 0x3a, 0x20, }; +const char http_crnl[3] = +/* "\r\n" */ +{0xd, 0xa, }; +const char http_index_html[12] = +/* "/index.html" */ +{0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_404_html[10] = +/* "/404.html" */ +{0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_referer[9] = +/* "Referer:" */ +{0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x3a, }; +const char http_header_200[84] = +/* "HTTP/1.0 200 OK\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, }; +const char http_header_404[91] = +/* "HTTP/1.0 404 Not found\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x34, 0x30, 0x34, 0x20, 0x4e, 0x6f, 0x74, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0xd, 0xa, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, }; +const char http_content_type_plain[29] = +/* "Content-type: text/plain\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_html[28] = +/* "Content-type: text/html\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_css [27] = +/* "Content-type: text/css\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_text[28] = +/* "Content-type: text/text\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x65, 0x78, 0x74, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_png [28] = +/* "Content-type: image/png\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_gif [28] = +/* "Content-type: image/gif\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_jpg [29] = +/* "Content-type: image/jpeg\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_binary[43] = +/* "Content-type: application/octet-stream\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0xd, 0xa, 0xd, 0xa, }; +const char http_html[6] = +/* ".html" */ +{0x2e, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_shtml[7] = +/* ".shtml" */ +{0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_htm[5] = +/* ".htm" */ +{0x2e, 0x68, 0x74, 0x6d, }; +const char http_css[5] = +/* ".css" */ +{0x2e, 0x63, 0x73, 0x73, }; +const char http_png[5] = +/* ".png" */ +{0x2e, 0x70, 0x6e, 0x67, }; +const char http_gif[5] = +/* ".gif" */ +{0x2e, 0x67, 0x69, 0x66, }; +const char http_jpg[5] = +/* ".jpg" */ +{0x2e, 0x6a, 0x70, 0x67, }; +const char http_text[5] = +/* ".txt" */ +{0x2e, 0x74, 0x78, 0x74, }; +const char http_txt[5] = +/* ".txt" */ +{0x2e, 0x74, 0x78, 0x74, }; diff --git a/uip/apps/webserver/http-strings.h b/uip/apps/webserver/http-strings.h new file mode 100644 index 0000000..f121dd7 --- /dev/null +++ b/uip/apps/webserver/http-strings.h @@ -0,0 +1,34 @@ +extern const char http_http[8]; +extern const char http_200[5]; +extern const char http_301[5]; +extern const char http_302[5]; +extern const char http_get[5]; +extern const char http_10[9]; +extern const char http_11[9]; +extern const char http_content_type[15]; +extern const char http_texthtml[10]; +extern const char http_location[11]; +extern const char http_host[7]; +extern const char http_crnl[3]; +extern const char http_index_html[12]; +extern const char http_404_html[10]; +extern const char http_referer[9]; +extern const char http_header_200[84]; +extern const char http_header_404[91]; +extern const char http_content_type_plain[29]; +extern const char http_content_type_html[28]; +extern const char http_content_type_css [27]; +extern const char http_content_type_text[28]; +extern const char http_content_type_png [28]; +extern const char http_content_type_gif [28]; +extern const char http_content_type_jpg [29]; +extern const char http_content_type_binary[43]; +extern const char http_html[6]; +extern const char http_shtml[7]; +extern const char http_htm[5]; +extern const char http_css[5]; +extern const char http_png[5]; +extern const char http_gif[5]; +extern const char http_jpg[5]; +extern const char http_text[5]; +extern const char http_txt[5]; diff --git a/uip/apps/webserver/httpd-cgi.c b/uip/apps/webserver/httpd-cgi.c new file mode 100644 index 0000000..6257035 --- /dev/null +++ b/uip/apps/webserver/httpd-cgi.c @@ -0,0 +1,203 @@ +/** + * \addtogroup httpd + * @{ + */ + +/** + * \file + * Web server script interface + * \author + * Adam Dunkels + * + */ + +/* + * Copyright (c) 2001-2006, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: httpd-cgi.c,v 1.2 2006/06/11 21:46:37 adam Exp $ + * + */ + +#include "uip.h" +#include "psock.h" +#include "httpd.h" +#include "httpd-cgi.h" +#include "httpd-fs.h" + +#include +#include + +HTTPD_CGI_CALL(file, "file-stats", file_stats); +HTTPD_CGI_CALL(tcp, "tcp-connections", tcp_stats); +HTTPD_CGI_CALL(net, "net-stats", net_stats); + +static const struct httpd_cgi_call *calls[] = { &file, &tcp, &net, NULL }; + +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(nullfunction(struct httpd_state *s, char *ptr)) +{ + PSOCK_BEGIN(&s->sout); + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +httpd_cgifunction +httpd_cgi(char *name) +{ + const struct httpd_cgi_call **f; + + /* Find the matching name in the table, return the function. */ + for(f = calls; *f != NULL; ++f) { + if(strncmp((*f)->name, name, strlen((*f)->name)) == 0) { + return (*f)->function; + } + } + return nullfunction; +} +/*---------------------------------------------------------------------------*/ +static unsigned short +generate_file_stats(void *arg) +{ + char *f = (char *)arg; + return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, "%5u", httpd_fs_count(f)); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(file_stats(struct httpd_state *s, char *ptr)) +{ + PSOCK_BEGIN(&s->sout); + + PSOCK_GENERATOR_SEND(&s->sout, generate_file_stats, strchr(ptr, ' ') + 1); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static const char closed[] = /* "CLOSED",*/ +{0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0}; +static const char syn_rcvd[] = /* "SYN-RCVD",*/ +{0x53, 0x59, 0x4e, 0x2d, 0x52, 0x43, 0x56, + 0x44, 0}; +static const char syn_sent[] = /* "SYN-SENT",*/ +{0x53, 0x59, 0x4e, 0x2d, 0x53, 0x45, 0x4e, + 0x54, 0}; +static const char established[] = /* "ESTABLISHED",*/ +{0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, + 0x45, 0x44, 0}; +static const char fin_wait_1[] = /* "FIN-WAIT-1",*/ +{0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, + 0x54, 0x2d, 0x31, 0}; +static const char fin_wait_2[] = /* "FIN-WAIT-2",*/ +{0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, + 0x54, 0x2d, 0x32, 0}; +static const char closing[] = /* "CLOSING",*/ +{0x43, 0x4c, 0x4f, 0x53, 0x49, + 0x4e, 0x47, 0}; +static const char time_wait[] = /* "TIME-WAIT,"*/ +{0x54, 0x49, 0x4d, 0x45, 0x2d, 0x57, 0x41, + 0x49, 0x54, 0}; +static const char last_ack[] = /* "LAST-ACK"*/ +{0x4c, 0x41, 0x53, 0x54, 0x2d, 0x41, 0x43, + 0x4b, 0}; + +static const char *states[] = { + closed, + syn_rcvd, + syn_sent, + established, + fin_wait_1, + fin_wait_2, + closing, + time_wait, + last_ack}; + + +static unsigned short +generate_tcp_stats(void *arg) +{ + struct uip_conn *conn; + struct httpd_state *s = (struct httpd_state *)arg; + + conn = &uip_conns[s->count]; + return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, + "%d%u.%u.%u.%u:%u%s%u%u%c %c\r\n", + htons(conn->lport), + htons(conn->ripaddr[0]) >> 8, + htons(conn->ripaddr[0]) & 0xff, + htons(conn->ripaddr[1]) >> 8, + htons(conn->ripaddr[1]) & 0xff, + htons(conn->rport), + states[conn->tcpstateflags & UIP_TS_MASK], + conn->nrtx, + conn->timer, + (uip_outstanding(conn))? '*':' ', + (uip_stopped(conn))? '!':' '); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(tcp_stats(struct httpd_state *s, char *ptr)) +{ + + PSOCK_BEGIN(&s->sout); + + for(s->count = 0; s->count < UIP_CONNS; ++s->count) { + if((uip_conns[s->count].tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { + PSOCK_GENERATOR_SEND(&s->sout, generate_tcp_stats, s); + } + } + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static unsigned short +generate_net_stats(void *arg) +{ + struct httpd_state *s = (struct httpd_state *)arg; + return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, + "%5u\n", ((uip_stats_t *)&uip_stat)[s->count]); +} + +static +PT_THREAD(net_stats(struct httpd_state *s, char *ptr)) +{ + PSOCK_BEGIN(&s->sout); + +#if UIP_STATISTICS + + for(s->count = 0; s->count < sizeof(uip_stat) / sizeof(uip_stats_t); + ++s->count) { + PSOCK_GENERATOR_SEND(&s->sout, generate_net_stats, s); + } + +#endif /* UIP_STATISTICS */ + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/uip/apps/webserver/httpd-cgi.h b/uip/apps/webserver/httpd-cgi.h new file mode 100644 index 0000000..e6ba51e --- /dev/null +++ b/uip/apps/webserver/httpd-cgi.h @@ -0,0 +1,84 @@ +/** + * \addtogroup httpd + * @{ + */ + +/** + * \file + * Web server script interface header file + * \author + * Adam Dunkels + * + */ + + + +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: httpd-cgi.h,v 1.2 2006/06/11 21:46:38 adam Exp $ + * + */ + +#ifndef __HTTPD_CGI_H__ +#define __HTTPD_CGI_H__ + +#include "psock.h" +#include "httpd.h" + +typedef PT_THREAD((* httpd_cgifunction)(struct httpd_state *, char *)); + +httpd_cgifunction httpd_cgi(char *name); + +struct httpd_cgi_call { + const char *name; + const httpd_cgifunction function; +}; + +/** + * \brief HTTPD CGI function declaration + * \param name The C variable name of the function + * \param str The string name of the function, used in the script file + * \param function A pointer to the function that implements it + * + * This macro is used for declaring a HTTPD CGI + * function. This function is then added to the list of + * HTTPD CGI functions with the httpd_cgi_add() function. + * + * \hideinitializer + */ +#define HTTPD_CGI_CALL(name, str, function) \ +static PT_THREAD(function(struct httpd_state *, char *)); \ +static const struct httpd_cgi_call name = {str, function} + +void httpd_cgi_init(void); +#endif /* __HTTPD_CGI_H__ */ + +/** @} */ diff --git a/uip/apps/webserver/httpd-fs.c b/uip/apps/webserver/httpd-fs.c new file mode 100644 index 0000000..21185e8 --- /dev/null +++ b/uip/apps/webserver/httpd-fs.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * $Id: httpd-fs.c,v 1.1 2006/06/07 09:13:08 adam Exp $ + */ + +#include "httpd.h" +#include "httpd-fs.h" +#include "httpd-fsdata.h" + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +#include "httpd-fsdata.c" + +#if HTTPD_FS_STATISTICS +static u16_t count[HTTPD_FS_NUMFILES]; +#endif /* HTTPD_FS_STATISTICS */ + +/*-----------------------------------------------------------------------------------*/ +static u8_t +httpd_fs_strcmp(const char *str1, const char *str2) +{ + u8_t i; + i = 0; + loop: + + if(str2[i] == 0 || + str1[i] == '\r' || + str1[i] == '\n') { + return 0; + } + + if(str1[i] != str2[i]) { + return 1; + } + + + ++i; + goto loop; +} +/*-----------------------------------------------------------------------------------*/ +int +httpd_fs_open(const char *name, struct httpd_fs_file *file) +{ +#if HTTPD_FS_STATISTICS + u16_t i = 0; +#endif /* HTTPD_FS_STATISTICS */ + struct httpd_fsdata_file_noconst *f; + + for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT; + f != NULL; + f = (struct httpd_fsdata_file_noconst *)f->next) { + + if(httpd_fs_strcmp(name, f->name) == 0) { + file->data = f->data; + file->len = f->len; +#if HTTPD_FS_STATISTICS + ++count[i]; +#endif /* HTTPD_FS_STATISTICS */ + return 1; + } +#if HTTPD_FS_STATISTICS + ++i; +#endif /* HTTPD_FS_STATISTICS */ + + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void +httpd_fs_init(void) +{ +#if HTTPD_FS_STATISTICS + u16_t i; + for(i = 0; i < HTTPD_FS_NUMFILES; i++) { + count[i] = 0; + } +#endif /* HTTPD_FS_STATISTICS */ +} +/*-----------------------------------------------------------------------------------*/ +#if HTTPD_FS_STATISTICS +u16_t httpd_fs_count +(char *name) +{ + struct httpd_fsdata_file_noconst *f; + u16_t i; + + i = 0; + for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT; + f != NULL; + f = (struct httpd_fsdata_file_noconst *)f->next) { + + if(httpd_fs_strcmp(name, f->name) == 0) { + return count[i]; + } + ++i; + } + return 0; +} +#endif /* HTTPD_FS_STATISTICS */ +/*-----------------------------------------------------------------------------------*/ diff --git a/uip/apps/webserver/httpd-fs.h b/uip/apps/webserver/httpd-fs.h new file mode 100644 index 0000000..d80ed3d --- /dev/null +++ b/uip/apps/webserver/httpd-fs.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * $Id: httpd-fs.h,v 1.1 2006/06/07 09:13:08 adam Exp $ + */ +#ifndef __HTTPD_FS_H__ +#define __HTTPD_FS_H__ + +#define HTTPD_FS_STATISTICS 1 + +struct httpd_fs_file { + char *data; + int len; +}; + +/* file must be allocated by caller and will be filled in + by the function. */ +int httpd_fs_open(const char *name, struct httpd_fs_file *file); + +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 +u16_t httpd_fs_count(char *name); +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ + +void httpd_fs_init(void); + +#endif /* __HTTPD_FS_H__ */ diff --git a/uip/apps/webserver/httpd-fs/404.html b/uip/apps/webserver/httpd-fs/404.html new file mode 100644 index 0000000..a17711d --- /dev/null +++ b/uip/apps/webserver/httpd-fs/404.html @@ -0,0 +1,8 @@ + + +
+

404 - file not found

+

Go here instead.

+
+ + \ No newline at end of file diff --git a/uip/apps/webserver/httpd-fs/fade.png b/uip/apps/webserver/httpd-fs/fade.png new file mode 100644 index 0000000..a9e69f7 Binary files /dev/null and b/uip/apps/webserver/httpd-fs/fade.png differ diff --git a/uip/apps/webserver/httpd-fs/files.shtml b/uip/apps/webserver/httpd-fs/files.shtml new file mode 100644 index 0000000..811e230 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/files.shtml @@ -0,0 +1,35 @@ +%!: /header.html +

File statistics

+
+ + + + + + + + + + + + + + + +
/index.html%! file-stats /index.html +
/files.shtml%! file-stats /files.shtml +
/tcp.shtml%! file-stats /tcp.shtml +
/stats.shtml%! file-stats /stats.shtml +
/style.css%! file-stats /style.css +
/404.html%! file-stats /404.html +
/fade.png%! file-stats /fade.png +
+
+%!: /footer.html diff --git a/uip/apps/webserver/httpd-fs/footer.html b/uip/apps/webserver/httpd-fs/footer.html new file mode 100644 index 0000000..1fd5f4f --- /dev/null +++ b/uip/apps/webserver/httpd-fs/footer.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/uip/apps/webserver/httpd-fs/header.html b/uip/apps/webserver/httpd-fs/header.html new file mode 100644 index 0000000..7b1a1fe --- /dev/null +++ b/uip/apps/webserver/httpd-fs/header.html @@ -0,0 +1,18 @@ + + + + Welcome to the uIP web server! + + + + + + +
diff --git a/uip/apps/webserver/httpd-fs/index.html b/uip/apps/webserver/httpd-fs/index.html new file mode 100644 index 0000000..27cbc93 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/index.html @@ -0,0 +1,29 @@ + + + + Welcome to the uIP web server! + + + + + + +
+

+ These web pages are served by a small web server running on top of + the uIP embedded TCP/IP + stack. +

+

+ Click on the links above for web server statistics. +

+ + + diff --git a/uip/apps/webserver/httpd-fs/processes.shtml b/uip/apps/webserver/httpd-fs/processes.shtml new file mode 100644 index 0000000..2f93e35 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/processes.shtml @@ -0,0 +1,5 @@ +%!: /header.html +

System processes


+ +%! processes +%!: /footer.html \ No newline at end of file diff --git a/uip/apps/webserver/httpd-fs/stats.shtml b/uip/apps/webserver/httpd-fs/stats.shtml new file mode 100644 index 0000000..c63ed4a --- /dev/null +++ b/uip/apps/webserver/httpd-fs/stats.shtml @@ -0,0 +1,31 @@ +%!: /header.html +

Network statistics

+
+
IDNamePriorityPoll handlerEvent handlerProcstate
+
+IP           Packets received
+             Packets sent
+	     Packets dropped
+IP errors    IP version/header length
+             IP length, high byte
+             IP length, low byte
+             IP fragments
+             Header checksum
+             Wrong protocol
+ICMP	     Packets received
+             Packets sent
+             Packets dropped
+             Type errors
+TCP          Packets received
+             Packets sent
+             Packets dropped
+             Checksum errors
+             Data packets without ACKs
+             Resets
+             Retransmissions
+	     No connection avaliable
+	     Connection attempts to closed ports
+
%! net-stats
+
+ +%!: /footer.html diff --git a/uip/apps/webserver/httpd-fs/style.css b/uip/apps/webserver/httpd-fs/style.css new file mode 100644 index 0000000..ba6df7f --- /dev/null +++ b/uip/apps/webserver/httpd-fs/style.css @@ -0,0 +1,92 @@ +h1 +{ + text-align: center; + font-size:14pt; + font-family:arial,helvetica; + font-weight:bold; + padding:10px; +} + +body +{ + + background-color: #fffeec; + color:black; + + font-size:8pt; + font-family:arial,helvetica; +} + +.menu +{ + margin: 4px; + width:60%; + + padding:2px; + + border: solid 1px; + background-color: #fffcd2; + text-align:left; + + font-size:9pt; + font-family:arial,helvetica; +} + +div.menubox +{ + width: 25%; + border: 0; + float: left; +text-align: center; +} + +.contentblock +{ + margin: 4px; + width:60%; + + padding:2px; + + border: 1px dotted; + background-color: white; + + font-size:8pt; + font-family:arial,helvetica; + +} + +p.intro +{ + margin-left:20px; + margin-right:20px; + + font-size:10pt; +/* font-weight:bold; */ + font-family:arial,helvetica; +} + +p.clink +{ + font-size:12pt; + font-family:courier,monospace; + text-align:center; +} + +p.clink9 +{ + font-size:9pt; + font-family:courier,monospace; + text-align:center; +} + + +p +{ + padding-left:10px; +} + +p.right +{ + text-align:right; +} + diff --git a/uip/apps/webserver/httpd-fs/tcp.shtml b/uip/apps/webserver/httpd-fs/tcp.shtml new file mode 100644 index 0000000..4c4bffe --- /dev/null +++ b/uip/apps/webserver/httpd-fs/tcp.shtml @@ -0,0 +1,5 @@ +%!: /header.html +

Current connections


+ +%! tcp-connections +%!: /footer.html \ No newline at end of file diff --git a/uip/apps/webserver/httpd-fsdata.c b/uip/apps/webserver/httpd-fsdata.c new file mode 100644 index 0000000..491095e --- /dev/null +++ b/uip/apps/webserver/httpd-fsdata.c @@ -0,0 +1,607 @@ +static const unsigned char data_processes_shtml[] = { + /* /processes.shtml */ + 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x70, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3c, 0x2f, 0x68, + 0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x49, 0x44, 0x3c, 0x2f, 0x74, + 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4e, 0x61, 0x6d, 0x65, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, + 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x3c, 0x2f, 0x74, + 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, 0x6f, 0x6c, 0x6c, + 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, + 0x72, 0x6f, 0x63, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x25, + 0x21, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x73, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, 0x6f, 0x6f, + 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0}; + +static const unsigned char data_404_html[] = { + /* /404.html */ + 0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, + 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3c, 0x68, 0x31, 0x3e, 0x34, 0x30, 0x34, 0x20, 0x2d, + 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, + 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x33, + 0x3e, 0x47, 0x6f, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, + 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x2e, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, + 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, +0}; + +static const unsigned char data_files_shtml[] = { + /* /files.shtml */ + 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x68, 0x31, + 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, + 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x33, 0x30, 0x30, 0x22, 0x3e, + 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, + 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, + 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, + 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x31, + 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, 0x21, + 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, + 0x73, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, + 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, + 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, + 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, + 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, + 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x31, 0x30, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, 0x21, 0x20, + 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, + 0x20, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, + 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, + 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, + 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, + 0x73, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, + 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, + 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, + 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, + 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, + 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, + 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, + 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, + 0x73, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x2f, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, + 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, + 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, + 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0xa, 0x3e, 0x20, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x34, + 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, + 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, + 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 0x30, 0x34, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, + 0x73, 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, + 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 0x30, 0x34, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, + 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x3e, 0x2f, 0x66, 0x61, + 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x3c, 0x2f, 0x61, 0x3e, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, + 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, + 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0xa, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0x3c, 0x2f, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x3a, 0x20, + 0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0xa, 0}; + +static const unsigned char data_footer_html[] = { + /* /footer.html */ + 0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, + 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0}; + +static const unsigned char data_header_html[] = { + /* /header.html */ + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, + 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, + 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x49, 0x50, 0x20, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x72, + 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, + 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, + 0x20, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, + 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, + 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, 0x22, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, + 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, + 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, + 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, + 0x65, 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0xa, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0xa, 0x20, + 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0}; + +static const unsigned char data_index_html[] = { + /* /index.html */ + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, + 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, + 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x49, 0x50, 0x20, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x72, + 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, + 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, + 0x20, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, + 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, + 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, 0x22, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, + 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, + 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, + 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, + 0x65, 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0xa, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x70, + 0x3e, 0xa, 0x20, 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x20, + 0x77, 0x65, 0x62, 0x20, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x6d, 0x61, 0x6c, + 0x6c, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6f, 0x66, + 0xa, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, + 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, + 0x2f, 0x75, 0x69, 0x70, 0x2f, 0x22, 0x3e, 0x75, 0x49, 0x50, + 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, + 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0xa, 0x20, 0x20, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0xa, + 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x70, 0x3e, 0xa, 0x20, 0x20, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0xa, 0x20, 0x20, 0x3c, + 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x62, + 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, 0}; + +static const unsigned char data_style_css[] = { + /* /style.css */ + 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0, + 0x68, 0x31, 0x20, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, + 0x31, 0x34, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, + 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, + 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, + 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0xa, 0x20, 0x20, 0x70, + 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x31, 0x30, 0x70, + 0x78, 0x3b, 0x20, 0xa, 0x7d, 0xa, 0xa, 0x62, 0x6f, 0x64, + 0x79, 0xa, 0x7b, 0xa, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, + 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x65, + 0x65, 0x63, 0x3b, 0xa, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3a, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x3b, 0xa, 0xa, + 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, + 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, + 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, + 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0xa, 0x7d, 0xa, + 0xa, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0xa, 0x7b, 0xa, 0x20, + 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, + 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x36, 0x30, 0x25, 0x3b, 0xa, 0xa, 0x20, 0x20, + 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x32, 0x70, + 0x78, 0x3b, 0xa, 0x9, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, + 0x20, 0x31, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, + 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, + 0x63, 0x64, 0x32, 0x3b, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x6c, 0x65, + 0x66, 0x74, 0x3b, 0xa, 0x20, 0x20, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x39, + 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, + 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, + 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, + 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0xa, 0x7d, 0xa, 0xa, + 0x64, 0x69, 0x76, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x20, 0x32, 0x35, 0x25, 0x3b, 0xa, 0x20, 0x20, + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x30, 0x3b, + 0xa, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, + 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0x74, 0x65, 0x78, 0x74, + 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0xa, 0x7b, 0x20, 0x20, 0xa, 0x20, 0x20, 0x6d, + 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, 0x70, 0x78, + 0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x36, 0x30, 0x25, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x32, 0x70, 0x78, 0x3b, + 0xa, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x3a, 0x20, 0x31, 0x70, 0x78, 0x20, 0x64, 0x6f, 0x74, 0x74, + 0x65, 0x64, 0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, + 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3a, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3b, + 0xa, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, + 0x69, 0x7a, 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 0x20, + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, + 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, + 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, + 0x20, 0xa, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x69, 0x6e, + 0x74, 0x72, 0x6f, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x6c, 0x65, 0x66, 0x74, 0x3a, + 0x32, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x3a, 0x32, 0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, + 0x31, 0x30, 0x70, 0x74, 0x3b, 0xa, 0x2f, 0x2a, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0x20, 0x2a, 0x2f, + 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, + 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, + 0x3b, 0x20, 0x20, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x63, + 0x6c, 0x69, 0x6e, 0x6b, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, + 0x32, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x63, + 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 0x6e, + 0x6f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 0xa, + 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, + 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x63, 0x6c, 0x69, 0x6e, + 0x6b, 0x39, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x39, 0x70, 0x74, + 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, + 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x63, 0x6f, 0x75, 0x72, + 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 0x6e, 0x6f, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 0xa, 0x20, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 0xa, + 0xa, 0xa, 0x70, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 0x66, 0x74, + 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x7d, 0xa, 0xa, + 0x70, 0x2e, 0x72, 0x69, 0x67, 0x68, 0x74, 0xa, 0x7b, 0xa, + 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 0x20, + 0xa, 0x7d, 0xa, 0xa, 0}; + +static const unsigned char data_tcp_shtml[] = { + /* /tcp.shtml */ + 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, + 0x68, 0x3e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, + 0x3e, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x74, 0x68, + 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x54, 0x69, 0x6d, 0x65, 0x72, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x46, + 0x6c, 0x61, 0x67, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, + 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x20, 0x74, 0x63, + 0x70, 0x2d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, + 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, +0}; + +static const unsigned char data_fade_png[] = { + /* /fade.png */ + 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0, + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 00, 00, + 00, 0xd, 0x49, 0x48, 0x44, 0x52, 00, 00, 00, 0x4, + 00, 00, 00, 0xa, 0x8, 0x2, 00, 00, 00, 0x1c, + 0x99, 0x68, 0x59, 00, 00, 00, 0x9, 0x70, 0x48, 0x59, + 0x73, 00, 00, 0xb, 0x13, 00, 00, 0xb, 0x13, 0x1, + 00, 0x9a, 0x9c, 0x18, 00, 00, 00, 0x7, 0x74, 0x49, + 0x4d, 0x45, 0x7, 0xd6, 0x6, 0x8, 0x14, 0x1b, 0x39, 0xaf, + 0x5b, 0xc0, 0xe3, 00, 00, 00, 0x1d, 0x74, 0x45, 0x58, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 00, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4d, 0x50, + 0xef, 0x64, 0x25, 0x6e, 00, 00, 00, 0x3a, 0x49, 0x44, + 0x41, 0x54, 0x8, 0xd7, 0x75, 0x8c, 0x31, 0x12, 00, 0x10, + 0x10, 0xc4, 0x2e, 0x37, 0x9e, 0x40, 0x65, 0xfd, 0xff, 0x83, + 0xf4, 0xa, 0x1c, 0x8d, 0x54, 0x9b, 0xc9, 0xcc, 0x9a, 0x3d, + 0x90, 0x73, 0x71, 0x67, 0x91, 0xd4, 0x74, 0x36, 0xa9, 0x55, + 0x1, 0xf8, 0x29, 0x58, 0xc8, 0xbf, 0x48, 0xc4, 0x81, 0x74, + 0xb, 0xa3, 0xf, 0x7c, 0xdb, 0x4, 0xe8, 0x40, 0x5, 0xdf, + 0xa1, 0xf3, 0xfc, 0x73, 00, 00, 00, 00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0}; + +static const unsigned char data_stats_shtml[] = { + /* /stats.shtml */ + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, + 0x2f, 0x68, 0x31, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x33, 0x30, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0xa, 0x49, + 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, + 0x73, 0x65, 0x6e, 0x74, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0xa, 0x49, 0x50, 0x20, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x20, 0x20, 0x20, 0x20, + 0x49, 0x50, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x50, + 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x2c, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x20, 0x62, 0x79, 0x74, 0x65, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x49, 0x50, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x2c, 0x20, 0x6c, 0x6f, 0x77, 0x20, 0x62, 0x79, 0x74, + 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x50, 0x20, 0x66, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x57, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0xa, 0x49, 0x43, 0x4d, 0x50, 0x9, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x54, 0x79, 0x70, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x73, 0xa, 0x54, 0x43, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x20, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x73, 0xa, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, + 0x61, 0x74, 0x61, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, + 0x41, 0x43, 0x4b, 0x73, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x73, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x4e, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x76, 0x61, 0x6c, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x20, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0xa, 0x3c, 0x2f, 0x70, 0x72, + 0x65, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, + 0x3e, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0x25, 0x21, 0x20, 0x6e, + 0x65, 0x74, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0xa, 0x3c, + 0x2f, 0x70, 0x72, 0x65, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x3e, 0xa, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, + 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0xa, 0}; + +const struct httpd_fsdata_file file_processes_shtml[] = {{NULL, data_processes_shtml, data_processes_shtml + 17, sizeof(data_processes_shtml) - 17}}; + +const struct httpd_fsdata_file file_404_html[] = {{file_processes_shtml, data_404_html, data_404_html + 10, sizeof(data_404_html) - 10}}; + +const struct httpd_fsdata_file file_files_shtml[] = {{file_404_html, data_files_shtml, data_files_shtml + 13, sizeof(data_files_shtml) - 13}}; + +const struct httpd_fsdata_file file_footer_html[] = {{file_files_shtml, data_footer_html, data_footer_html + 13, sizeof(data_footer_html) - 13}}; + +const struct httpd_fsdata_file file_header_html[] = {{file_footer_html, data_header_html, data_header_html + 13, sizeof(data_header_html) - 13}}; + +const struct httpd_fsdata_file file_index_html[] = {{file_header_html, data_index_html, data_index_html + 12, sizeof(data_index_html) - 12}}; + +const struct httpd_fsdata_file file_style_css[] = {{file_index_html, data_style_css, data_style_css + 11, sizeof(data_style_css) - 11}}; + +const struct httpd_fsdata_file file_tcp_shtml[] = {{file_style_css, data_tcp_shtml, data_tcp_shtml + 11, sizeof(data_tcp_shtml) - 11}}; + +const struct httpd_fsdata_file file_fade_png[] = {{file_tcp_shtml, data_fade_png, data_fade_png + 10, sizeof(data_fade_png) - 10}}; + +const struct httpd_fsdata_file file_stats_shtml[] = {{file_fade_png, data_stats_shtml, data_stats_shtml + 13, sizeof(data_stats_shtml) - 13}}; + +#define HTTPD_FS_ROOT file_stats_shtml + +#define HTTPD_FS_NUMFILES 10 diff --git a/uip/apps/webserver/httpd-fsdata.h b/uip/apps/webserver/httpd-fsdata.h new file mode 100644 index 0000000..0ad2d6e --- /dev/null +++ b/uip/apps/webserver/httpd-fsdata.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * $Id: httpd-fsdata.h,v 1.1 2006/06/07 09:13:08 adam Exp $ + */ +#ifndef __HTTPD_FSDATA_H__ +#define __HTTPD_FSDATA_H__ + +#include "uip.h" + +struct httpd_fsdata_file { + const struct httpd_fsdata_file *next; + const char *name; + const char *data; + const int len; +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 + u16_t count; +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ +}; + +struct httpd_fsdata_file_noconst { + struct httpd_fsdata_file *next; + char *name; + char *data; + int len; +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 + u16_t count; +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ +}; + +#endif /* __HTTPD_FSDATA_H__ */ diff --git a/uip/apps/webserver/httpd.c b/uip/apps/webserver/httpd.c new file mode 100644 index 0000000..937e138 --- /dev/null +++ b/uip/apps/webserver/httpd.c @@ -0,0 +1,338 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup httpd Web server + * @{ + * The uIP web server is a very simplistic implementation of an HTTP + * server. It can serve web pages and files from a read-only ROM + * filesystem, and provides a very small scripting language. + + */ + +/** + * \file + * Web server + * \author + * Adam Dunkels + */ + + +/* + * Copyright (c) 2004, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $ + */ + +#include "uip.h" +#include "httpd.h" +#include "httpd-fs.h" +#include "httpd-cgi.h" +#include "http-strings.h" + +#include + +#define STATE_WAITING 0 +#define STATE_OUTPUT 1 + +#define ISO_nl 0x0a +#define ISO_space 0x20 +#define ISO_bang 0x21 +#define ISO_percent 0x25 +#define ISO_period 0x2e +#define ISO_slash 0x2f +#define ISO_colon 0x3a + + +/*---------------------------------------------------------------------------*/ +static unsigned short +generate_part_of_file(void *state) +{ + struct httpd_state *s = (struct httpd_state *)state; + + if(s->file.len > uip_mss()) { + s->len = uip_mss(); + } else { + s->len = s->file.len; + } + memcpy(uip_appdata, s->file.data, s->len); + + return s->len; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_file(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sout); + + do { + PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s); + s->file.len -= s->len; + s->file.data += s->len; + } while(s->file.len > 0); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_part_of_file(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sout); + + PSOCK_SEND(&s->sout, s->file.data, s->len); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static void +next_scriptstate(struct httpd_state *s) +{ + char *p; + p = strchr(s->scriptptr, ISO_nl) + 1; + s->scriptlen -= (unsigned short)(p - s->scriptptr); + s->scriptptr = p; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_script(struct httpd_state *s)) +{ + char *ptr; + + PT_BEGIN(&s->scriptpt); + + + while(s->file.len > 0) { + + /* Check if we should start executing a script. */ + if(*s->file.data == ISO_percent && + *(s->file.data + 1) == ISO_bang) { + s->scriptptr = s->file.data + 3; + s->scriptlen = s->file.len - 3; + if(*(s->scriptptr - 1) == ISO_colon) { + httpd_fs_open(s->scriptptr + 1, &s->file); + PT_WAIT_THREAD(&s->scriptpt, send_file(s)); + } else { + PT_WAIT_THREAD(&s->scriptpt, + httpd_cgi(s->scriptptr)(s, s->scriptptr)); + } + next_scriptstate(s); + + /* The script is over, so we reset the pointers and continue + sending the rest of the file. */ + s->file.data = s->scriptptr; + s->file.len = s->scriptlen; + } else { + /* See if we find the start of script marker in the block of HTML + to be sent. */ + + if(s->file.len > uip_mss()) { + s->len = uip_mss(); + } else { + s->len = s->file.len; + } + + if(*s->file.data == ISO_percent) { + ptr = strchr(s->file.data + 1, ISO_percent); + } else { + ptr = strchr(s->file.data, ISO_percent); + } + if(ptr != NULL && + ptr != s->file.data) { + s->len = (int)(ptr - s->file.data); + if(s->len >= uip_mss()) { + s->len = uip_mss(); + } + } + PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); + s->file.data += s->len; + s->file.len -= s->len; + + } + } + + PT_END(&s->scriptpt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr)) +{ + char *ptr; + + PSOCK_BEGIN(&s->sout); + + PSOCK_SEND_STR(&s->sout, statushdr); + + ptr = strrchr(s->filename, ISO_period); + if(ptr == NULL) { + PSOCK_SEND_STR(&s->sout, http_content_type_binary); + } else if(strncmp(http_html, ptr, 5) == 0 || + strncmp(http_shtml, ptr, 6) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_html); + } else if(strncmp(http_css, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_css); + } else if(strncmp(http_png, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_png); + } else if(strncmp(http_gif, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_gif); + } else if(strncmp(http_jpg, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_jpg); + } else { + PSOCK_SEND_STR(&s->sout, http_content_type_plain); + } + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_output(struct httpd_state *s)) +{ + char *ptr; + + PT_BEGIN(&s->outputpt); + + if(!httpd_fs_open(s->filename, &s->file)) { + httpd_fs_open(http_404_html, &s->file); + strcpy(s->filename, http_404_html); + PT_WAIT_THREAD(&s->outputpt, + send_headers(s, + http_header_404)); + PT_WAIT_THREAD(&s->outputpt, + send_file(s)); + } else { + PT_WAIT_THREAD(&s->outputpt, + send_headers(s, + http_header_200)); + ptr = strchr(s->filename, ISO_period); + if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) { + PT_INIT(&s->scriptpt); + PT_WAIT_THREAD(&s->outputpt, handle_script(s)); + } else { + PT_WAIT_THREAD(&s->outputpt, + send_file(s)); + } + } + PSOCK_CLOSE(&s->sout); + PT_END(&s->outputpt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_input(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sin); + + PSOCK_READTO(&s->sin, ISO_space); + + + if(strncmp(s->inputbuf, http_get, 4) != 0) { + PSOCK_CLOSE_EXIT(&s->sin); + } + PSOCK_READTO(&s->sin, ISO_space); + + if(s->inputbuf[0] != ISO_slash) { + PSOCK_CLOSE_EXIT(&s->sin); + } + + if(s->inputbuf[1] == ISO_space) { + strncpy(s->filename, http_index_html, sizeof(s->filename)); + } else { + s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; + strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); + } + + /* httpd_log_file(uip_conn->ripaddr, s->filename);*/ + + s->state = STATE_OUTPUT; + + while(1) { + PSOCK_READTO(&s->sin, ISO_nl); + + if(strncmp(s->inputbuf, http_referer, 8) == 0) { + s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0; + /* httpd_log(&s->inputbuf[9]);*/ + } + } + + PSOCK_END(&s->sin); +} +/*---------------------------------------------------------------------------*/ +static void +handle_connection(struct httpd_state *s) +{ + handle_input(s); + if(s->state == STATE_OUTPUT) { + handle_output(s); + } +} +/*---------------------------------------------------------------------------*/ +void +httpd_appcall(void) +{ + struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate); + + if(uip_closed() || uip_aborted() || uip_timedout()) { + } else if(uip_connected()) { + PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1); + PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1); + PT_INIT(&s->outputpt); + s->state = STATE_WAITING; + /* timer_set(&s->timer, CLOCK_SECOND * 100);*/ + s->timer = 0; + handle_connection(s); + } else if(s != NULL) { + if(uip_poll()) { + ++s->timer; + if(s->timer >= 20) { + uip_abort(); + } + } else { + s->timer = 0; + } + handle_connection(s); + } else { + uip_abort(); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize the web server + * + * This function initializes the web server and should be + * called at system boot-up. + */ +void +httpd_init(void) +{ + uip_listen(HTONS(80)); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/uip/apps/webserver/httpd.h b/uip/apps/webserver/httpd.h new file mode 100644 index 0000000..270d49d --- /dev/null +++ b/uip/apps/webserver/httpd.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001-2005, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: httpd.h,v 1.2 2006/06/11 21:46:38 adam Exp $ + * + */ + +#ifndef __HTTPD_H__ +#define __HTTPD_H__ + +#include "psock.h" +#include "httpd-fs.h" + +struct httpd_state { + unsigned char timer; + struct psock sin, sout; + struct pt outputpt, scriptpt; + char inputbuf[50]; + char filename[20]; + char state; + struct httpd_fs_file file; + int len; + char *scriptptr; + int scriptlen; + + unsigned short count; +}; + +void httpd_init(void); +void httpd_appcall(void); + +void httpd_log(char *msg); +void httpd_log_file(u16_t *requester, char *file); + +#endif /* __HTTPD_H__ */ diff --git a/uip/apps/webserver/makefsdata b/uip/apps/webserver/makefsdata new file mode 100755 index 0000000..b2109ab --- /dev/null +++ b/uip/apps/webserver/makefsdata @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +open(OUTPUT, "> httpd-fsdata.c"); + +chdir("httpd-fs"); + +opendir(DIR, "."); +@files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); +closedir(DIR); + +foreach $file (@files) { + + if(-d $file && $file !~ /^\./) { + print "Processing directory $file\n"; + opendir(DIR, $file); + @newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); + closedir(DIR); + printf "Adding files @newfiles\n"; + @files = (@files, map { $_ = "$file/$_" } @newfiles); + next; + } +} + +foreach $file (@files) { + if(-f $file) { + + print "Adding file $file\n"; + + open(FILE, $file) || die "Could not open file $file\n"; + + $file =~ s-^-/-; + $fvar = $file; + $fvar =~ s-/-_-g; + $fvar =~ s-\.-_-g; + # for AVR, add PROGMEM here + print(OUTPUT "static const unsigned char data".$fvar."[] = {\n"); + print(OUTPUT "\t/* $file */\n\t"); + for($j = 0; $j < length($file); $j++) { + printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); + } + printf(OUTPUT "0,\n"); + + + $i = 0; + while(read(FILE, $data, 1)) { + if($i == 0) { + print(OUTPUT "\t"); + } + printf(OUTPUT "%#02x, ", unpack("C", $data)); + $i++; + if($i == 10) { + print(OUTPUT "\n"); + $i = 0; + } + } + print(OUTPUT "0};\n\n"); + close(FILE); + push(@fvars, $fvar); + push(@pfiles, $file); + } +} + +for($i = 0; $i < @fvars; $i++) { + $file = $pfiles[$i]; + $fvar = $fvars[$i]; + + if($i == 0) { + $prevfile = "NULL"; + } else { + $prevfile = "file" . $fvars[$i - 1]; + } + print(OUTPUT "const struct httpd_fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); + print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); + print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); +} + +print(OUTPUT "#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n"); +print(OUTPUT "#define HTTPD_FS_NUMFILES $i\n"); diff --git a/uip/apps/webserver/makestrings b/uip/apps/webserver/makestrings new file mode 100755 index 0000000..20f0e24 --- /dev/null +++ b/uip/apps/webserver/makestrings @@ -0,0 +1,40 @@ +#!/usr/bin/perl + + +sub stringify { + my $name = shift(@_); + open(OUTPUTC, "> $name.c"); + open(OUTPUTH, "> $name.h"); + + open(FILE, "$name"); + + while() { + if(/(.+) "(.+)"/) { + $var = $1; + $data = $2; + + $datan = $data; + $datan =~ s/\\r/\r/g; + $datan =~ s/\\n/\n/g; + $datan =~ s/\\01/\01/g; + $datan =~ s/\\0/\0/g; + + printf(OUTPUTC "const char $var\[%d] = \n", length($datan) + 1); + printf(OUTPUTC "/* \"$data\" */\n"); + printf(OUTPUTC "{"); + for($j = 0; $j < length($datan); $j++) { + printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1))); + } + printf(OUTPUTC "};\n"); + + printf(OUTPUTH "extern const char $var\[%d];\n", length($datan) + 1); + + } + } + close(OUTPUTC); + close(OUTPUTH); +} +stringify("http-strings"); + +exit 0; + diff --git a/uip/apps/webserver/webserver.h b/uip/apps/webserver/webserver.h new file mode 100644 index 0000000..48753e6 --- /dev/null +++ b/uip/apps/webserver/webserver.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: webserver.h,v 1.2 2006/06/11 21:46:38 adam Exp $ + * + */ +#ifndef __WEBSERVER_H__ +#define __WEBSERVER_H__ + +#include "httpd.h" + +typedef struct httpd_state uip_tcp_appstate_t; +/* UIP_APPCALL: the name of the application function. This function + must return void and take no arguments (i.e., C type "void + appfunc(void)"). */ +#ifndef UIP_APPCALL +#define UIP_APPCALL httpd_appcall +#endif + + +#endif /* __WEBSERVER_H__ */ diff --git a/uip/lib/memb.c b/uip/lib/memb.c new file mode 100644 index 0000000..777b52f --- /dev/null +++ b/uip/lib/memb.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: memb.c,v 1.1 2006/06/12 08:21:43 adam Exp $ + */ + +/** + * \addtogroup memb + * @{ + */ + + /** + * \file + * Memory block allocation routines. + * \author Adam Dunkels + */ +#include + +#include "memb.h" + +/*---------------------------------------------------------------------------*/ +void +memb_init(struct memb_blocks *m) +{ + memset(m->count, 0, m->num); + memset(m->mem, 0, m->size * m->num); +} +/*---------------------------------------------------------------------------*/ +void * +memb_alloc(struct memb_blocks *m) +{ + int i; + + for(i = 0; i < m->num; ++i) { + if(m->count[i] == 0) { + /* If this block was unused, we increase the reference count to + indicate that it now is used and return a pointer to the + memory block. */ + ++(m->count[i]); + return (void *)((char *)m->mem + (i * m->size)); + } + } + + /* No free block was found, so we return NULL to indicate failure to + allocate block. */ + return NULL; +} +/*---------------------------------------------------------------------------*/ +char +memb_free(struct memb_blocks *m, void *ptr) +{ + int i; + char *ptr2; + + /* Walk through the list of blocks and try to find the block to + which the pointer "ptr" points to. */ + ptr2 = (char *)m->mem; + for(i = 0; i < m->num; ++i) { + + if(ptr2 == (char *)ptr) { + /* We've found to block to which "ptr" points so we decrease the + reference count and return the new value of it. */ + if(m->count[i] > 0) { + /* Make sure that we don't deallocate free memory. */ + --(m->count[i]); + } + return m->count[i]; + } + ptr2 += m->size; + } + return -1; +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/uip/lib/memb.h b/uip/lib/memb.h new file mode 100644 index 0000000..b725ebe --- /dev/null +++ b/uip/lib/memb.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: memb.h,v 1.1 2006/06/12 08:21:43 adam Exp $ + */ + +/** + * \defgroup memb Memory block management functions + * + * The memory block allocation routines provide a simple yet powerful + * set of functions for managing a set of memory blocks of fixed + * size. A set of memory blocks is statically declared with the + * MEMB() macro. Memory blocks are allocated from the declared + * memory by the memb_alloc() function, and are deallocated with the + * memb_free() function. + * + * \note Because of namespace clashes only one MEMB() can be + * declared per C module, and the name scope of a MEMB() memory + * block is local to each C module. + * + * The following example shows how to declare and use a memory block + * called "cmem" which has 8 chunks of memory with each memory chunk + * being 20 bytes large. + * + * @{ + */ + + +/** + * \file + * Memory block allocation routines. + * \author + * Adam Dunkels + * + */ + +#ifndef __MEMB_H__ +#define __MEMB_H__ + +/* + * Here we define a C preprocessing macro for concatenating to + * strings. We need use two macros in order to allow concatenation of + * two #defined macros. + */ +#define MEMB_CONCAT2(s1, s2) s1##s2 +#define MEMB_CONCAT(s1, s2) MEMB_CONCAT2(s1, s2) + +/** + * Declare a memory block. + * + * This macro is used to staticall declare a block of memory that can + * be used by the block allocation functions. The macro statically + * declares a C array with a size that matches the specified number of + * blocks and their individual sizes. + * + * Example: + \code +MEMB(connections, sizeof(struct connection), 16); + \endcode + * + * \param name The name of the memory block (later used with + * memb_init(), memb_alloc() and memb_free()). + * + * \param size The size of each memory chunk, in bytes. + * + * \param num The total number of memory chunks in the block. + * + */ +#define MEMB(name, structure, num) \ + static char MEMB_CONCAT(name,_memb_count)[num]; \ + static structure MEMB_CONCAT(name,_memb_mem)[num]; \ + static struct memb_blocks name = {sizeof(structure), num, \ + MEMB_CONCAT(name,_memb_count), \ + (void *)MEMB_CONCAT(name,_memb_mem)} + +struct memb_blocks { + unsigned short size; + unsigned short num; + char *count; + void *mem; +}; + +/** + * Initialize a memory block that was declared with MEMB(). + * + * \param m A memory block previosly declared with MEMB(). + */ +void memb_init(struct memb_blocks *m); + +/** + * Allocate a memory block from a block of memory declared with MEMB(). + * + * \param m A memory block previosly declared with MEMB(). + */ +void *memb_alloc(struct memb_blocks *m); + +/** + * Deallocate a memory block from a memory block previously declared + * with MEMB(). + * + * \param m m A memory block previosly declared with MEMB(). + * + * \param ptr A pointer to the memory block that is to be deallocated. + * + * \return The new reference count for the memory block (should be 0 + * if successfully deallocated) or -1 if the pointer "ptr" did not + * point to a legal memory block. + */ +char memb_free(struct memb_blocks *m, void *ptr); + +/** @} */ + +#endif /* __MEMB_H__ */ diff --git a/uip/uip-1.0-changelog.txt b/uip/uip-1.0-changelog.txt new file mode 100644 index 0000000..1e6c61c --- /dev/null +++ b/uip/uip-1.0-changelog.txt @@ -0,0 +1,98 @@ +* A new API: protosockets that are similar to BSD sockets but does not + require any underlying multithreading system. + +* Very rudimentary IPv6 support + +* New application: DHCP client. Web server rewritten with protosockets. + +* Removed uIP zero-copy functionality in order to simplify uIP device + driver coding: outbound packets are now *always* stored in full in + the uip_buf buffer. + +* Checksum computation is now part of uip.c, but it still is possible + to implement them in assembly code by specifying a configuration + option. Checksum code now runs on architectures with 2-byte alignment. + +* Added TCP persistent timer. + +* Made all IP address representations use the new uip_ipaddr_ip + datatype for clarity. + +* Updated window behavior so that sending to a host with a small open + window works better now. + +* UDP API change: uip_udp_new() now takes port numbers in network byte + order like TCP functions. + +* Allow reception of packets when no IP address is configured to make + DHCP work. + +* Moved Ethernet address into main uIP module from ARP module. + +* Made constants explicit #defines and moved them out of the code + (header sizes, TCP options, TCP header length field). + +* If uip_len is less than that reported by the IP header, the packet + is discarded. If uip_len is greater than the length reported by the + IP header, uip_len is adjusted. + +* Moved header size definitions into header file. + +* Added uIP call for polling an application without triggering any + timer events. Removed redundant assignments of uip_len and uip_slen. + +* Removed compiler warning about icmp_input label being defined when + UIP_PINGADDRCONF was not used. + +* Added UIP_APPDATA_SIZE macro that holds the available buffer size + for user data. + +* Added uip_udp_bind() call. + +* Moved checksum code into main uIP module. + +* Switched the TCP, UDP and IP header structures to be structs rather + than typedefs. + +* Prefixed TCP state names with UIP_ to avoid name space + contamination. + +* Changed declarations of uip_appdatap and friends to void * to avoid + explicit typecasts. + +* Bugfixes + + o TCP: Fixed bug with high byte of peer window size. + + o TCP: Fixed bug that in some cases prevented concurrent reception and + transmission of TCP data. + + o TCP: uip_connect() didn't correctly calculate age of TIME_WAIT + connections. + + o TCP: Array index for uip_conns[] array was out of bounds in + comparison. Comparison changed to make index within bounds. + + o TCP: if the remote host crashes and tries to reestablish an old + connection, uIP should respond with an ACK with the correct + sequence and acknowledgment numbers, to which the remote host + should respond with an ACK. uIP did not respond with the correct + ACK. + + o TCP: Fixed check for SYNACK segment: now checks only relevant TCP + control flags and discards flags reserved for future expansion. + + o TCP: Fixed bug where uIP did not inform application that a connection + had been aborted during an active open. + + o TCP: FIN segment was accepted even though application had stopped + incoming data with uip_stop(). + + o TCP: A FINACK segment would not always correctly acknowledge data. + + o UDP: checksums are now calculated after all fields have been + filled in. + + o UDP: network byte order on lastport in uip_udp_new(). + + o IP: memset() bugs in IP fragment reassembly code fixed. diff --git a/uip/uip/Makefile.include b/uip/uip/Makefile.include new file mode 100644 index 0000000..3426dd1 --- /dev/null +++ b/uip/uip/Makefile.include @@ -0,0 +1,47 @@ + + +ifdef APPS + APPDIRS = $(foreach APP, $(APPS), ../apps/$(APP)) + -include $(foreach APP, $(APPS), ../apps/$(APP)/Makefile.$(APP)) + CFLAGS += $(addprefix -I../apps/,$(APPS)) +endif + +ifndef CCDEP + CCDEP = $(CC) +endif +ifndef CCDEPCFLAGS + CCDEPCFLAGS = $(CFLAGS) +endif +ifndef OBJECTDIR + OBJECTDIR = obj +endif + +ifeq (${wildcard $(OBJECTDIR)},) + DUMMY := ${shell mkdir $(OBJECTDIR)} +endif + + +vpath %.c . ../uip ../lib $(APPDIRS) + +$(OBJECTDIR)/%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJECTDIR)/%.d: %.c + @set -e; rm -f $@; \ + $(CCDEP) -MM $(CCDEPCFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,$(OBJECTDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +UIP_SOURCES=uip.c uip_arp.c uiplib.c psock.c timer.c uip-neighbor.c + + +ifneq ($(MAKECMDGOALS),clean) +-include $(addprefix $(OBJECTDIR)/,$(UIP_SOURCES:.c=.d) \ + $(APP_SOURCES:.c=.d)) +endif + +uip.a: ${addprefix $(OBJECTDIR)/, $(UIP_SOURCES:.c=.o)} + $(AR) a $@ $^ + +apps.a: ${addprefix $(OBJECTDIR)/, $(APP_SOURCES:.c=.o)} + $(AR) a $@ $^ diff --git a/uip/uip/clock.h b/uip/uip/clock.h new file mode 100644 index 0000000..f34d78f --- /dev/null +++ b/uip/uip/clock.h @@ -0,0 +1,88 @@ +/** + * \defgroup clock Clock interface + * + * The clock interface is the interface between the \ref timer "timer library" + * and the platform specific clock functionality. The clock + * interface must be implemented for each platform that uses the \ref + * timer "timer library". + * + * The clock interface does only one this: it measures time. The clock + * interface provides a macro, CLOCK_SECOND, which corresponds to one + * second of system time. + * + * \sa \ref timer "Timer library" + * + * @{ + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: clock.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __CLOCK_H__ +#define __CLOCK_H__ + +#include "clock-arch.h" + +/** + * Initialize the clock library. + * + * This function initializes the clock library and should be called + * from the main() function of the system. + * + */ +void clock_init(void); + +/** + * Get the current clock time. + * + * This function returns the current system clock time. + * + * \return The current clock time, measured in system ticks. + */ +clock_time_t clock_time(void); + +/** + * A second, measured in system clock time. + * + * \hideinitializer + */ +#ifdef CLOCK_CONF_SECOND +#define CLOCK_SECOND CLOCK_CONF_SECOND +#else +#define CLOCK_SECOND (clock_time_t)32 +#endif + +#endif /* __CLOCK_H__ */ + +/** @} */ diff --git a/uip/uip/lc-addrlabels.h b/uip/uip/lc-addrlabels.h new file mode 100644 index 0000000..fe1387e --- /dev/null +++ b/uip/uip/lc-addrlabels.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: lc-addrlabels.h,v 1.3 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \addtogroup lc + * @{ + */ + +/** + * \file + * Implementation of local continuations based on the "Labels as + * values" feature of gcc + * \author + * Adam Dunkels + * + * This implementation of local continuations is based on a special + * feature of the GCC C compiler called "labels as values". This + * feature allows assigning pointers with the address of the code + * corresponding to a particular C label. + * + * For more information, see the GCC documentation: + * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + * + * Thanks to dividuum for finding the nice local scope label + * implementation. + */ + +#ifndef __LC_ADDRLABELS_H__ +#define __LC_ADDRLABELS_H__ + +/** \hideinitializer */ +typedef void * lc_t; + +#define LC_INIT(s) s = NULL + + +#define LC_RESUME(s) \ + do { \ + if(s != NULL) { \ + goto *s; \ + } \ + } while(0) + +#define LC_SET(s) \ + do { ({ __label__ resume; resume: (s) = &&resume; }); }while(0) + +#define LC_END(s) + +#endif /* __LC_ADDRLABELS_H__ */ + +/** @} */ diff --git a/uip/uip/lc-switch.h b/uip/uip/lc-switch.h new file mode 100644 index 0000000..f32885f --- /dev/null +++ b/uip/uip/lc-switch.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: lc-switch.h,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \addtogroup lc + * @{ + */ + +/** + * \file + * Implementation of local continuations based on switch() statment + * \author Adam Dunkels + * + * This implementation of local continuations uses the C switch() + * statement to resume execution of a function somewhere inside the + * function's body. The implementation is based on the fact that + * switch() statements are able to jump directly into the bodies of + * control structures such as if() or while() statmenets. + * + * This implementation borrows heavily from Simon Tatham's coroutines + * implementation in C: + * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + */ + +#ifndef __LC_SWITCH_H__ +#define __LC_SWTICH_H__ + +/* WARNING! lc implementation using switch() does not work if an + LC_SET() is done within another switch() statement! */ + +/** \hideinitializer */ +typedef unsigned short lc_t; + +#define LC_INIT(s) s = 0; + +#define LC_RESUME(s) switch(s) { case 0: + +#define LC_SET(s) s = __LINE__; case __LINE__: + +#define LC_END(s) } + +#endif /* __LC_SWITCH_H__ */ + +/** @} */ diff --git a/uip/uip/lc.h b/uip/uip/lc.h new file mode 100644 index 0000000..a9e9d46 --- /dev/null +++ b/uip/uip/lc.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: lc.h,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \defgroup lc Local continuations + * @{ + * + * Local continuations form the basis for implementing protothreads. A + * local continuation can be set in a specific function to + * capture the state of the function. After a local continuation has + * been set can be resumed in order to restore the state of the + * function at the point where the local continuation was set. + * + * + */ + +/** + * \file lc.h + * Local continuations + * \author + * Adam Dunkels + * + */ + +#ifdef DOXYGEN +/** + * Initialize a local continuation. + * + * This operation initializes the local continuation, thereby + * unsetting any previously set continuation state. + * + * \hideinitializer + */ +#define LC_INIT(lc) + +/** + * Set a local continuation. + * + * The set operation saves the state of the function at the point + * where the operation is executed. As far as the set operation is + * concerned, the state of the function does not include the + * call-stack or local (automatic) variables, but only the program + * counter and such CPU registers that needs to be saved. + * + * \hideinitializer + */ +#define LC_SET(lc) + +/** + * Resume a local continuation. + * + * The resume operation resumes a previously set local continuation, thus + * restoring the state in which the function was when the local + * continuation was set. If the local continuation has not been + * previously set, the resume operation does nothing. + * + * \hideinitializer + */ +#define LC_RESUME(lc) + +/** + * Mark the end of local continuation usage. + * + * The end operation signifies that local continuations should not be + * used any more in the function. This operation is not needed for + * most implementations of local continuation, but is required by a + * few implementations. + * + * \hideinitializer + */ +#define LC_END(lc) + +/** + * \var typedef lc_t; + * + * The local continuation type. + * + * \hideinitializer + */ +#endif /* DOXYGEN */ + +#ifndef __LC_H__ +#define __LC_H__ + +#ifdef LC_CONF_INCLUDE +#include LC_CONF_INCLUDE +#else +#include "lc-switch.h" +#endif /* LC_CONF_INCLUDE */ + +#endif /* __LC_H__ */ + +/** @} */ +/** @} */ diff --git a/uip/uip/psock.c b/uip/uip/psock.c new file mode 100644 index 0000000..f284cb9 --- /dev/null +++ b/uip/uip/psock.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: psock.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +#include +#include + +#include "uipopt.h" +#include "psock.h" +#include "uip.h" + +#define STATE_NONE 0 +#define STATE_ACKED 1 +#define STATE_READ 2 +#define STATE_BLOCKED_NEWDATA 3 +#define STATE_BLOCKED_CLOSE 4 +#define STATE_BLOCKED_SEND 5 +#define STATE_DATA_SENT 6 + +/* + * Return value of the buffering functions that indicates that a + * buffer was not filled by incoming data. + * + */ +#define BUF_NOT_FULL 0 +#define BUF_NOT_FOUND 0 + +/* + * Return value of the buffering functions that indicates that a + * buffer was completely filled by incoming data. + * + */ +#define BUF_FULL 1 + +/* + * Return value of the buffering functions that indicates that an + * end-marker byte was found. + * + */ +#define BUF_FOUND 2 + +/*---------------------------------------------------------------------------*/ +static void +buf_setup(struct psock_buf *buf, + u8_t *bufptr, u16_t bufsize) +{ + buf->ptr = bufptr; + buf->left = bufsize; +} +/*---------------------------------------------------------------------------*/ +static u8_t +buf_bufdata(struct psock_buf *buf, u16_t len, + u8_t **dataptr, u16_t *datalen) +{ + if(*datalen < buf->left) { + memcpy(buf->ptr, *dataptr, *datalen); + buf->ptr += *datalen; + buf->left -= *datalen; + *dataptr += *datalen; + *datalen = 0; + return BUF_NOT_FULL; + } else if(*datalen == buf->left) { + memcpy(buf->ptr, *dataptr, *datalen); + buf->ptr += *datalen; + buf->left = 0; + *dataptr += *datalen; + *datalen = 0; + return BUF_FULL; + } else { + memcpy(buf->ptr, *dataptr, buf->left); + buf->ptr += buf->left; + *datalen -= buf->left; + *dataptr += buf->left; + buf->left = 0; + return BUF_FULL; + } +} +/*---------------------------------------------------------------------------*/ +static u8_t +buf_bufto(register struct psock_buf *buf, u8_t endmarker, + register u8_t **dataptr, register u16_t *datalen) +{ + u8_t c; + while(buf->left > 0 && *datalen > 0) { + c = *buf->ptr = **dataptr; + ++*dataptr; + ++buf->ptr; + --*datalen; + --buf->left; + + if(c == endmarker) { + return BUF_FOUND; + } + } + + if(*datalen == 0) { + return BUF_NOT_FOUND; + } + + while(*datalen > 0) { + c = **dataptr; + --*datalen; + ++*dataptr; + + if(c == endmarker) { + return BUF_FOUND | BUF_FULL; + } + } + + return BUF_FULL; +} +/*---------------------------------------------------------------------------*/ +static char +send_data(register struct psock *s) +{ + if(s->state != STATE_DATA_SENT || uip_rexmit()) { + if(s->sendlen > uip_mss()) { + uip_send(s->sendptr, uip_mss()); + } else { + uip_send(s->sendptr, s->sendlen); + } + s->state = STATE_DATA_SENT; + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static char +data_acked(register struct psock *s) +{ + if(s->state == STATE_DATA_SENT && uip_acked()) { + if(s->sendlen > uip_mss()) { + s->sendlen -= uip_mss(); + s->sendptr += uip_mss(); + } else { + s->sendptr += s->sendlen; + s->sendlen = 0; + } + s->state = STATE_ACKED; + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +PT_THREAD(psock_send(register struct psock *s, const char *buf, + unsigned int len)) +{ + PT_BEGIN(&s->psockpt); + + /* If there is no data to send, we exit immediately. */ + if(len == 0) { + PT_EXIT(&s->psockpt); + } + + /* Save the length of and a pointer to the data that is to be + sent. */ + s->sendptr = buf; + s->sendlen = len; + + s->state = STATE_NONE; + + /* We loop here until all data is sent. The s->sendlen variable is + updated by the data_sent() function. */ + while(s->sendlen > 0) { + + /* + * The condition for this PT_WAIT_UNTIL is a little tricky: the + * protothread will wait here until all data has been acknowledged + * (data_acked() returns true) and until all data has been sent + * (send_data() returns true). The two functions data_acked() and + * send_data() must be called in succession to ensure that all + * data is sent. Therefore the & operator is used instead of the + * && operator, which would cause only the data_acked() function + * to be called when it returns false. + */ + PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s)); + } + + s->state = STATE_NONE; + + PT_END(&s->psockpt); +} +/*---------------------------------------------------------------------------*/ +PT_THREAD(psock_generator_send(register struct psock *s, + unsigned short (*generate)(void *), void *arg)) +{ + PT_BEGIN(&s->psockpt); + + /* Ensure that there is a generator function to call. */ + if(generate == NULL) { + PT_EXIT(&s->psockpt); + } + + /* Call the generator function to generate the data in the + uip_appdata buffer. */ + s->sendlen = generate(arg); + s->sendptr = uip_appdata; + + s->state = STATE_NONE; + do { + /* Call the generator function again if we are called to perform a + retransmission. */ + if(uip_rexmit()) { + generate(arg); + } + /* Wait until all data is sent and acknowledged. */ + PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s)); + } while(s->sendlen > 0); + + s->state = STATE_NONE; + + PT_END(&s->psockpt); +} +/*---------------------------------------------------------------------------*/ +u16_t +psock_datalen(struct psock *psock) +{ + return psock->bufsize - psock->buf.left; +} +/*---------------------------------------------------------------------------*/ +char +psock_newdata(struct psock *s) +{ + if(s->readlen > 0) { + /* There is data in the uip_appdata buffer that has not yet been + read with the PSOCK_READ functions. */ + return 1; + } else if(s->state == STATE_READ) { + /* All data in uip_appdata buffer already consumed. */ + s->state = STATE_BLOCKED_NEWDATA; + return 0; + } else if(uip_newdata()) { + /* There is new data that has not been consumed. */ + return 1; + } else { + /* There is no new data. */ + return 0; + } +} +/*---------------------------------------------------------------------------*/ +PT_THREAD(psock_readto(register struct psock *psock, unsigned char c)) +{ + PT_BEGIN(&psock->psockpt); + + buf_setup(&psock->buf, psock->bufptr, psock->bufsize); + + /* XXX: Should add buf_checkmarker() before do{} loop, if + incoming data has been handled while waiting for a write. */ + + do { + if(psock->readlen == 0) { + PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock)); + psock->state = STATE_READ; + psock->readptr = (u8_t *)uip_appdata; + psock->readlen = uip_datalen(); + } + } while((buf_bufto(&psock->buf, c, + &psock->readptr, + &psock->readlen) & BUF_FOUND) == 0); + + if(psock_datalen(psock) == 0) { + psock->state = STATE_NONE; + PT_RESTART(&psock->psockpt); + } + PT_END(&psock->psockpt); +} +/*---------------------------------------------------------------------------*/ +PT_THREAD(psock_readbuf(register struct psock *psock)) +{ + PT_BEGIN(&psock->psockpt); + + buf_setup(&psock->buf, psock->bufptr, psock->bufsize); + + /* XXX: Should add buf_checkmarker() before do{} loop, if + incoming data has been handled while waiting for a write. */ + + do { + if(psock->readlen == 0) { + PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock)); + printf("Waited for newdata\n"); + psock->state = STATE_READ; + psock->readptr = (u8_t *)uip_appdata; + psock->readlen = uip_datalen(); + } + } while(buf_bufdata(&psock->buf, psock->bufsize, + &psock->readptr, + &psock->readlen) != BUF_FULL); + + if(psock_datalen(psock) == 0) { + psock->state = STATE_NONE; + PT_RESTART(&psock->psockpt); + } + PT_END(&psock->psockpt); +} +/*---------------------------------------------------------------------------*/ +void +psock_init(register struct psock *psock, char *buffer, unsigned int buffersize) +{ + psock->state = STATE_NONE; + psock->readlen = 0; + psock->bufptr = buffer; + psock->bufsize = buffersize; + buf_setup(&psock->buf, buffer, buffersize); + PT_INIT(&psock->pt); + PT_INIT(&psock->psockpt); +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/uip/psock.h b/uip/uip/psock.h new file mode 100644 index 0000000..3dffa73 --- /dev/null +++ b/uip/uip/psock.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: psock.h,v 1.3 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \defgroup psock Protosockets library + * @{ + * + * The protosocket library provides an interface to the uIP stack that is + * similar to the traditional BSD socket interface. Unlike programs + * written for the ordinary uIP event-driven interface, programs + * written with the protosocket library are executed in a sequential + * fashion and does not have to be implemented as explicit state + * machines. + * + * Protosockets only work with TCP connections. + * + * The protosocket library uses \ref pt protothreads to provide + * sequential control flow. This makes the protosockets lightweight in + * terms of memory, but also means that protosockets inherits the + * functional limitations of protothreads. Each protosocket lives only + * within a single function. Automatic variables (stack variables) are + * not retained across a protosocket library function call. + * + * \note Because the protosocket library uses protothreads, local + * variables will not always be saved across a call to a protosocket + * library function. It is therefore advised that local variables are + * used with extreme care. + * + * The protosocket library provides functions for sending data without + * having to deal with retransmissions and acknowledgements, as well + * as functions for reading data without having to deal with data + * being split across more than one TCP segment. + * + * Because each protosocket runs as a protothread, the protosocket has to be + * started with a call to PSOCK_BEGIN() at the start of the function + * in which the protosocket is used. Similarly, the protosocket protothread can + * be terminated by a call to PSOCK_EXIT(). + * + */ + +/** + * \file + * Protosocket library header file + * \author + * Adam Dunkels + * + */ + +#ifndef __PSOCK_H__ +#define __PSOCK_H__ + +#include "uipopt.h" +#include "pt.h" + + /* + * The structure that holds the state of a buffer. + * + * This structure holds the state of a uIP buffer. The structure has + * no user-visible elements, but is used through the functions + * provided by the library. + * + */ +struct psock_buf { + u8_t *ptr; + unsigned short left; +}; + +/** + * The representation of a protosocket. + * + * The protosocket structrure is an opaque structure with no user-visible + * elements. + */ +struct psock { + struct pt pt, psockpt; /* Protothreads - one that's using the psock + functions, and one that runs inside the + psock functions. */ + const u8_t *sendptr; /* Pointer to the next data to be sent. */ + u8_t *readptr; /* Pointer to the next data to be read. */ + + char *bufptr; /* Pointer to the buffer used for buffering + incoming data. */ + + u16_t sendlen; /* The number of bytes left to be sent. */ + u16_t readlen; /* The number of bytes left to be read. */ + + struct psock_buf buf; /* The structure holding the state of the + input buffer. */ + unsigned int bufsize; /* The size of the input buffer. */ + + unsigned char state; /* The state of the protosocket. */ +}; + +void psock_init(struct psock *psock, char *buffer, unsigned int buffersize); +/** + * Initialize a protosocket. + * + * This macro initializes a protosocket and must be called before the + * protosocket is used. The initialization also specifies the input buffer + * for the protosocket. + * + * \param psock (struct psock *) A pointer to the protosocket to be + * initialized + * + * \param buffer (char *) A pointer to the input buffer for the + * protosocket. + * + * \param buffersize (unsigned int) The size of the input buffer. + * + * \hideinitializer + */ +#define PSOCK_INIT(psock, buffer, buffersize) \ + psock_init(psock, buffer, buffersize) + +/** + * Start the protosocket protothread in a function. + * + * This macro starts the protothread associated with the protosocket and + * must come before other protosocket calls in the function it is used. + * + * \param psock (struct psock *) A pointer to the protosocket to be + * started. + * + * \hideinitializer + */ +#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt)) + +PT_THREAD(psock_send(struct psock *psock, const char *buf, unsigned int len)); +/** + * Send data. + * + * This macro sends data over a protosocket. The protosocket protothread blocks + * until all data has been sent and is known to have been received by + * the remote end of the TCP connection. + * + * \param psock (struct psock *) A pointer to the protosocket over which + * data is to be sent. + * + * \param data (char *) A pointer to the data that is to be sent. + * + * \param datalen (unsigned int) The length of the data that is to be + * sent. + * + * \hideinitializer + */ +#define PSOCK_SEND(psock, data, datalen) \ + PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen)) + +/** + * \brief Send a null-terminated string. + * \param psock Pointer to the protosocket. + * \param str The string to be sent. + * + * This function sends a null-terminated string over the + * protosocket. + * + * \hideinitializer + */ +#define PSOCK_SEND_STR(psock, str) \ + PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str))) + +PT_THREAD(psock_generator_send(struct psock *psock, + unsigned short (*f)(void *), void *arg)); + +/** + * \brief Generate data with a function and send it + * \param psock Pointer to the protosocket. + * \param generator Pointer to the generator function + * \param arg Argument to the generator function + * + * This function generates data and sends it over the + * protosocket. This can be used to dynamically generate + * data for a transmission, instead of generating the data + * in a buffer beforehand. This function reduces the need for + * buffer memory. The generator function is implemented by + * the application, and a pointer to the function is given + * as an argument with the call to PSOCK_GENERATOR_SEND(). + * + * The generator function should place the generated data + * directly in the uip_appdata buffer, and return the + * length of the generated data. The generator function is + * called by the protosocket layer when the data first is + * sent, and once for every retransmission that is needed. + * + * \hideinitializer + */ +#define PSOCK_GENERATOR_SEND(psock, generator, arg) \ + PT_WAIT_THREAD(&((psock)->pt), \ + psock_generator_send(psock, generator, arg)) + + +/** + * Close a protosocket. + * + * This macro closes a protosocket and can only be called from within the + * protothread in which the protosocket lives. + * + * \param psock (struct psock *) A pointer to the protosocket that is to + * be closed. + * + * \hideinitializer + */ +#define PSOCK_CLOSE(psock) uip_close() + +PT_THREAD(psock_readbuf(struct psock *psock)); +/** + * Read data until the buffer is full. + * + * This macro will block waiting for data and read the data into the + * input buffer specified with the call to PSOCK_INIT(). Data is read + * until the buffer is full.. + * + * \param psock (struct psock *) A pointer to the protosocket from which + * data should be read. + * + * \hideinitializer + */ +#define PSOCK_READBUF(psock) \ + PT_WAIT_THREAD(&((psock)->pt), psock_readbuf(psock)) + +PT_THREAD(psock_readto(struct psock *psock, unsigned char c)); +/** + * Read data up to a specified character. + * + * This macro will block waiting for data and read the data into the + * input buffer specified with the call to PSOCK_INIT(). Data is only + * read until the specifieed character appears in the data stream. + * + * \param psock (struct psock *) A pointer to the protosocket from which + * data should be read. + * + * \param c (char) The character at which to stop reading. + * + * \hideinitializer + */ +#define PSOCK_READTO(psock, c) \ + PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c)) + +/** + * The length of the data that was previously read. + * + * This macro returns the length of the data that was previously read + * using PSOCK_READTO() or PSOCK_READ(). + * + * \param psock (struct psock *) A pointer to the protosocket holding the data. + * + * \hideinitializer + */ +#define PSOCK_DATALEN(psock) psock_datalen(psock) + +u16_t psock_datalen(struct psock *psock); + +/** + * Exit the protosocket's protothread. + * + * This macro terminates the protothread of the protosocket and should + * almost always be used in conjunction with PSOCK_CLOSE(). + * + * \sa PSOCK_CLOSE_EXIT() + * + * \param psock (struct psock *) A pointer to the protosocket. + * + * \hideinitializer + */ +#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt)) + +/** + * Close a protosocket and exit the protosocket's protothread. + * + * This macro closes a protosocket and exits the protosocket's protothread. + * + * \param psock (struct psock *) A pointer to the protosocket. + * + * \hideinitializer + */ +#define PSOCK_CLOSE_EXIT(psock) \ + do { \ + PSOCK_CLOSE(psock); \ + PSOCK_EXIT(psock); \ + } while(0) + +/** + * Declare the end of a protosocket's protothread. + * + * This macro is used for declaring that the protosocket's protothread + * ends. It must always be used together with a matching PSOCK_BEGIN() + * macro. + * + * \param psock (struct psock *) A pointer to the protosocket. + * + * \hideinitializer + */ +#define PSOCK_END(psock) PT_END(&((psock)->pt)) + +char psock_newdata(struct psock *s); + +/** + * Check if new data has arrived on a protosocket. + * + * This macro is used in conjunction with the PSOCK_WAIT_UNTIL() + * macro to check if data has arrived on a protosocket. + * + * \param psock (struct psock *) A pointer to the protosocket. + * + * \hideinitializer + */ +#define PSOCK_NEWDATA(psock) psock_newdata(psock) + +/** + * Wait until a condition is true. + * + * This macro blocks the protothread until the specified condition is + * true. The macro PSOCK_NEWDATA() can be used to check if new data + * arrives when the protosocket is waiting. + * + * Typically, this macro is used as follows: + * + \code + PT_THREAD(thread(struct psock *s, struct timer *t)) + { + PSOCK_BEGIN(s); + + PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t)); + + if(PSOCK_NEWDATA(s)) { + PSOCK_READTO(s, '\n'); + } else { + handle_timed_out(s); + } + + PSOCK_END(s); + } + \endcode + * + * \param psock (struct psock *) A pointer to the protosocket. + * \param condition The condition to wait for. + * + * \hideinitializer + */ +#define PSOCK_WAIT_UNTIL(psock, condition) \ + PT_WAIT_UNTIL(&((psock)->pt), (condition)); + +#define PSOCK_WAIT_THREAD(psock, condition) \ + PT_WAIT_THREAD(&((psock)->pt), (condition)) + +#endif /* __PSOCK_H__ */ + +/** @} */ diff --git a/uip/uip/pt.h b/uip/uip/pt.h new file mode 100644 index 0000000..9f1f64d --- /dev/null +++ b/uip/uip/pt.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: pt.h,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \file + * Protothreads implementation. + * \author + * Adam Dunkels + * + */ + +#ifndef __PT_H__ +#define __PT_H__ + +#include "lc.h" + +struct pt { + lc_t lc; +}; + +#define PT_WAITING 0 +#define PT_EXITED 1 +#define PT_ENDED 2 +#define PT_YIELDED 3 + +/** + * \name Initialization + * @{ + */ + +/** + * Initialize a protothread. + * + * Initializes a protothread. Initialization must be done prior to + * starting to execute the protothread. + * + * \param pt A pointer to the protothread control structure. + * + * \sa PT_SPAWN() + * + * \hideinitializer + */ +#define PT_INIT(pt) LC_INIT((pt)->lc) + +/** @} */ + +/** + * \name Declaration and definition + * @{ + */ + +/** + * Declaration of a protothread. + * + * This macro is used to declare a protothread. All protothreads must + * be declared with this macro. + * + * \param name_args The name and arguments of the C function + * implementing the protothread. + * + * \hideinitializer + */ +#define PT_THREAD(name_args) char name_args + +/** + * Declare the start of a protothread inside the C function + * implementing the protothread. + * + * This macro is used to declare the starting point of a + * protothread. It should be placed at the start of the function in + * which the protothread runs. All C statements above the PT_BEGIN() + * invokation will be executed each time the protothread is scheduled. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) + +/** + * Declare the end of a protothread. + * + * This macro is used for declaring that a protothread ends. It must + * always be used together with a matching PT_BEGIN() macro. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ + PT_INIT(pt); return PT_ENDED; } + +/** @} */ + +/** + * \name Blocked wait + * @{ + */ + +/** + * Block and wait until condition is true. + * + * This macro blocks the protothread until the specified condition is + * true. + * + * \param pt A pointer to the protothread control structure. + * \param condition The condition. + * + * \hideinitializer + */ +#define PT_WAIT_UNTIL(pt, condition) \ + do { \ + LC_SET((pt)->lc); \ + if(!(condition)) { \ + return PT_WAITING; \ + } \ + } while(0) + +/** + * Block and wait while condition is true. + * + * This function blocks and waits while condition is true. See + * PT_WAIT_UNTIL(). + * + * \param pt A pointer to the protothread control structure. + * \param cond The condition. + * + * \hideinitializer + */ +#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) + +/** @} */ + +/** + * \name Hierarchical protothreads + * @{ + */ + +/** + * Block and wait until a child protothread completes. + * + * This macro schedules a child protothread. The current protothread + * will block until the child protothread completes. + * + * \note The child protothread must be manually initialized with the + * PT_INIT() function before this function is used. + * + * \param pt A pointer to the protothread control structure. + * \param thread The child protothread with arguments + * + * \sa PT_SPAWN() + * + * \hideinitializer + */ +#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) + +/** + * Spawn a child protothread and wait until it exits. + * + * This macro spawns a child protothread and waits until it exits. The + * macro can only be used within a protothread. + * + * \param pt A pointer to the protothread control structure. + * \param child A pointer to the child protothread's control structure. + * \param thread The child protothread with arguments + * + * \hideinitializer + */ +#define PT_SPAWN(pt, child, thread) \ + do { \ + PT_INIT((child)); \ + PT_WAIT_THREAD((pt), (thread)); \ + } while(0) + +/** @} */ + +/** + * \name Exiting and restarting + * @{ + */ + +/** + * Restart the protothread. + * + * This macro will block and cause the running protothread to restart + * its execution at the place of the PT_BEGIN() call. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_RESTART(pt) \ + do { \ + PT_INIT(pt); \ + return PT_WAITING; \ + } while(0) + +/** + * Exit the protothread. + * + * This macro causes the protothread to exit. If the protothread was + * spawned by another protothread, the parent protothread will become + * unblocked and can continue to run. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_EXIT(pt) \ + do { \ + PT_INIT(pt); \ + return PT_EXITED; \ + } while(0) + +/** @} */ + +/** + * \name Calling a protothread + * @{ + */ + +/** + * Schedule a protothread. + * + * This function shedules a protothread. The return value of the + * function is non-zero if the protothread is running or zero if the + * protothread has exited. + * + * \param f The call to the C function implementing the protothread to + * be scheduled + * + * \hideinitializer + */ +#define PT_SCHEDULE(f) ((f) == PT_WAITING) + +/** @} */ + +/** + * \name Yielding from a protothread + * @{ + */ + +/** + * Yield from the current protothread. + * + * This function will yield the protothread, thereby allowing other + * processing to take place in the system. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_YIELD(pt) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if(PT_YIELD_FLAG == 0) { \ + return PT_YIELDED; \ + } \ + } while(0) + +/** + * \brief Yield from the protothread until a condition occurs. + * \param pt A pointer to the protothread control structure. + * \param cond The condition. + * + * This function will yield the protothread, until the + * specified condition evaluates to true. + * + * + * \hideinitializer + */ +#define PT_YIELD_UNTIL(pt, cond) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if((PT_YIELD_FLAG == 0) || !(cond)) { \ + return PT_YIELDED; \ + } \ + } while(0) + +/** @} */ + +#endif /* __PT_H__ */ + +/** @} */ diff --git a/uip/uip/timer.c b/uip/uip/timer.c new file mode 100644 index 0000000..74eedf6 --- /dev/null +++ b/uip/uip/timer.c @@ -0,0 +1,127 @@ +/** + * \addtogroup timer + * @{ + */ + +/** + * \file + * Timer library implementation. + * \author + * Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +#include "clock.h" +#include "timer.h" + +/*---------------------------------------------------------------------------*/ +/** + * Set a timer. + * + * This function is used to set a timer for a time sometime in the + * future. The function timer_expired() will evaluate to true after + * the timer has expired. + * + * \param t A pointer to the timer + * \param interval The interval before the timer expires. + * + */ +void +timer_set(struct timer *t, clock_time_t interval) +{ + t->interval = interval; + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Reset the timer with the same interval. + * + * This function resets the timer with the same interval that was + * given to the timer_set() function. The start point of the interval + * is the exact time that the timer last expired. Therefore, this + * function will cause the timer to be stable over time, unlike the + * timer_rester() function. + * + * \param t A pointer to the timer. + * + * \sa timer_restart() + */ +void +timer_reset(struct timer *t) +{ + t->start += t->interval; +} +/*---------------------------------------------------------------------------*/ +/** + * Restart the timer from the current point in time + * + * This function restarts a timer with the same interval that was + * given to the timer_set() function. The timer will start at the + * current time. + * + * \note A periodic timer will drift if this function is used to reset + * it. For preioric timers, use the timer_reset() function instead. + * + * \param t A pointer to the timer. + * + * \sa timer_reset() + */ +void +timer_restart(struct timer *t) +{ + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Check if a timer has expired. + * + * This function tests if a timer has expired and returns true or + * false depending on its status. + * + * \param t A pointer to the timer + * + * \return Non-zero if the timer has expired, zero otherwise. + * + */ +int +timer_expired(struct timer *t) +{ + return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval; +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/uip/uip/timer.h b/uip/uip/timer.h new file mode 100644 index 0000000..057bea4 --- /dev/null +++ b/uip/uip/timer.h @@ -0,0 +1,86 @@ +/** + * \defgroup timer Timer library + * + * The timer library provides functions for setting, resetting and + * restarting timers, and for checking if a timer has expired. An + * application must "manually" check if its timers have expired; this + * is not done automatically. + * + * A timer is declared as a \c struct \c timer and all access to the + * timer is made by a pointer to the declared timer. + * + * \note The timer library uses the \ref clock "Clock library" to + * measure time. Intervals should be specified in the format used by + * the clock library. + * + * @{ + */ + + +/** + * \file + * Timer library header file. + * \author + * Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#include "clock.h" + +/** + * A timer. + * + * This structure is used for declaring a timer. The timer must be set + * with timer_set() before it can be used. + * + * \hideinitializer + */ +struct timer { + clock_time_t start; + clock_time_t interval; +}; + +void timer_set(struct timer *t, clock_time_t interval); +void timer_reset(struct timer *t); +void timer_restart(struct timer *t); +int timer_expired(struct timer *t); + +#endif /* __TIMER_H__ */ + +/** @} */ diff --git a/uip/uip/uip-fw.c b/uip/uip/uip-fw.c new file mode 100644 index 0000000..01858ea --- /dev/null +++ b/uip/uip/uip-fw.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: uip-fw.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uipfw uIP packet forwarding + * @{ + * + */ + +/** + * \file + * uIP packet forwarding. + * \author Adam Dunkels + * + * This file implements a number of simple functions which do packet + * forwarding over multiple network interfaces with uIP. + * + */ + +#include "uip.h" +#include "uip_arch.h" +#include "uip-fw.h" + +#include /* for memcpy() */ + +/* + * The list of registered network interfaces. + */ +static struct uip_fw_netif *netifs = NULL; + +/* + * A pointer to the default network interface. + */ +static struct uip_fw_netif *defaultnetif = NULL; + +struct tcpip_hdr { + /* IP header. */ + u8_t vhl, + tos; + u16_t len, + ipid, + ipoffset; + u8_t ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; + + /* TCP header. */ + u16_t srcport, + destport; + u8_t seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + u16_t tcpchksum; + u8_t urgp[2]; + u8_t optdata[4]; +}; + +struct icmpip_hdr { + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; + /* ICMP (echo) header. */ + u8_t type, icode; + u16_t icmpchksum; + u16_t id, seqno; + u8_t payload[1]; +}; + +/* ICMP ECHO. */ +#define ICMP_ECHO 8 + +/* ICMP TIME-EXCEEDED. */ +#define ICMP_TE 11 + +/* + * Pointer to the TCP/IP headers of the packet in the uip_buf buffer. + */ +#define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/* + * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer. + */ +#define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/* + * Certain fields of an IP packet that are used for identifying + * duplicate packets. + */ +struct fwcache_entry { + u16_t timer; + + u16_t srcipaddr[2]; + u16_t destipaddr[2]; + u16_t ipid; + u8_t proto; + u8_t unused; + +#if notdef + u16_t payload[2]; +#endif + +#if UIP_REASSEMBLY > 0 + u16_t len, offset; +#endif +}; + +/* + * The number of packets to remember when looking for duplicates. + */ +#ifdef UIP_CONF_FWCACHE_SIZE +#define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE +#else +#define FWCACHE_SIZE 2 +#endif + + +/* + * A cache of packet header fields which are used for + * identifying duplicate packets. + */ +static struct fwcache_entry fwcache[FWCACHE_SIZE]; + +/** + * \internal + * The time that a packet cache is active. + */ +#define FW_TIME 20 + +/*------------------------------------------------------------------------------*/ +/** + * Initialize the uIP packet forwarding module. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_init(void) +{ + struct uip_fw_netif *t; + defaultnetif = NULL; + while(netifs != NULL) { + t = netifs; + netifs = netifs->next; + t->next = NULL; + } +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Check if an IP address is within the network defined by an IP + * address and a netmask. + * + * \param ipaddr The IP address to be checked. + * \param netipaddr The IP address of the network. + * \param netmask The netmask of the network. + * + * \return Non-zero if IP address is in network, zero otherwise. + */ +/*------------------------------------------------------------------------------*/ +static unsigned char +ipaddr_maskcmp(u16_t *ipaddr, u16_t *netipaddr, u16_t *netmask) +{ + return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) && + (ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]); +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Send out an ICMP TIME-EXCEEDED message. + * + * This function replaces the packet in the uip_buf buffer with the + * ICMP packet. + */ +/*------------------------------------------------------------------------------*/ +static void +time_exceeded(void) +{ + u16_t tmp16; + + /* We don't send out ICMP errors for ICMP messages. */ + if(ICMPBUF->proto == UIP_PROTO_ICMP) { + uip_len = 0; + return; + } + /* Copy fields from packet header into payload of this ICMP packet. */ + memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28); + + /* Set the ICMP type and code. */ + ICMPBUF->type = ICMP_TE; + ICMPBUF->icode = 0; + + /* Calculate the ICMP checksum. */ + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36); + + /* Set the IP destination address to be the source address of the + original packet. */ + tmp16= BUF->destipaddr[0]; + BUF->destipaddr[0] = BUF->srcipaddr[0]; + BUF->srcipaddr[0] = tmp16; + tmp16 = BUF->destipaddr[1]; + BUF->destipaddr[1] = BUF->srcipaddr[1]; + BUF->srcipaddr[1] = tmp16; + + /* Set our IP address as the source address. */ + BUF->srcipaddr[0] = uip_hostaddr[0]; + BUF->srcipaddr[1] = uip_hostaddr[1]; + + /* The size of the ICMP time exceeded packet is 36 + the size of the + IP header (20) = 56. */ + uip_len = 56; + ICMPBUF->len[0] = 0; + ICMPBUF->len[1] = uip_len; + + /* Fill in the other fields in the IP header. */ + ICMPBUF->vhl = 0x45; + ICMPBUF->tos = 0; + ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0; + ICMPBUF->ttl = UIP_TTL; + ICMPBUF->proto = UIP_PROTO_ICMP; + + /* Calculate IP checksum. */ + ICMPBUF->ipchksum = 0; + ICMPBUF->ipchksum = ~(uip_ipchksum()); + + +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Register a packet in the forwarding cache so that it won't be + * forwarded again. + */ +/*------------------------------------------------------------------------------*/ +static void +fwcache_register(void) +{ + struct fwcache_entry *fw; + int i, oldest; + + oldest = FW_TIME; + fw = NULL; + + /* Find the oldest entry in the cache. */ + for(i = 0; i < FWCACHE_SIZE; ++i) { + if(fwcache[i].timer == 0) { + fw = &fwcache[i]; + break; + } else if(fwcache[i].timer <= oldest) { + fw = &fwcache[i]; + oldest = fwcache[i].timer; + } + } + + fw->timer = FW_TIME; + fw->ipid = BUF->ipid; + fw->srcipaddr[0] = BUF->srcipaddr[0]; + fw->srcipaddr[1] = BUF->srcipaddr[1]; + fw->destipaddr[0] = BUF->destipaddr[0]; + fw->destipaddr[1] = BUF->destipaddr[1]; + fw->proto = BUF->proto; +#if notdef + fw->payload[0] = BUF->srcport; + fw->payload[1] = BUF->destport; +#endif +#if UIP_REASSEMBLY > 0 + fw->len = BUF->len; + fw->offset = BUF->ipoffset; +#endif +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Find a network interface for the IP packet in uip_buf. + */ +/*------------------------------------------------------------------------------*/ +static struct uip_fw_netif * +find_netif(void) +{ + struct uip_fw_netif *netif; + + /* Walk through every network interface to check for a match. */ + for(netif = netifs; netif != NULL; netif = netif->next) { + if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr, + netif->netmask)) { + /* If there was a match, we break the loop. */ + return netif; + } + } + + /* If no matching netif was found, we use default netif. */ + return defaultnetif; +} +/*------------------------------------------------------------------------------*/ +/** + * Output an IP packet on the correct network interface. + * + * The IP packet should be present in the uip_buf buffer and its + * length in the global uip_len variable. + * + * \retval UIP_FW_ZEROLEN Indicates that a zero-length packet + * transmission was attempted and that no packet was sent. + * + * \retval UIP_FW_NOROUTE No suitable network interface could be found + * for the outbound packet, and the packet was not sent. + * + * \return The return value from the actual network interface output + * function is passed unmodified as a return value. + */ +/*------------------------------------------------------------------------------*/ +u8_t +uip_fw_output(void) +{ + struct uip_fw_netif *netif; + + if(uip_len == 0) { + return UIP_FW_ZEROLEN; + } + + fwcache_register(); + +#if UIP_BROADCAST + /* Link local broadcasts go out on all interfaces. */ + if(/*BUF->proto == UIP_PROTO_UDP &&*/ + BUF->destipaddr[0] == 0xffff && + BUF->destipaddr[1] == 0xffff) { + if(defaultnetif != NULL) { + defaultnetif->output(); + } + for(netif = netifs; netif != NULL; netif = netif->next) { + netif->output(); + } + return UIP_FW_OK; + } +#endif /* UIP_BROADCAST */ + + netif = find_netif(); + /* printf("uip_fw_output: netif %p ->output %p len %d\n", netif, + netif->output, + uip_len);*/ + + if(netif == NULL) { + return UIP_FW_NOROUTE; + } + /* If we now have found a suitable network interface, we call its + output function to send out the packet. */ + return netif->output(); +} +/*------------------------------------------------------------------------------*/ +/** + * Forward an IP packet in the uip_buf buffer. + * + * + * + * \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if + * the packet should be processed locally. + */ +/*------------------------------------------------------------------------------*/ +u8_t +uip_fw_forward(void) +{ + struct fwcache_entry *fw; + + /* First check if the packet is destined for ourselves and return 0 + to indicate that the packet should be processed locally. */ + if(BUF->destipaddr[0] == uip_hostaddr[0] && + BUF->destipaddr[1] == uip_hostaddr[1]) { + return UIP_FW_LOCAL; + } + + /* If we use ping IP address configuration, and our IP address is + not yet configured, we should intercept all ICMP echo packets. */ +#if UIP_PINGADDRCONF + if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 && + BUF->proto == UIP_PROTO_ICMP && + ICMPBUF->type == ICMP_ECHO) { + return UIP_FW_LOCAL; + } +#endif /* UIP_PINGADDRCONF */ + + /* Check if the packet is in the forwarding cache already, and if so + we drop it. */ + + for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { + if(fw->timer != 0 && +#if UIP_REASSEMBLY > 0 + fw->len == BUF->len && + fw->offset == BUF->ipoffset && +#endif + fw->ipid == BUF->ipid && + fw->srcipaddr[0] == BUF->srcipaddr[0] && + fw->srcipaddr[1] == BUF->srcipaddr[1] && + fw->destipaddr[0] == BUF->destipaddr[0] && + fw->destipaddr[1] == BUF->destipaddr[1] && +#if notdef + fw->payload[0] == BUF->srcport && + fw->payload[1] == BUF->destport && +#endif + fw->proto == BUF->proto) { + /* Drop packet. */ + return UIP_FW_FORWARDED; + } + } + + /* If the TTL reaches zero we produce an ICMP time exceeded message + in the uip_buf buffer and forward that packet back to the sender + of the packet. */ + if(BUF->ttl <= 1) { + /* No time exceeded for broadcasts and multicasts! */ + if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) { + return UIP_FW_LOCAL; + } + time_exceeded(); + } + + /* Decrement the TTL (time-to-live) value in the IP header */ + BUF->ttl = BUF->ttl - 1; + + /* Update the IP checksum. */ + if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) { + BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1; + } else { + BUF->ipchksum = BUF->ipchksum + HTONS(0x0100); + } + + if(uip_len > 0) { + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]; + uip_fw_output(); + } + +#if UIP_BROADCAST + if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) { + return UIP_FW_LOCAL; + } +#endif /* UIP_BROADCAST */ + + /* Return non-zero to indicate that the packet was forwarded and that no + other processing should be made. */ + return UIP_FW_FORWARDED; +} +/*------------------------------------------------------------------------------*/ +/** + * Register a network interface with the forwarding module. + * + * \param netif A pointer to the network interface that is to be + * registered. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_register(struct uip_fw_netif *netif) +{ + netif->next = netifs; + netifs = netif; +} +/*------------------------------------------------------------------------------*/ +/** + * Register a default network interface. + * + * All packets that don't go out on any of the other interfaces will + * be routed to the default interface. + * + * \param netif A pointer to the network interface that is to be + * registered. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_default(struct uip_fw_netif *netif) +{ + defaultnetif = netif; +} +/*------------------------------------------------------------------------------*/ +/** + * Perform periodic processing. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_periodic(void) +{ + struct fwcache_entry *fw; + for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { + if(fw->timer > 0) { + --fw->timer; + } + } +} +/*------------------------------------------------------------------------------*/ diff --git a/uip/uip/uip-fw.h b/uip/uip/uip-fw.h new file mode 100644 index 0000000..9033850 --- /dev/null +++ b/uip/uip/uip-fw.h @@ -0,0 +1,176 @@ +/** + * \addtogroup uipfw + * @{ + */ + +/** + * \file + * uIP packet forwarding header file. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: uip-fw.h,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ +#ifndef __UIP_FW_H__ +#define __UIP_FW_H__ + +#include "uip.h" + +/** + * Representation of a uIP network interface. + */ +struct uip_fw_netif { + struct uip_fw_netif *next; /**< Pointer to the next interface when + linked in a list. */ + u16_t ipaddr[2]; /**< The IP address of this interface. */ + u16_t netmask[2]; /**< The netmask of the interface. */ + u8_t (* output)(void); + /**< A pointer to the function that + sends a packet. */ +}; + +/** + * Intantiating macro for a uIP network interface. + * + * Example: + \code + struct uip_fw_netif slipnetif = + {UIP_FW_NETIF(192,168,76,1, 255,255,255,0, slip_output)}; + \endcode + * \param ip1,ip2,ip3,ip4 The IP address of the network interface. + * + * \param nm1,nm2,nm3,nm4 The netmask of the network interface. + * + * \param outputfunc A pointer to the output function of the network interface. + * + * \hideinitializer + */ +#define UIP_FW_NETIF(ip1,ip2,ip3,ip4, nm1,nm2,nm3,nm4, outputfunc) \ + NULL, \ + {HTONS((ip1 << 8) | ip2), HTONS((ip3 << 8) | ip4)}, \ + {HTONS((nm1 << 8) | nm2), HTONS((nm3 << 8) | nm4)}, \ + outputfunc + +/** + * Set the IP address of a network interface. + * + * \param netif A pointer to the uip_fw_netif structure for the network interface. + * + * \param addr A pointer to an IP address. + * + * \hideinitializer + */ +#define uip_fw_setipaddr(netif, addr) \ + do { (netif)->ipaddr[0] = ((u16_t *)(addr))[0]; \ + (netif)->ipaddr[1] = ((u16_t *)(addr))[1]; } while(0) +/** + * Set the netmask of a network interface. + * + * \param netif A pointer to the uip_fw_netif structure for the network interface. + * + * \param addr A pointer to an IP address representing the netmask. + * + * \hideinitializer + */ +#define uip_fw_setnetmask(netif, addr) \ + do { (netif)->netmask[0] = ((u16_t *)(addr))[0]; \ + (netif)->netmask[1] = ((u16_t *)(addr))[1]; } while(0) + +void uip_fw_init(void); +u8_t uip_fw_forward(void); +u8_t uip_fw_output(void); +void uip_fw_register(struct uip_fw_netif *netif); +void uip_fw_default(struct uip_fw_netif *netif); +void uip_fw_periodic(void); + + +/** + * A non-error message that indicates that a packet should be + * processed locally. + * + * \hideinitializer + */ +#define UIP_FW_LOCAL 0 + +/** + * A non-error message that indicates that something went OK. + * + * \hideinitializer + */ +#define UIP_FW_OK 0 + +/** + * A non-error message that indicates that a packet was forwarded. + * + * \hideinitializer + */ +#define UIP_FW_FORWARDED 1 + +/** + * A non-error message that indicates that a zero-length packet + * transmission was attempted, and that no packet was sent. + * + * \hideinitializer + */ +#define UIP_FW_ZEROLEN 2 + +/** + * An error message that indicates that a packet that was too large + * for the outbound network interface was detected. + * + * \hideinitializer + */ +#define UIP_FW_TOOLARGE 3 + +/** + * An error message that indicates that no suitable interface could be + * found for an outbound packet. + * + * \hideinitializer + */ +#define UIP_FW_NOROUTE 4 + +/** + * An error message that indicates that a packet that should be + * forwarded or output was dropped. + * + * \hideinitializer + */ +#define UIP_FW_DROPPED 5 + + +#endif /* __UIP_FW_H__ */ + +/** @} */ diff --git a/uip/uip/uip-neighbor.c b/uip/uip/uip-neighbor.c new file mode 100644 index 0000000..18a2502 --- /dev/null +++ b/uip/uip/uip-neighbor.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: uip-neighbor.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \file + * Database of link-local neighbors, used by IPv6 code and + * to be used by a future ARP code rewrite. + * \author + * Adam Dunkels + */ + +#include "uip-neighbor.h" + +#include +#include + +#define MAX_TIME 128 + +#ifdef UIP_NEIGHBOR_CONF_ENTRIES +#define ENTRIES UIP_NEIGHBOR_CONF_ENTRIES +#else /* UIP_NEIGHBOR_CONF_ENTRIES */ +#define ENTRIES 8 +#endif /* UIP_NEIGHBOR_CONF_ENTRIES */ + +struct neighbor_entry { + uip_ipaddr_t ipaddr; + struct uip_neighbor_addr addr; + u8_t time; +}; +static struct neighbor_entry entries[ENTRIES]; + +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_init(void) +{ + int i; + + for(i = 0; i < ENTRIES; ++i) { + entries[i].time = MAX_TIME; + } +} +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_periodic(void) +{ + int i; + + for(i = 0; i < ENTRIES; ++i) { + if(entries[i].time < MAX_TIME) { + entries[i].time++; + } + } +} +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr) +{ + int i, oldest; + u8_t oldest_time; + + printf("Adding neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n", + addr->addr.addr[0], addr->addr.addr[1], addr->addr.addr[2], addr->addr.addr[3], + addr->addr.addr[4], addr->addr.addr[5]); + + /* Find the first unused entry or the oldest used entry. */ + oldest_time = 0; + oldest = 0; + for(i = 0; i < ENTRIES; ++i) { + if(entries[i].time == MAX_TIME) { + oldest = i; + break; + } + if(uip_ipaddr_cmp(entries[i].ipaddr, addr)) { + oldest = i; + break; + } + if(entries[i].time > oldest_time) { + oldest = i; + oldest_time = entries[i].time; + } + } + + /* Use the oldest or first free entry (either pointed to by the + "oldest" variable). */ + entries[oldest].time = 0; + uip_ipaddr_copy(entries[oldest].ipaddr, ipaddr); + memcpy(&entries[oldest].addr, addr, sizeof(struct uip_neighbor_addr)); +} +/*---------------------------------------------------------------------------*/ +static struct neighbor_entry * +find_entry(uip_ipaddr_t ipaddr) +{ + int i; + + for(i = 0; i < ENTRIES; ++i) { + if(uip_ipaddr_cmp(entries[i].ipaddr, ipaddr)) { + return &entries[i]; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_update(uip_ipaddr_t ipaddr) +{ + struct neighbor_entry *e; + + e = find_entry(ipaddr); + if(e != NULL) { + e->time = 0; + } +} +/*---------------------------------------------------------------------------*/ +struct uip_neighbor_addr * +uip_neighbor_lookup(uip_ipaddr_t ipaddr) +{ + struct neighbor_entry *e; + + e = find_entry(ipaddr); + if(e != NULL) { + /* printf("Lookup neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n", + e->addr.addr.addr[0], e->addr.addr.addr[1], e->addr.addr.addr[2], e->addr.addr.addr[3], + e->addr.addr.addr[4], e->addr.addr.addr[5]);*/ + + return &e->addr; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/uip/uip-neighbor.h b/uip/uip/uip-neighbor.h new file mode 100644 index 0000000..d3b351c --- /dev/null +++ b/uip/uip/uip-neighbor.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: uip-neighbor.h,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +/** + * \file + * Header file for database of link-local neighbors, used by + * IPv6 code and to be used by future ARP code. + * \author + * Adam Dunkels + */ + +#ifndef __UIP_NEIGHBOR_H__ +#define __UIP_NEIGHBOR_H__ + +#include "uip.h" + +struct uip_neighbor_addr { +#if UIP_NEIGHBOR_CONF_ADDRTYPE + UIP_NEIGHBOR_CONF_ADDRTYPE addr; +#else + struct uip_eth_addr addr; +#endif +}; + +void uip_neighbor_init(void); +void uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr); +void uip_neighbor_update(uip_ipaddr_t ipaddr); +struct uip_neighbor_addr *uip_neighbor_lookup(uip_ipaddr_t ipaddr); +void uip_neighbor_periodic(void); + +#endif /* __UIP-NEIGHBOR_H__ */ diff --git a/uip/uip/uip-split.c b/uip/uip/uip-split.c new file mode 100644 index 0000000..a910ee6 --- /dev/null +++ b/uip/uip/uip-split.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: uip-split.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +#include + +#include "uip-split.h" +#include "uip.h" +#include "uip-fw.h" +#include "uip_arch.h" + + + +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/*-----------------------------------------------------------------------------*/ +void +uip_split_output(void) +{ + u16_t tcplen, len1, len2; + + /* We only try to split maximum sized TCP segments. */ + if(BUF->proto == UIP_PROTO_TCP && + uip_len == UIP_BUFSIZE - UIP_LLH_LEN) { + + tcplen = uip_len - UIP_TCPIP_HLEN; + /* Split the segment in two. If the original packet length was + odd, we make the second packet one byte larger. */ + len1 = len2 = tcplen / 2; + if(len1 + len2 < tcplen) { + ++len2; + } + + /* Create the first packet. This is done by altering the length + field of the IP header and updating the checksums. */ + uip_len = len1 + UIP_TCPIP_HLEN; +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = uip_len >> 8; + BUF->len[1] = uip_len & 0xff; +#endif /* UIP_CONF_IPV6 */ + + /* Recalculate the TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + +#if !UIP_CONF_IPV6 + /* Recalculate the IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); +#endif /* UIP_CONF_IPV6 */ + + /* Transmit the first packet. */ + /* uip_fw_output();*/ + tcpip_output(); + + /* Now, create the second packet. To do this, it is not enough to + just alter the length field, but we must also update the TCP + sequence number and point the uip_appdata to a new place in + memory. This place is detemined by the length of the first + packet (len1). */ + uip_len = len2 + UIP_TCPIP_HLEN; +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = uip_len >> 8; + BUF->len[1] = uip_len & 0xff; +#endif /* UIP_CONF_IPV6 */ + + /* uip_appdata += len1;*/ + memcpy(uip_appdata, (u8_t *)uip_appdata + len1, len2); + + uip_add32(BUF->seqno, len1); + BUF->seqno[0] = uip_acc32[0]; + BUF->seqno[1] = uip_acc32[1]; + BUF->seqno[2] = uip_acc32[2]; + BUF->seqno[3] = uip_acc32[3]; + + /* Recalculate the TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + +#if !UIP_CONF_IPV6 + /* Recalculate the IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); +#endif /* UIP_CONF_IPV6 */ + + /* Transmit the second packet. */ + /* uip_fw_output();*/ + tcpip_output(); + } else { + /* uip_fw_output();*/ + tcpip_output(); + } + +} +/*-----------------------------------------------------------------------------*/ diff --git a/uip/uip/uip-split.h b/uip/uip/uip-split.h new file mode 100644 index 0000000..c2c1789 --- /dev/null +++ b/uip/uip/uip-split.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: uip-split.h,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uipsplit uIP TCP throughput booster hack + * @{ + * + * The basic uIP TCP implementation only allows each TCP connection to + * have a single TCP segment in flight at any given time. Because of + * the delayed ACK algorithm employed by most TCP receivers, uIP's + * limit on the amount of in-flight TCP segments seriously reduces the + * maximum achievable throughput for sending data from uIP. + * + * The uip-split module is a hack which tries to remedy this + * situation. By splitting maximum sized outgoing TCP segments into + * two, the delayed ACK algorithm is not invoked at TCP + * receivers. This improves the throughput when sending data from uIP + * by orders of magnitude. + * + * The uip-split module uses the uip-fw module (uIP IP packet + * forwarding) for sending packets. Therefore, the uip-fw module must + * be set up with the appropriate network interfaces for this module + * to work. + */ + + +/** + * \file + * Module for splitting outbound TCP segments in two to avoid the + * delayed ACK throughput degradation. + * \author + * Adam Dunkels + * + */ + +#ifndef __UIP_SPLIT_H__ +#define __UIP_SPLIT_H__ + +/** + * Handle outgoing packets. + * + * This function inspects an outgoing packet in the uip_buf buffer and + * sends it out using the uip_fw_output() function. If the packet is a + * full-sized TCP segment it will be split into two segments and + * transmitted separately. This function should be called instead of + * the actual device driver output function, or the uip_fw_output() + * function. + * + * The headers of the outgoing packet is assumed to be in the uip_buf + * buffer and the payload is assumed to be wherever uip_appdata + * points. The length of the outgoing packet is assumed to be in the + * uip_len variable. + * + */ +void uip_split_output(void); + +#endif /* __UIP_SPLIT_H__ */ + +/** @} */ +/** @} */ diff --git a/uip/uip/uip.c b/uip/uip/uip.c new file mode 100644 index 0000000..c5f7b93 --- /dev/null +++ b/uip/uip/uip.c @@ -0,0 +1,1912 @@ +#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/ + +/** + * \defgroup uip The uIP TCP/IP stack + * @{ + * + * uIP is an implementation of the TCP/IP protocol stack intended for + * small 8-bit and 16-bit microcontrollers. + * + * uIP provides the necessary protocols for Internet communication, + * with a very small code footprint and RAM requirements - the uIP + * code size is on the order of a few kilobytes and RAM usage is on + * the order of a few hundred bytes. + */ + +/** + * \file + * The uIP TCP/IP stack code. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $ + * + */ + +/* + * uIP is a small implementation of the IP, UDP and TCP protocols (as + * well as some basic ICMP stuff). The implementation couples the IP, + * UDP, TCP and the application layers very tightly. To keep the size + * of the compiled code down, this code frequently uses the goto + * statement. While it would be possible to break the uip_process() + * function into many smaller functions, this would increase the code + * size because of the overhead of parameter passing and the fact that + * the optimier would not be as efficient. + * + * The principle is that we have a small buffer, called the uip_buf, + * in which the device driver puts an incoming packet. The TCP/IP + * stack parses the headers in the packet, and calls the + * application. If the remote host has sent data to the application, + * this data is present in the uip_buf and the application read the + * data from there. It is up to the application to put this data into + * a byte stream if needed. The application will not be fed with data + * that is out of sequence. + * + * If the application whishes to send data to the peer, it should put + * its data into the uip_buf. The uip_appdata pointer points to the + * first available byte. The TCP/IP stack will calculate the + * checksums, and fill in the necessary header fields and finally send + * the packet back to the peer. +*/ + +#include "uip.h" +#include "uipopt.h" +#include "uip_arch.h" + +#if UIP_CONF_IPV6 +#include "uip-neighbor.h" +#endif /* UIP_CONF_IPV6 */ + +#include + +/*---------------------------------------------------------------------------*/ +/* Variable definitions. */ + + +/* The IP address of this host. If it is defined to be fixed (by + setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set + here. Otherwise, the address */ +#if UIP_FIXEDADDR > 0 +const uip_ipaddr_t uip_hostaddr = + {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1), + HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)}; +const uip_ipaddr_t uip_draddr = + {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1), + HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)}; +const uip_ipaddr_t uip_netmask = + {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1), + HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)}; +#else +uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask; +#endif /* UIP_FIXEDADDR */ + +static const uip_ipaddr_t all_ones_addr = +#if UIP_CONF_IPV6 + {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; +#else /* UIP_CONF_IPV6 */ + {0xffff,0xffff}; +#endif /* UIP_CONF_IPV6 */ +static const uip_ipaddr_t all_zeroes_addr = +#if UIP_CONF_IPV6 + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; +#else /* UIP_CONF_IPV6 */ + {0x0000,0x0000}; +#endif /* UIP_CONF_IPV6 */ + + +#if UIP_CONF_IPV6 +#if UIP_FIXEDETHADDR +const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0, + UIP_ETHADDR1, + UIP_ETHADDR2, + UIP_ETHADDR3, + UIP_ETHADDR4, + UIP_ETHADDR5}}; +#else +struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +#endif +#endif /* UIP_CONF_IPV6 */ + +#ifndef UIP_CONF_EXTERNAL_BUFFER +u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains + incoming packets. */ +#endif /* UIP_CONF_EXTERNAL_BUFFER */ + +void *uip_appdata; /* The uip_appdata pointer points to + application data. */ +void *uip_sappdata; /* The uip_appdata pointer points to + the application data which is to + be sent. */ +#if UIP_URGDATA > 0 +void *uip_urgdata; /* The uip_urgdata pointer points to + urgent data (out-of-band data), if + present. */ +u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + +u16_t uip_len, uip_slen; + /* The uip_len is either 8 or 16 bits, + depending on the maximum packet + size. */ + +u8_t uip_flags; /* The uip_flags variable is used for + communication between the TCP/IP stack + and the application program. */ +struct uip_conn *uip_conn; /* uip_conn always points to the current + connection. */ + +struct uip_conn uip_conns[UIP_CONNS]; + /* The uip_conns array holds all TCP + connections. */ + +#ifdef UIP_TCP_LISTEN +u16_t uip_listenports[UIP_LISTENPORTS]; + /* The uip_listenports list all currently + listning ports. */ +#endif + +#if UIP_UDP +struct uip_udp_conn *uip_udp_conn; +struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +static u16_t ipid; /* Ths ipid variable is an increasing + number that is used for the IP ID + field. */ + +void uip_setipid(u16_t id) { ipid = id; } + +static u8_t iss[4]; /* The iss variable is used for the TCP + initial sequence number. */ + +#if UIP_ACTIVE_OPEN +static u16_t lastport; /* Keeps track of the last port used for + a new connection. */ +#endif /* UIP_ACTIVE_OPEN */ + +/* Temporary variables. */ +u8_t uip_acc32[4]; +static u8_t c, opt; +static u16_t tmp16; + +/* Structures and definitions. */ +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 +#define TCP_CTL 0x3f + +#define TCP_OPT_END 0 /* End of TCP options list */ +#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */ +#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */ + +#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */ + +#define ICMP_ECHO_REPLY 0 +#define ICMP_ECHO 8 + +#define ICMP6_ECHO_REPLY 129 +#define ICMP6_ECHO 128 +#define ICMP6_NEIGHBOR_SOLICITATION 135 +#define ICMP6_NEIGHBOR_ADVERTISEMENT 136 + +#define ICMP6_FLAG_S (1 << 6) + +#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1 +#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2 + + +/* Macros. */ +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) +#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +#if UIP_LOGGING == 1 +#include +void uip_log(char *msg); +#define UIP_LOG(m) uip_log(m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if ! UIP_ARCH_ADD32 +void +uip_add32(u8_t *op32, u16_t op16) +{ + uip_acc32[3] = op32[3] + (op16 & 0xff); + uip_acc32[2] = op32[2] + (op16 >> 8); + uip_acc32[1] = op32[1]; + uip_acc32[0] = op32[0]; + + if(uip_acc32[2] < (op16 >> 8)) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + + + if(uip_acc32[3] < (op16 & 0xff)) { + ++uip_acc32[2]; + if(uip_acc32[2] == 0) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + } +} + +#endif /* UIP_ARCH_ADD32 */ + +#if ! UIP_ARCH_CHKSUM +/*---------------------------------------------------------------------------*/ +static u16_t +chksum(u16_t sum, const u8_t *data, u16_t len) +{ + u16_t t; + const u8_t *dataptr; + const u8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} +/*---------------------------------------------------------------------------*/ +u16_t +uip_chksum(u16_t *data, u16_t len) +{ + return htons(chksum(0, (u8_t *)data, len)); +} +/*---------------------------------------------------------------------------*/ +#ifndef UIP_ARCH_IPCHKSUM +u16_t +uip_ipchksum(void) +{ + u16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum); + return (sum == 0) ? 0xffff : htons(sum); +} +#endif +/*---------------------------------------------------------------------------*/ +static u16_t +upper_layer_chksum(u8_t proto) +{ + u16_t upper_layer_len; + u16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = upper_layer_len + proto; + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + /* Sum TCP header and data. */ + sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], + upper_layer_len); + + return (sum == 0) ? 0xffff : htons(sum); +} +/*---------------------------------------------------------------------------*/ +#if UIP_CONF_IPV6 +u16_t +uip_icmp6chksum(void) +{ + return upper_layer_chksum(UIP_PROTO_ICMP6); + +} +#endif /* UIP_CONF_IPV6 */ +/*---------------------------------------------------------------------------*/ +u16_t +uip_tcpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_TCP); +} +/*---------------------------------------------------------------------------*/ +#if UIP_UDP_CHECKSUMS +u16_t +uip_udpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_UDP); +} +#endif /* UIP_UDP_CHECKSUMS */ +#endif /* UIP_ARCH_CHKSUM */ +/*---------------------------------------------------------------------------*/ +void +uip_init(void) +{ +#ifdef UIP_TCP_LISTEN + for(c = 0; c < UIP_LISTENPORTS; ++c) { + uip_listenports[c] = 0; + } +#endif + for(c = 0; c < UIP_CONNS; ++c) { + uip_conns[c].tcpstateflags = UIP_CLOSED; + } +#if UIP_ACTIVE_OPEN + lastport = 1024; +#endif /* UIP_ACTIVE_OPEN */ + +#if UIP_UDP + for(c = 0; c < UIP_UDP_CONNS; ++c) { + uip_udp_conns[c].lport = 0; + } +#endif /* UIP_UDP */ + + + /* IPv4 initialization. */ +#if UIP_FIXEDADDR == 0 + /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/ +#endif /* UIP_FIXEDADDR */ + +} +/*---------------------------------------------------------------------------*/ +#if UIP_ACTIVE_OPEN +struct uip_conn * +uip_connect(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_conn *conn, *cconn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + /* Check if this port is already in use, and if so try to find + another one. */ + for(c = 0; c < UIP_CONNS; ++c) { + conn = &uip_conns[c]; + if(conn->tcpstateflags != UIP_CLOSED && + conn->lport == htons(lastport)) { + goto again; + } + } + + conn = 0; + for(c = 0; c < UIP_CONNS; ++c) { + cconn = &uip_conns[c]; + if(cconn->tcpstateflags == UIP_CLOSED) { + conn = cconn; + break; + } + if(cconn->tcpstateflags == UIP_TIME_WAIT) { + if(conn == 0 || + cconn->timer > conn->timer) { + conn = cconn; + } + } + } + + if(conn == 0) { + return 0; + } + + conn->tcpstateflags = UIP_SYN_SENT; + + conn->snd_nxt[0] = iss[0]; + conn->snd_nxt[1] = iss[1]; + conn->snd_nxt[2] = iss[2]; + conn->snd_nxt[3] = iss[3]; + + conn->initialmss = conn->mss = UIP_TCP_MSS; + + conn->len = 1; /* TCP length of the SYN is one. */ + conn->nrtx = 0; + conn->timer = 1; /* Send the SYN next time around. */ + conn->rto = UIP_RTO; + conn->sa = 0; + conn->sv = 16; /* Initial value of the RTT variance. */ + conn->lport = htons(lastport); + conn->rport = rport; + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + + return conn; +} +#endif /* UIP_ACTIVE_OPEN */ +/*---------------------------------------------------------------------------*/ +#if UIP_UDP +struct uip_udp_conn * +uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_udp_conn *conn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == htons(lastport)) { + goto again; + } + } + + + conn = 0; + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == 0) { + conn = &uip_udp_conns[c]; + break; + } + } + + if(conn == 0) { + return 0; + } + + conn->lport = HTONS(lastport); + conn->rport = rport; + if(ripaddr == NULL) { + memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); + } else { + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + } + conn->ttl = UIP_TTL; + + return conn; +} +#endif /* UIP_UDP */ +/*---------------------------------------------------------------------------*/ +#ifdef UIP_TCP_LISTEN +void +uip_unlisten(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == port) { + uip_listenports[c] = 0; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +void +uip_listen(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == 0) { + uip_listenports[c] = port; + return; + } + } +} +#endif +/*---------------------------------------------------------------------------*/ +/* XXX: IP fragment reassembly: not well-tested. */ + +#if UIP_REASSEMBLY && !UIP_CONF_IPV6 +#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN) +static u8_t uip_reassbuf[UIP_REASS_BUFSIZE]; +static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; +static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, + 0x0f, 0x07, 0x03, 0x01}; +static u16_t uip_reasslen; +static u8_t uip_reassflags; +#define UIP_REASS_FLAG_LASTFRAG 0x01 +static u8_t uip_reasstmr; + +#define IP_MF 0x20 + +static u8_t +uip_reass(void) +{ + u16_t offset, len; + u16_t i; + + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + if(uip_reasstmr == 0) { + memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN); + uip_reasstmr = UIP_REASS_MAXAGE; + uip_reassflags = 0; + /* Clear the bitmap. */ + memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] && + BUF->srcipaddr[1] == FBUF->srcipaddr[1] && + BUF->destipaddr[0] == FBUF->destipaddr[0] && + BUF->destipaddr[1] == FBUF->destipaddr[1] && + BUF->ipid[0] == FBUF->ipid[0] && + BUF->ipid[1] == FBUF->ipid[1]) { + + len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4; + offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if(offset > UIP_REASS_BUFSIZE || + offset + len > UIP_REASS_BUFSIZE) { + uip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], + (char *)BUF + (int)((BUF->vhl & 0x0f) * 4), + len); + + /* Update the bitmap. */ + if(offset / (8 * 8) == (offset + len) / (8 * 8)) { + /* If the two endpoints are in the same byte, we only update + that byte. */ + + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7] & + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7]; + for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + uip_reassbitmap[i] = 0xff; + } + uip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if((BUF->ipoffset[0] & IP_MF) == 0) { + uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; + uip_reasslen = offset + len; + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { + if(uip_reassbitmap[i] != 0xff) { + goto nullreturn; + } + } + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + if(uip_reassbitmap[uip_reasslen / (8 * 8)] != + (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { + goto nullreturn; + } + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + uip_reasstmr = 0; + memcpy(BUF, FBUF, uip_reasslen); + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + BUF->len[0] = uip_reasslen >> 8; + BUF->len[1] = uip_reasslen & 0xff; + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + + return uip_reasslen; + } + } + + nullreturn: + return 0; +} +#endif /* UIP_REASSEMBLY */ +/*---------------------------------------------------------------------------*/ +static void +uip_add_rcv_nxt(u16_t n) +{ + uip_add32(uip_conn->rcv_nxt, n); + uip_conn->rcv_nxt[0] = uip_acc32[0]; + uip_conn->rcv_nxt[1] = uip_acc32[1]; + uip_conn->rcv_nxt[2] = uip_acc32[2]; + uip_conn->rcv_nxt[3] = uip_acc32[3]; +} +/*---------------------------------------------------------------------------*/ +void +uip_process(u8_t flag) +{ + register struct uip_conn *uip_connr = uip_conn; + +#if UIP_UDP + if(flag == UIP_UDP_SEND_CONN) { + goto udp_send; + } +#endif /* UIP_UDP */ + + uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; + + /* Check if we were invoked because of a poll request for a + particular connection. */ + if(flag == UIP_POLL_REQUEST) { + if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && + !uip_outstanding(uip_connr)) { + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + goto drop; + + /* Check if we were invoked because of the perodic timer fireing. */ + } else if(flag == UIP_TIMER) { +#if UIP_REASSEMBLY + if(uip_reasstmr != 0) { + --uip_reasstmr; + } +#endif /* UIP_REASSEMBLY */ + /* Increase the initial sequence number. */ + if(++iss[3] == 0) { + if(++iss[2] == 0) { + if(++iss[1] == 0) { + ++iss[0]; + } + } + } + + /* Reset the length variables. */ + uip_len = 0; + uip_slen = 0; + + /* Check if the connection is in a state in which we simply wait + for the connection to time out. If so, we increase the + connection's timer and remove the connection if it times + out. */ + if(uip_connr->tcpstateflags == UIP_TIME_WAIT || + uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { + ++(uip_connr->timer); + if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { + uip_connr->tcpstateflags = UIP_CLOSED; + } + } else if(uip_connr->tcpstateflags != UIP_CLOSED) { + /* If the connection has outstanding data, we increase the + connection's timer and see if it has reached the RTO value + in which case we retransmit. */ + if(uip_outstanding(uip_connr)) { + if(uip_connr->timer-- == 0) { + if(uip_connr->nrtx == UIP_MAXRTX || + ((uip_connr->tcpstateflags == UIP_SYN_SENT || + uip_connr->tcpstateflags == UIP_SYN_RCVD) && + uip_connr->nrtx == UIP_MAXSYNRTX)) { + uip_connr->tcpstateflags = UIP_CLOSED; + + /* We call UIP_APPCALL() with uip_flags set to + UIP_TIMEDOUT to inform the application that the + connection has timed out. */ + uip_flags = UIP_TIMEDOUT; + UIP_APPCALL(); + + /* We also send a reset packet to the remote host. */ + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + /* Exponential backoff. */ + uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4? + 4: + uip_connr->nrtx); + ++(uip_connr->nrtx); + + /* Ok, so we need to retransmit. We do this differently + depending on which state we are in. In ESTABLISHED, we + call upon the application so that it may prepare the + data for the retransmit. In SYN_RCVD, we resend the + SYNACK that we sent earlier and in LAST_ACK we have to + retransmit our FINACK. */ + UIP_STAT(++uip_stat.tcp.rexmit); + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + case UIP_SYN_RCVD: + /* In the SYN_RCVD state, we should retransmit our + SYNACK. */ + goto tcp_send_synack; + +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In the SYN_SENT state, we retransmit out SYN. */ + BUF->flags = 0; + goto tcp_send_syn; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application + to do the actual retransmit after which we jump into + the code for sending out the packet (the apprexmit + label). */ + uip_flags = UIP_REXMIT; + UIP_APPCALL(); + goto apprexmit; + + case UIP_FIN_WAIT_1: + case UIP_CLOSING: + case UIP_LAST_ACK: + /* In all these states we should retransmit a FINACK. */ + goto tcp_send_finack; + + } + } + } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { + /* If there was no need for a retransmission, we poll the + application for new data. */ + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + } + goto drop; + } +#if UIP_UDP + if(flag == UIP_UDP_TIMER) { + if(uip_udp_conn->lport != 0) { + uip_conn = NULL; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_len = uip_slen = 0; + uip_flags = UIP_POLL; + UIP_UDP_APPCALL(); + goto udp_send; + } else { + goto drop; + } + } +#endif + + /* This is where the input processing starts. */ + UIP_STAT(++uip_stat.ip.recv); + + /* Start of IP input header processing code. */ + +#if UIP_CONF_IPV6 + /* Check validity of the IP header. */ + if((BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ipv6: invalid version."); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* Check validity of the IP header. */ + if(BUF->vhl != 0x45) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ip: invalid version or header length."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + /* Check the size of the packet. If the size reported to us in + uip_len is smaller the size reported in the IP header, we assume + that the packet has been corrupted in transit. If the size of + uip_len is larger than the size reported in the IP packet header, + the packet has been padded and we set uip_len to the correct + value.. */ + + if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) { + uip_len = (BUF->len[0] << 8) + BUF->len[1]; +#if UIP_CONF_IPV6 + uip_len += 40; /* The length reported in the IPv6 header is the + length of the payload that follows the + header. However, uIP uses the uip_len variable + for holding the size of the entire packet, + including the IP header. For IPv4 this is not a + problem as the length field in the IPv4 header + contains the length of the entire packet. But + for IPv6 we need to add the size of the IPv6 + header (40 bytes). */ +#endif /* UIP_CONF_IPV6 */ + } else { + UIP_LOG("ip: packet shorter than reported in IP header."); + goto drop; + } + +#if !UIP_CONF_IPV6 + /* Check the fragment flag. */ + if((BUF->ipoffset[0] & 0x3f) != 0 || + BUF->ipoffset[1] != 0) { +#if UIP_REASSEMBLY + uip_len = uip_reass(); + if(uip_len == 0) { + goto drop; + } +#else /* UIP_REASSEMBLY */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.fragerr); + UIP_LOG("ip: fragment dropped."); + goto drop; +#endif /* UIP_REASSEMBLY */ + } +#endif /* UIP_CONF_IPV6 */ + + if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) { + /* If we are configured to use ping IP address configuration and + hasn't been assigned an IP address yet, we accept all ICMP + packets. */ +#if UIP_PINGADDRCONF && !UIP_CONF_IPV6 + if(BUF->proto == UIP_PROTO_ICMP) { + UIP_LOG("ip: possible ping config packet received."); + goto icmp_input; + } else { + UIP_LOG("ip: packet dropped since no address assigned."); + goto drop; + } +#endif /* UIP_PINGADDRCONF */ + + } else { + /* If IP broadcast support is configured, we check for a broadcast + UDP packet, which may be destined to us. */ +#if UIP_BROADCAST + DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum()); + if(BUF->proto == UIP_PROTO_UDP && + uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) + /*&& + uip_ipchksum() == 0xffff*/) { + goto udp_input; + } +#endif /* UIP_BROADCAST */ + + /* Check if the packet is destined for our IP address. */ +#if !UIP_CONF_IPV6 + if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* For IPv6, packet reception is a little trickier as we need to + make sure that we listen to certain multicast addresses (all + hosts multicast address, and the solicited-node multicast + address) as well. However, we will cheat here and accept all + multicast packets that are sent to the ff02::/16 addresses. */ + if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && + BUF->destipaddr[0] != HTONS(0xff02)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + } + +#if !UIP_CONF_IPV6 + if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header + checksum. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.chkerr); + UIP_LOG("ip: bad checksum."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so, + proceed with TCP input + processing. */ + goto tcp_input; + } + +#if UIP_UDP + if(BUF->proto == UIP_PROTO_UDP) { + goto udp_input; + } +#endif /* UIP_UDP */ + +#if !UIP_CONF_IPV6 + /* ICMPv4 processing code follows. */ + if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp."); + goto drop; + } + +#if UIP_PINGADDRCONF + icmp_input: +#endif /* UIP_PINGADDRCONF */ + UIP_STAT(++uip_stat.icmp.recv); + + /* ICMP echo (i.e., ping) processing. This is simple, we only change + the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP + checksum before we return the packet. */ + if(ICMPBUF->type != ICMP_ECHO) { + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: not icmp echo."); + goto drop; + } + + /* If we are configured to use ping IP address assignment, we use + the destination IP address of this ping packet and assign it to + ourself. */ +#if UIP_PINGADDRCONF + if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) { + uip_hostaddr[0] = BUF->destipaddr[0]; + uip_hostaddr[1] = BUF->destipaddr[1]; + } +#endif /* UIP_PINGADDRCONF */ + + ICMPBUF->type = ICMP_ECHO_REPLY; + + if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1; + } else { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8); + } + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + + /* End of IPv4 input header processing code. */ +#else /* !UIP_CONF_IPV6 */ + + /* This is IPv6 ICMPv6 processing code. */ + DEBUG_PRINTF("icmp6_input: length %d\n", uip_len); + + if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp6."); + goto drop; + } + + UIP_STAT(++uip_stat.icmp.recv); + + /* If we get a neighbor solicitation for our address we should send + a neighbor advertisement message back. */ + if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) { + if(uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) { + + if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { + /* Save the sender's address in our neighbor list. */ + uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2])); + } + + /* We should now send a neighbor advertisement back to where the + neighbor solicication came from. */ + ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT; + ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */ + + ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0; + + uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr); + uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr); + ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; + ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */ + memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr)); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + goto send; + + } + goto drop; + } else if(ICMPBUF->type == ICMP6_ECHO) { + /* ICMP echo (i.e., ping) processing. This is simple, we only + change the ICMP type from ECHO to ECHO_REPLY and update the + ICMP checksum before we return the packet. */ + + ICMPBUF->type = ICMP6_ECHO_REPLY; + + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + } else { + DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type); + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: unknown ICMP message."); + goto drop; + } + + /* End of IPv6 ICMP processing. */ + +#endif /* !UIP_CONF_IPV6 */ + +#if UIP_UDP + /* UDP input processing. */ + udp_input: + /* UDP processing is really just a hack. We don't do anything to the + UDP/IP headers, but let the UDP application do all the hard + work. If the application sets uip_slen, it has a packet to + send. */ +#if UIP_UDP_CHECKSUMS + uip_len = uip_len - UIP_IPUDPH_LEN; + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) { + UIP_STAT(++uip_stat.udp.drop); + UIP_STAT(++uip_stat.udp.chkerr); + UIP_LOG("udp: bad checksum."); + goto drop; + } +#else /* UIP_UDP_CHECKSUMS */ + uip_len = uip_len - UIP_IPUDPH_LEN; +#endif /* UIP_UDP_CHECKSUMS */ + + /* Demultiplex this UDP packet between the UDP "connections". */ + for(uip_udp_conn = &uip_udp_conns[0]; + uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; + ++uip_udp_conn) { + /* If the local UDP port is non-zero, the connection is considered + to be used. If so, the local port number is checked against the + destination port number in the received packet. If the two port + numbers match, the remote port number is checked if the + connection is bound to a remote port. Finally, if the + connection is bound to a remote IP address, the source IP + address of the packet is checked. */ + if(uip_udp_conn->lport != 0 && + UDPBUF->destport == uip_udp_conn->lport && + (uip_udp_conn->rport == 0 || + UDPBUF->srcport == uip_udp_conn->rport) && + (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) || + uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) || + uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) { + goto udp_found; + } + } + UIP_LOG("udp: no matching connection found"); + goto drop; + + udp_found: + uip_conn = NULL; + uip_flags = UIP_NEWDATA; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_slen = 0; + UIP_UDP_APPCALL(); + udp_send: + if(uip_slen == 0) { + goto drop; + } + uip_len = uip_slen + UIP_IPUDPH_LEN; + +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->ttl = uip_udp_conn->ttl; + BUF->proto = UIP_PROTO_UDP; + + UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN); + UDPBUF->udpchksum = 0; + + BUF->srcport = uip_udp_conn->lport; + BUF->destport = uip_udp_conn->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr); + + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN]; + +#if UIP_UDP_CHECKSUMS + /* Calculate UDP checksum. */ + UDPBUF->udpchksum = ~(uip_udpchksum()); + if(UDPBUF->udpchksum == 0) { + UDPBUF->udpchksum = 0xffff; + } +#endif /* UIP_UDP_CHECKSUMS */ + + goto ip_send_nolen; +#endif /* UIP_UDP */ + + /* TCP input processing. */ + tcp_input: + UIP_STAT(++uip_stat.tcp.recv); + + /* Start of TCP input header processing code. */ + + if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP + checksum. */ + UIP_STAT(++uip_stat.tcp.drop); + UIP_STAT(++uip_stat.tcp.chkerr); + UIP_LOG("tcp: bad checksum."); + goto drop; + } + + + /* Demultiplex this segment. */ + /* First check any active connections. */ + for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; + ++uip_connr) { + if(uip_connr->tcpstateflags != UIP_CLOSED && + BUF->destport == uip_connr->lport && + BUF->srcport == uip_connr->rport && + uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) { + goto found; + } + } + + /* If we didn't find and active connection that expected the packet, + either this packet is an old duplicate, or this is a SYN packet + destined for a connection in LISTEN. If the SYN flag isn't set, + it is an old packet and we send a RST. */ + if((BUF->flags & TCP_CTL) != TCP_SYN) { + goto reset; + } + + tmp16 = BUF->destport; + +#ifdef UIP_TCP_LISTEN + /* Next, check listening connections. */ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(tmp16 == uip_listenports[c]) + goto found_listen; + } +#endif + + /* No matching connection found, so we send a RST packet. */ + UIP_STAT(++uip_stat.tcp.synrst); + reset: + + /* We do not send resets in response to resets. */ + if(BUF->flags & TCP_RST) { + goto drop; + } + + UIP_STAT(++uip_stat.tcp.rst); + + BUF->flags = TCP_RST | TCP_ACK; + uip_len = UIP_IPTCPH_LEN; + BUF->tcpoffset = 5 << 4; + + /* Flip the seqno and ackno fields in the TCP header. */ + c = BUF->seqno[3]; + BUF->seqno[3] = BUF->ackno[3]; + BUF->ackno[3] = c; + + c = BUF->seqno[2]; + BUF->seqno[2] = BUF->ackno[2]; + BUF->ackno[2] = c; + + c = BUF->seqno[1]; + BUF->seqno[1] = BUF->ackno[1]; + BUF->ackno[1] = c; + + c = BUF->seqno[0]; + BUF->seqno[0] = BUF->ackno[0]; + BUF->ackno[0] = c; + + /* We also have to increase the sequence number we are + acknowledging. If the least significant byte overflowed, we need + to propagate the carry to the other bytes as well. */ + if(++BUF->ackno[3] == 0) { + if(++BUF->ackno[2] == 0) { + if(++BUF->ackno[1] == 0) { + ++BUF->ackno[0]; + } + } + } + + /* Swap port numbers. */ + tmp16 = BUF->srcport; + BUF->srcport = BUF->destport; + BUF->destport = tmp16; + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + /* And send out the RST packet! */ + goto tcp_send_noconn; + +#ifdef UIP_TCP_LISTEN + /* This label will be jumped to if we matched the incoming packet + with a connection in LISTEN. In that case, we should create a new + connection and send a SYNACK in return. */ + found_listen: + /* First we check if there are any connections avaliable. Unused + connections are kept in the same table as used connections, but + unused ones have the tcpstate set to CLOSED. Also, connections in + TIME_WAIT are kept track of and we'll use the oldest one if no + CLOSED connections are found. Thanks to Eddie C. Dost for a very + nice algorithm for the TIME_WAIT search. */ + uip_connr = 0; + for(c = 0; c < UIP_CONNS; ++c) { + if(uip_conns[c].tcpstateflags == UIP_CLOSED) { + uip_connr = &uip_conns[c]; + break; + } + if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { + if(uip_connr == 0 || + uip_conns[c].timer > uip_connr->timer) { + uip_connr = &uip_conns[c]; + } + } + } + + if(uip_connr == 0) { + /* All connections are used already, we drop packet and hope that + the remote end will retransmit the packet at a time when we + have more spare connections. */ + UIP_STAT(++uip_stat.tcp.syndrop); + UIP_LOG("tcp: found no unused connections."); + goto drop; + } + uip_conn = uip_connr; + + /* Fill in the necessary fields for the new connection. */ + uip_connr->rto = uip_connr->timer = UIP_RTO; + uip_connr->sa = 0; + uip_connr->sv = 4; + uip_connr->nrtx = 0; + uip_connr->lport = BUF->destport; + uip_connr->rport = BUF->srcport; + uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr); + uip_connr->tcpstateflags = UIP_SYN_RCVD; + + uip_connr->snd_nxt[0] = iss[0]; + uip_connr->snd_nxt[1] = iss[1]; + uip_connr->snd_nxt[2] = iss[2]; + uip_connr->snd_nxt[3] = iss[3]; + uip_connr->len = 1; + + /* rcv_nxt should be the seqno from the incoming packet + 1. */ + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_add_rcv_nxt(1); + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = uip_connr->mss = + tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } +#endif + + /* Our response will be a SYNACK. */ +#if UIP_ACTIVE_OPEN + tcp_send_synack: + BUF->flags = TCP_ACK; + + tcp_send_syn: + BUF->flags |= TCP_SYN; +#else /* UIP_ACTIVE_OPEN */ + tcp_send_synack: + BUF->flags = TCP_SYN | TCP_ACK; +#endif /* UIP_ACTIVE_OPEN */ + + /* We send out the TCP Maximum Segment Size option with our + SYNACK. */ + BUF->optdata[0] = TCP_OPT_MSS; + BUF->optdata[1] = TCP_OPT_MSS_LEN; + BUF->optdata[2] = (UIP_TCP_MSS) / 256; + BUF->optdata[3] = (UIP_TCP_MSS) & 255; + uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; + BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; + goto tcp_send; + + /* This label will be jumped to if we found an active connection. */ + found: + uip_conn = uip_connr; + uip_flags = 0; + /* We do a very naive form of TCP reset processing; we just accept + any RST and kill our connection. We should in fact check if the + sequence number of this reset is wihtin our advertised window + before we accept the reset. */ + if(BUF->flags & TCP_RST) { + uip_connr->tcpstateflags = UIP_CLOSED; + UIP_LOG("tcp: got reset, aborting connection."); + uip_flags = UIP_ABORT; + UIP_APPCALL(); + goto drop; + } + /* Calculated the length of the data, if the application has sent + any data to us. */ + c = (BUF->tcpoffset >> 4) << 2; + /* uip_len will contain the length of the actual TCP data. This is + calculated by subtracing the length of the TCP header (in + c) and the length of the IP header (20 bytes). */ + uip_len = uip_len - c - UIP_IPH_LEN; + + /* First, check if the sequence number of the incoming packet is + what we're expecting next. If not, we send out an ACK with the + correct numbers in. */ + if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && + ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) { + if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) && + (BUF->seqno[0] != uip_connr->rcv_nxt[0] || + BUF->seqno[1] != uip_connr->rcv_nxt[1] || + BUF->seqno[2] != uip_connr->rcv_nxt[2] || + BUF->seqno[3] != uip_connr->rcv_nxt[3])) { + goto tcp_send_ack; + } + } + + /* Next, check if the incoming segment acknowledges any outstanding + data. If so, we update the sequence number, reset the length of + the outstanding data, calculate RTT estimations, and reset the + retransmission timer. */ + if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) { + uip_add32(uip_connr->snd_nxt, uip_connr->len); + + if(BUF->ackno[0] == uip_acc32[0] && + BUF->ackno[1] == uip_acc32[1] && + BUF->ackno[2] == uip_acc32[2] && + BUF->ackno[3] == uip_acc32[3]) { + /* Update sequence number. */ + uip_connr->snd_nxt[0] = uip_acc32[0]; + uip_connr->snd_nxt[1] = uip_acc32[1]; + uip_connr->snd_nxt[2] = uip_acc32[2]; + uip_connr->snd_nxt[3] = uip_acc32[3]; + + + /* Do RTT estimation, unless we have done retransmissions. */ + if(uip_connr->nrtx == 0) { + signed char m; + m = uip_connr->rto - uip_connr->timer; + /* This is taken directly from VJs original code in his paper */ + m = m - (uip_connr->sa >> 3); + uip_connr->sa += m; + if(m < 0) { + m = -m; + } + m = m - (uip_connr->sv >> 2); + uip_connr->sv += m; + uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv; + + } + /* Set the acknowledged flag. */ + uip_flags = UIP_ACKDATA; + /* Reset the retransmission timer. */ + uip_connr->timer = uip_connr->rto; + + /* Reset length of outstanding data. */ + uip_connr->len = 0; + } + + } + + /* Do different things depending on in what state the connection is. */ + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not + implemented, since we force the application to close when the + peer sends a FIN (hence the application goes directly from + ESTABLISHED to LAST_ACK). */ + case UIP_SYN_RCVD: + /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and + we are waiting for an ACK that acknowledges the data we sent + out the last time. Therefore, we want to have the UIP_ACKDATA + flag set. If so, we enter the ESTABLISHED state. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_flags = UIP_CONNECTED; + uip_connr->len = 0; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + goto drop; +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In SYN_SENT, we wait for a SYNACK that is sent in response to + our SYN. The rcv_nxt is set to sequence number in the SYNACK + plus one, and we send an ACK. We move into the ESTABLISHED + state. */ + if((uip_flags & UIP_ACKDATA) && + (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = + uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_add_rcv_nxt(1); + uip_flags = UIP_CONNECTED | UIP_NEWDATA; + uip_connr->len = 0; + uip_len = 0; + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + /* Inform the application that the connection failed */ + uip_flags = UIP_ABORT; + UIP_APPCALL(); + /* The connection is closed after we send the RST */ + uip_conn->tcpstateflags = UIP_CLOSED; + goto reset; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application to feed + data into the uip_buf. If the UIP_ACKDATA flag is set, the + application should put new data into the buffer, otherwise we are + retransmitting an old segment, and the application should put that + data into the buffer. + + If the incoming packet is a FIN, we should close the connection on + this side as well, and we send out a FIN and enter the LAST_ACK + state. We require that there is no outstanding data; otherwise the + sequence numbers will be screwed up. */ + + if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + if(uip_outstanding(uip_connr)) { + goto drop; + } + uip_add_rcv_nxt(1 + uip_len); + uip_flags |= UIP_CLOSE; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + } + UIP_APPCALL(); + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_LAST_ACK; + uip_connr->nrtx = 0; + tcp_send_finack: + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* Check the URG flag. If this is set, the segment carries urgent + data that we must pass to the application. */ + if((BUF->flags & TCP_URG) != 0) { +#if UIP_URGDATA > 0 + uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1]; + if(uip_urglen > uip_len) { + /* There is more urgent data in the next segment to come. */ + uip_urglen = uip_len; + } + uip_add_rcv_nxt(uip_urglen); + uip_len -= uip_urglen; + uip_urgdata = uip_appdata; + uip_appdata += uip_urglen; + } else { + uip_urglen = 0; +#else /* UIP_URGDATA > 0 */ + uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]); + uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1]; +#endif /* UIP_URGDATA > 0 */ + } + + /* If uip_len > 0 we have TCP data in the packet, and we flag this + by setting the UIP_NEWDATA flag and update the sequence number + we acknowledge. If the application has stopped the dataflow + using uip_stop(), we must not accept any data packets from the + remote host. */ + if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + + /* Check if the available buffer space advertised by the other end + is smaller than the initial MSS for this connection. If so, we + set the current MSS to the window size to ensure that the + application does not send more data than the other end can + handle. + + If the remote host advertises a zero window, we set the MSS to + the initial MSS so that the application will send an entire MSS + of data. This data will not be acknowledged by the receiver, + and the application will retransmit it. This is called the + "persistent timer" and uses the retransmission mechanim. + */ + tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1]; + if(tmp16 > uip_connr->initialmss || + tmp16 == 0) { + tmp16 = uip_connr->initialmss; + } + uip_connr->mss = tmp16; + + /* If this packet constitutes an ACK for outstanding data (flagged + by the UIP_ACKDATA flag, we should call the application since it + might want to send more data. If the incoming packet had data + from the peer (as flagged by the UIP_NEWDATA flag), the + application must also be notified. + + When the application is called, the global variable uip_len + contains the length of the incoming data. The application can + access the incoming data through the global pointer + uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN + bytes into the uip_buf array. + + If the application wishes to send any data, this data should be + put into the uip_appdata and the length of the data should be + put into uip_len. If the application don't have any data to + send, uip_len must be set to 0. */ + if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) { + uip_slen = 0; + UIP_APPCALL(); + + appsend: + + if(uip_flags & UIP_ABORT) { + uip_slen = 0; + uip_connr->tcpstateflags = UIP_CLOSED; + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + if(uip_flags & UIP_CLOSE) { + uip_slen = 0; + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_FIN_WAIT_1; + uip_connr->nrtx = 0; + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* If uip_slen > 0, the application has data to be sent. */ + if(uip_slen > 0) { + + /* If the connection has acknowledged data, the contents of + the ->len variable should be discarded. */ + if((uip_flags & UIP_ACKDATA) != 0) { + uip_connr->len = 0; + } + + /* If the ->len variable is non-zero the connection has + already data in transit and cannot send anymore right + now. */ + if(uip_connr->len == 0) { + + /* The application cannot send more than what is allowed by + the mss (the minumum of the MSS and the available + window). */ + if(uip_slen > uip_connr->mss) { + uip_slen = uip_connr->mss; + } + + /* Remember how much data we send out now so that we know + when everything has been acknowledged. */ + uip_connr->len = uip_slen; + } else { + + /* If the application already had unacknowledged data, we + make sure that the application does not send (i.e., + retransmit) out more than it previously sent out. */ + uip_slen = uip_connr->len; + } + } + uip_connr->nrtx = 0; + apprexmit: + uip_appdata = uip_sappdata; + + /* If the application has data to be sent, or if the incoming + packet had new data in it, we must send out a packet. */ + if(uip_slen > 0 && uip_connr->len > 0) { + /* Add the length of the IP and TCP headers. */ + uip_len = uip_connr->len + UIP_TCPIP_HLEN; + /* We always set the ACK flag in response packets. */ + BUF->flags = TCP_ACK | TCP_PSH; + /* Send the packet. */ + goto tcp_send_noopts; + } + /* If there is no data to send, just send out a pure ACK if + there is newdata. */ + if(uip_flags & UIP_NEWDATA) { + uip_len = UIP_TCPIP_HLEN; + BUF->flags = TCP_ACK; + goto tcp_send_noopts; + } + } + goto drop; + case UIP_LAST_ACK: + /* We can close this connection if the peer has acknowledged our + FIN. This is indicated by the UIP_ACKDATA flag. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_CLOSED; + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + } + break; + + case UIP_FIN_WAIT_1: + /* The application has closed the connection, but the remote host + hasn't closed its end yet. Thus we do nothing but wait for a + FIN from the other side. */ + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_connr->len = 0; + } else { + uip_connr->tcpstateflags = UIP_CLOSING; + } + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } else if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_FIN_WAIT_2; + uip_connr->len = 0; + goto drop; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_FIN_WAIT_2: + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_TIME_WAIT: + goto tcp_send_ack; + + case UIP_CLOSING: + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + } + } + goto drop; + + + /* We jump here when we are ready to send the packet, and just want + to set the appropriate TCP sequence numbers in the TCP header. */ + tcp_send_ack: + BUF->flags = TCP_ACK; + tcp_send_nodata: + uip_len = UIP_IPTCPH_LEN; + tcp_send_noopts: + BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; + tcp_send: + /* We're done with the input processing. We are now ready to send a + reply. Our job is to fill in all the fields of the TCP and IP + headers before calculating the checksum and finally send the + packet. */ + BUF->ackno[0] = uip_connr->rcv_nxt[0]; + BUF->ackno[1] = uip_connr->rcv_nxt[1]; + BUF->ackno[2] = uip_connr->rcv_nxt[2]; + BUF->ackno[3] = uip_connr->rcv_nxt[3]; + + BUF->seqno[0] = uip_connr->snd_nxt[0]; + BUF->seqno[1] = uip_connr->snd_nxt[1]; + BUF->seqno[2] = uip_connr->snd_nxt[2]; + BUF->seqno[3] = uip_connr->snd_nxt[3]; + + BUF->proto = UIP_PROTO_TCP; + + BUF->srcport = uip_connr->lport; + BUF->destport = uip_connr->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr); + + if(uip_connr->tcpstateflags & UIP_STOPPED) { + /* If the connection has issued uip_stop(), we advertise a zero + window so that the remote host will stop sending data. */ + BUF->wnd[0] = BUF->wnd[1] = 0; + } else { + BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); + BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); + } + + tcp_send_noconn: + BUF->ttl = UIP_TTL; +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->urgp[0] = BUF->urgp[1] = 0; + + /* Calculate TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + + ip_send_nolen: + +#if UIP_CONF_IPV6 + BUF->vtc = 0x60; + BUF->tcflow = 0x00; + BUF->flow = 0x00; +#else /* UIP_CONF_IPV6 */ + BUF->vhl = 0x45; + BUF->tos = 0; + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + ++ipid; + BUF->ipid[0] = ipid >> 8; + BUF->ipid[1] = ipid & 0xff; + /* Calculate IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum()); +#endif /* UIP_CONF_IPV6 */ + + UIP_STAT(++uip_stat.tcp.sent); + send: + DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len, + (BUF->len[0] << 8) | BUF->len[1]); + + UIP_STAT(++uip_stat.ip.sent); + /* Return and let the caller do the actual transmission. */ + uip_flags = 0; + return; + drop: + uip_len = 0; + uip_flags = 0; + return; +} +/*---------------------------------------------------------------------------*/ +u16_t +htons(u16_t val) +{ + return HTONS(val); +} +/*---------------------------------------------------------------------------*/ +void +uip_send(const void *data, int len) +{ + if(len > 0) { + uip_slen = len; + if(data != uip_sappdata) { + memcpy(uip_sappdata, (data), uip_slen); + } + } +} +/** @} */ diff --git a/uip/uip/uip.h b/uip/uip/uip.h new file mode 100644 index 0000000..2fed1f6 --- /dev/null +++ b/uip/uip/uip.h @@ -0,0 +1,1603 @@ + +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * Header file for the uIP TCP/IP stack. + * \author Adam Dunkels + * + * The uIP TCP/IP stack header file contains definitions for a number + * of C macros that are used by uIP programs as well as internal uIP + * structures, TCP/IP header structures and function declarations. + * + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.h,v 1.40 2006/06/08 07:12:07 adam Exp $ + * + */ + +#ifndef __UIP_H__ +#define __UIP_H__ + +#include "uipopt.h" + +/** + * Repressentation of an IP address. + * + */ +typedef u16_t uip_ip4addr_t[2]; +typedef u16_t uip_ip6addr_t[8]; +#if UIP_CONF_IPV6 +typedef uip_ip6addr_t uip_ipaddr_t; +#else /* UIP_CONF_IPV6 */ +typedef uip_ip4addr_t uip_ipaddr_t; +#endif /* UIP_CONF_IPV6 */ + +/*---------------------------------------------------------------------------*/ +/* First, the functions that should be called from the + * system. Initialization, the periodic timer and incoming packets are + * handled by the following three functions. + */ + +/** + * \defgroup uipconffunc uIP configuration functions + * @{ + * + * The uIP configuration functions are used for setting run-time + * parameters in uIP such as IP addresses. + */ + +/** + * Set the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + + uip_ipaddr_t addr; + + uip_ipaddr(&addr, 192,168,1,2); + uip_sethostaddr(&addr); + + \endcode + * \param addr A pointer to an IP address of type uip_ipaddr_t; + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_sethostaddr(addr) uip_ipaddr_copy(uip_hostaddr, (addr)) + +/** + * Get the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + uip_ipaddr_t hostaddr; + + uip_gethostaddr(&hostaddr); + \endcode + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the currently configured IP address. + * + * \hideinitializer + */ +#define uip_gethostaddr(addr) uip_ipaddr_copy((addr), uip_hostaddr) + +/** + * Set the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the default router. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setdraddr(addr) uip_ipaddr_copy(uip_draddr, (addr)) + +/** + * Set the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the netmask. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setnetmask(addr) uip_ipaddr_copy(uip_netmask, (addr)) + + +/** + * Get the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address of the default router. + * + * \hideinitializer + */ +#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr) + +/** + * Get the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the value of the netmask. + * + * \hideinitializer + */ +#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask) + +/** @} */ + +/** + * \defgroup uipinit uIP initialization functions + * @{ + * + * The uIP initialization functions are used for booting uIP. + */ + +/** + * uIP initialization function. + * + * This function should be called at boot up to initilize the uIP + * TCP/IP stack. + */ +void uip_init(void); + +/** + * uIP initialization function. + * + * This function may be used at boot time to set the initial ip_id. + */ +void uip_setipid(u16_t id); + +/** @} */ + +/** + * \defgroup uipdevfunc uIP device driver functions + * @{ + * + * These functions are used by a network device driver for interacting + * with uIP. + */ + +/** + * Process an incoming packet. + * + * This function should be called when the device driver has received + * a packet from the network. The packet from the device driver must + * be present in the uip_buf buffer, and the length of the packet + * should be placed in the uip_len variable. + * + * When the function returns, there may be an outbound packet placed + * in the uip_buf packet buffer. If so, the uip_len variable is set to + * the length of the packet. If no packet is to be sent out, the + * uip_len variable is set to 0. + * + * The usual way of calling the function is presented by the source + * code below. + \code + uip_len = devicedriver_poll(); + if(uip_len > 0) { + uip_input(); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uIP ARP code before calling + * this function: + \code + #define BUF ((struct uip_eth_hdr *)&uip_buf[0]) + uip_len = ethernet_devicedrver_poll(); + if(uip_len > 0) { + if(BUF->type == HTONS(UIP_ETHTYPE_IP)) { + uip_arp_ipin(); + uip_input(); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + if(uip_len > 0) { + ethernet_devicedriver_send(); + } + } + \endcode + * + * \hideinitializer + */ +#define uip_input() uip_process(UIP_DATA) + +/** + * Periodic processing for a connection identified by its number. + * + * This function does the necessary periodic processing (timers, + * polling) for a uIP TCP conneciton, and should be called when the + * periodic uIP timer goes off. It should be called for every + * connection, regardless of whether they are open of closed. + * + * When the function returns, it may have an outbound packet waiting + * for service in the uIP packet buffer, and if so the uip_len + * variable is set to a value larger than zero. The device driver + * should be called to send out the packet. + * + * The ususal way of calling the function is through a for() loop like + * this: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uip_arp_out() function before + * calling the device driver: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the connection which is to be periodically polled. + * + * \hideinitializer + */ +#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \ + uip_process(UIP_TIMER); } while (0) + +/** + * + * + */ +#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED) + +/** + * Perform periodic processing for a connection identified by a pointer + * to its structure. + * + * Same as uip_periodic() but takes a pointer to the actual uip_conn + * struct instead of an integer as its argument. This function can be + * used to force periodic processing of a specific connection. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_periodic_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_TIMER); } while (0) + +/** + * Reuqest that a particular connection should be polled. + * + * Similar to uip_periodic_conn() but does not perform any timer + * processing. The application is polled for new data. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_poll_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_POLL_REQUEST); } while (0) + + +#if UIP_UDP +/** + * Periodic processing for a UDP connection identified by its number. + * + * This function is essentially the same as uip_periodic(), but for + * UDP connections. It is called in a similar fashion as the + * uip_periodic() function: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note As for the uip_periodic() function, special care has to be + * taken when using uIP together with ARP and Ethernet: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the UDP connection to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \ + uip_process(UIP_UDP_TIMER); } while (0) + +/** + * Periodic processing for a UDP connection identified by a pointer to + * its structure. + * + * Same as uip_udp_periodic() but takes a pointer to the actual + * uip_conn struct instead of an integer as its argument. This + * function can be used to force periodic processing of a specific + * connection. + * + * \param conn A pointer to the uip_udp_conn struct for the connection + * to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \ + uip_process(UIP_UDP_TIMER); } while (0) + + +#endif /* UIP_UDP */ + +/** + * The uIP packet buffer. + * + * The uip_buf array is used to hold incoming and outgoing + * packets. The device driver should place incoming data into this + * buffer. When sending data, the device driver should read the link + * level headers and the TCP/IP headers from this buffer. The size of + * the link level headers is configured by the UIP_LLH_LEN define. + * + * \note The application data need not be placed in this buffer, so + * the device driver must read it from the place pointed to by the + * uip_appdata pointer as illustrated by the following example: + \code + void + devicedriver_send(void) + { + hwsend(&uip_buf[0], UIP_LLH_LEN); + if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) { + hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN); + } else { + hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN); + hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN); + } + } + \endcode + */ +extern u8_t uip_buf[UIP_BUFSIZE+2]; + +/** @} */ + +/*---------------------------------------------------------------------------*/ +/* Functions that are used by the uIP application program. Opening and + * closing connections, sending and receiving data, etc. is all + * handled by the functions below. +*/ +/** + * \defgroup uipappfunc uIP application functions + * @{ + * + * Functions used by an application running of top of uIP. + */ + +#ifdef UIP_TCP_LISTEN +/** + * Start listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_listen(HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_listen(u16_t port); + +/** + * Stop listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_unlisten(HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_unlisten(u16_t port); +#endif + +/** + * Connect to a remote host using TCP. + * + * This function is used to start a new connection to the specified + * port on the specied host. It allocates a new connection identifier, + * sets the connection to the SYN_SENT state and sets the + * retransmission timer to 0. This will cause a TCP SYN segment to be + * sent out the next time this connection is periodically processed, + * which usually is done within 0.5 seconds after the call to + * uip_connect(). + * + * \note This function is avaliable only if support for active open + * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h. + * + * \note Since this function requires the port number to be in network + * byte order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_ipaddr_t ipaddr; + + uip_ipaddr(&ipaddr, 192,168,1,2); + uip_connect(&ipaddr, HTONS(80)); + \endcode + * + * \param ripaddr The IP address of the remote hot. + * + * \param port A 16-bit port number in network byte order. + * + * \return A pointer to the uIP connection identifier for the new connection, + * or NULL if no connection could be allocated. + * + */ +struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, u16_t port); + + + +/** + * \internal + * + * Check if a connection has outstanding (i.e., unacknowledged) data. + * + * \param conn A pointer to the uip_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_outstanding(conn) ((conn)->len) + +/** + * Send data on the current connection. + * + * This function is used to send out a single segment of TCP + * data. Only applications that have been invoked by uIP for event + * processing can send data. + * + * The amount of data that actually is sent out after a call to this + * funcion is determined by the maximum amount of data TCP allows. uIP + * will automatically crop the data so that only the appropriate + * amount of data is sent. The function uip_mss() can be used to query + * uIP for the amount of data that actually will be sent. + * + * \note This function does not guarantee that the sent data will + * arrive at the destination. If the data is lost in the network, the + * application will be invoked with the uip_rexmit() event being + * set. The application will then have to resend the data using this + * function. + * + * \param data A pointer to the data which is to be sent. + * + * \param len The maximum amount of data bytes to be sent. + * + * \hideinitializer + */ +void uip_send(const void *data, int len); + +/** + * The length of any incoming data that is currently avaliable (if avaliable) + * in the uip_appdata buffer. + * + * The test function uip_data() must first be used to check if there + * is any data available at all. + * + * \hideinitializer + */ +/*void uip_datalen(void);*/ +#define uip_datalen() uip_len + +/** + * The length of any out-of-band data (urgent data) that has arrived + * on the connection. + * + * \note The configuration parameter UIP_URGDATA must be set for this + * function to be enabled. + * + * \hideinitializer + */ +#define uip_urgdatalen() uip_urglen + +/** + * Close the current connection. + * + * This function will close the current connection in a nice way. + * + * \hideinitializer + */ +#define uip_close() (uip_flags = UIP_CLOSE) + +/** + * Abort the current connection. + * + * This function will abort (reset) the current connection, and is + * usually used when an error has occured that prevents using the + * uip_close() function. + * + * \hideinitializer + */ +#define uip_abort() (uip_flags = UIP_ABORT) + +/** + * Tell the sending host to stop sending data. + * + * This function will close our receiver's window so that we stop + * receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED) + +/** + * Find out if the current connection has been previously stopped with + * uip_stop(). + * + * \hideinitializer + */ +#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED) + +/** + * Restart the current connection, if is has previously been stopped + * with uip_stop(). + * + * This function will open the receiver's window again so that we + * start receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_restart() do { uip_flags |= UIP_NEWDATA; \ + uip_conn->tcpstateflags &= ~UIP_STOPPED; \ + } while(0) + + +/* uIP tests that can be made to determine in what state the current + connection is, and what the application function should do. */ + +/** + * Is the current connection a UDP connection? + * + * This function checks whether the current connection is a UDP connection. + * + * \hideinitializer + * + */ +#define uip_udpconnection() (uip_conn == NULL) + +/** + * Is new incoming data available? + * + * Will reduce to non-zero if there is new data for the application + * present at the uip_appdata pointer. The size of the data is + * avaliable through the uip_len variable. + * + * \hideinitializer + */ +#define uip_newdata() (uip_flags & UIP_NEWDATA) + +/** + * Has previously sent data been acknowledged? + * + * Will reduce to non-zero if the previously sent data has been + * acknowledged by the remote host. This means that the application + * can send new data. + * + * \hideinitializer + */ +#define uip_acked() (uip_flags & UIP_ACKDATA) + +/** + * Has the connection just been connected? + * + * Reduces to non-zero if the current connection has been connected to + * a remote host. This will happen both if the connection has been + * actively opened (with uip_connect()) or passively opened (with + * uip_listen()). + * + * \hideinitializer + */ +#define uip_connected() (uip_flags & UIP_CONNECTED) + +/** + * Has the connection been closed by the other end? + * + * Is non-zero if the connection has been closed by the remote + * host. The application may then do the necessary clean-ups. + * + * \hideinitializer + */ +#define uip_closed() (uip_flags & UIP_CLOSE) + +/** + * Has the connection been aborted by the other end? + * + * Non-zero if the current connection has been aborted (reset) by the + * remote host. + * + * \hideinitializer + */ +#define uip_aborted() (uip_flags & UIP_ABORT) + +/** + * Has the connection timed out? + * + * Non-zero if the current connection has been aborted due to too many + * retransmissions. + * + * \hideinitializer + */ +#define uip_timedout() (uip_flags & UIP_TIMEDOUT) + +/** + * Do we need to retransmit previously data? + * + * Reduces to non-zero if the previously sent data has been lost in + * the network, and the application should retransmit it. The + * application should send the exact same data as it did the last + * time, using the uip_send() function. + * + * \hideinitializer + */ +#define uip_rexmit() (uip_flags & UIP_REXMIT) + +/** + * Is the connection being polled by uIP? + * + * Is non-zero if the reason the application is invoked is that the + * current connection has been idle for a while and should be + * polled. + * + * The polling event can be used for sending data without having to + * wait for the remote host to send data. + * + * \hideinitializer + */ +#define uip_poll() (uip_flags & UIP_POLL) + +/** + * Get the initial maxium segment size (MSS) of the current + * connection. + * + * \hideinitializer + */ +#define uip_initialmss() (uip_conn->initialmss) + +/** + * Get the current maxium segment size that can be sent on the current + * connection. + * + * The current maxiumum segment size that can be sent on the + * connection is computed from the receiver's window and the MSS of + * the connection (which also is available by calling + * uip_initialmss()). + * + * \hideinitializer + */ +#define uip_mss() (uip_conn->mss) + +/** + * Set up a new UDP connection. + * + * This function sets up a new UDP connection. The function will + * automatically allocate an unused local port for the new + * connection. However, another port can be chosen by using the + * uip_udp_bind() call, after the uip_udp_new() function has been + * called. + * + * Example: + \code + uip_ipaddr_t addr; + struct uip_udp_conn *c; + + uip_ipaddr(&addr, 192,168,2,1); + c = uip_udp_new(&addr, HTONS(12345)); + if(c != NULL) { + uip_udp_bind(c, HTONS(12344)); + } + \endcode + * \param ripaddr The IP address of the remote host. + * + * \param rport The remote port number in network byte order. + * + * \return The uip_udp_conn structure for the new connection or NULL + * if no connection could be allocated. + */ +struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport); + +/** + * Removed a UDP connection. + * + * \param conn A pointer to the uip_udp_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_udp_remove(conn) (conn)->lport = 0 + +/** + * Bind a UDP connection to a local port. + * + * \param conn A pointer to the uip_udp_conn structure for the + * connection. + * + * \param port The local port number, in network byte order. + * + * \hideinitializer + */ +#define uip_udp_bind(conn, port) (conn)->lport = port + +/** + * Send a UDP datagram of length len on the current connection. + * + * This function can only be called in response to a UDP event (poll + * or newdata). The data must be present in the uip_buf buffer, at the + * place pointed to by the uip_appdata pointer. + * + * \param len The length of the data in the uip_buf buffer. + * + * \hideinitializer + */ +#define uip_udp_send(len) uip_send((char *)uip_appdata, len) + +/** @} */ + +/* uIP convenience and converting functions. */ + +/** + * \defgroup uipconvfunc uIP conversion functions + * @{ + * + * These functions can be used for converting between different data + * formats used by uIP. + */ + +/** + * Construct an IP address from four bytes. + * + * This function constructs an IP address of the type that uIP handles + * internally from four bytes. The function is handy for specifying IP + * addresses to use with e.g. the uip_connect() function. + * + * Example: + \code + uip_ipaddr_t ipaddr; + struct uip_conn *c; + + uip_ipaddr(&ipaddr, 192,168,1,2); + c = uip_connect(&ipaddr, HTONS(80)); + \endcode + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address. + * + * \param addr0 The first octet of the IP address. + * \param addr1 The second octet of the IP address. + * \param addr2 The third octet of the IP address. + * \param addr3 The forth octet of the IP address. + * + * \hideinitializer + */ +#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \ + ((u16_t *)(addr))[0] = HTONS(((addr0) << 8) | (addr1)); \ + ((u16_t *)(addr))[1] = HTONS(((addr2) << 8) | (addr3)); \ + } while(0) + +/** + * Construct an IPv6 address from eight 16-bit words. + * + * This function constructs an IPv6 address. + * + * \hideinitializer + */ +#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \ + ((u16_t *)(addr))[0] = HTONS((addr0)); \ + ((u16_t *)(addr))[1] = HTONS((addr1)); \ + ((u16_t *)(addr))[2] = HTONS((addr2)); \ + ((u16_t *)(addr))[3] = HTONS((addr3)); \ + ((u16_t *)(addr))[4] = HTONS((addr4)); \ + ((u16_t *)(addr))[5] = HTONS((addr5)); \ + ((u16_t *)(addr))[6] = HTONS((addr6)); \ + ((u16_t *)(addr))[7] = HTONS((addr7)); \ + } while(0) + +/** + * Copy an IP address to another IP address. + * + * Copies an IP address from one place to another. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr_copy(&ipaddr2, &ipaddr1); + \endcode + * + * \param dest The destination for the copy. + * \param src The source from where to copy. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_copy(dest, src) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1]; \ + } while(0) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t)) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses + * + * Compares two IP addresses. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_cmp(addr1, addr2) (((u16_t *)addr1)[0] == ((u16_t *)addr2)[0] && \ + ((u16_t *)addr1)[1] == ((u16_t *)addr2)[1]) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses with netmasks + * + * Compares two IP addresses with netmasks. The masks are used to mask + * out the bits that are to be compared. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, mask; + + uip_ipaddr(&mask, 255,255,255,0); + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&ipaddr2, 192,16,1,3); + if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_maskcmp(addr1, addr2, mask) \ + (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \ + (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \ + ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \ + (((u16_t *)addr2)[1] & ((u16_t *)mask)[1]))) + + +/** + * Mask out the network part of an IP address. + * + * Masks out the network part of an IP address, given the address and + * the netmask. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, netmask; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&netmask, 255,255,255,0); + uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask); + \endcode + * + * In the example above, the variable "ipaddr2" will contain the IP + * address 192.168.1.0. + * + * \param dest Where the result is to be placed. + * \param src The IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_mask(dest, src, mask) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \ + } while(0) + +/** + * Pick the first octet of an IP address. + * + * Picks out the first octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr1(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 1. + * + * \hideinitializer + */ +#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8) + +/** + * Pick the second octet of an IP address. + * + * Picks out the second octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr2(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 2. + * + * \hideinitializer + */ +#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff) + +/** + * Pick the third octet of an IP address. + * + * Picks out the third octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr3(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 3. + * + * \hideinitializer + */ +#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8) + +/** + * Pick the fourth octet of an IP address. + * + * Picks out the fourth octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr4(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 4. + * + * \hideinitializer + */ +#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff) + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This macro is primarily used for converting constants from host + * byte order to network byte order. For converting variables to + * network byte order, use the htons() function instead. + * + * \hideinitializer + */ +#ifndef HTONS +# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN +# define HTONS(n) (n) +# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8)) +# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +#else +#error "HTONS already defined!" +#endif /* HTONS */ + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This function is primarily used for converting variables from host + * byte order to network byte order. For converting constants to + * network byte order, use the HTONS() macro instead. + */ +#ifndef htons +u16_t htons(u16_t val); +#endif /* htons */ +#ifndef ntohs +#define ntohs htons +#endif + +/** @} */ + +/** + * Pointer to the application data in the packet buffer. + * + * This pointer points to the application data when the application is + * called. If the application wishes to send data, the application may + * use this space to write the data into before calling uip_send(). + */ +extern void *uip_appdata; + +#if UIP_URGDATA > 0 +/* u8_t *uip_urgdata: + * + * This pointer points to any urgent data that has been received. Only + * present if compiled with support for urgent data (UIP_URGDATA). + */ +extern void *uip_urgdata; +#endif /* UIP_URGDATA > 0 */ + + +/** + * \defgroup uipdrivervars Variables used in uIP device drivers + * @{ + * + * uIP has a few global variables that are used in device drivers for + * uIP. + */ + +/** + * The length of the packet in the uip_buf buffer. + * + * The global variable uip_len holds the length of the packet in the + * uip_buf buffer. + * + * When the network device driver calls the uIP input function, + * uip_len should be set to the length of the packet in the uip_buf + * buffer. + * + * When sending packets, the device driver should use the contents of + * the uip_len variable to determine the length of the outgoing + * packet. + * + */ +extern u16_t uip_len; + +/** @} */ + +#if UIP_URGDATA > 0 +extern u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + + +/** + * Representation of a uIP TCP connection. + * + * The uip_conn structure is used for identifying a connection. All + * but one field in the structure are to be considered read-only by an + * application. The only exception is the appstate field whos purpose + * is to let the application store application-specific state (e.g., + * file pointers) for the connection. The type of this field is + * configured in the "uipopt.h" header file. + */ +struct uip_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */ + + u16_t lport; /**< The local TCP port, in network byte order. */ + u16_t rport; /**< The local remote TCP port, in network byte + order. */ + + u8_t rcv_nxt[4]; /**< The sequence number that we expect to + receive next. */ + u8_t snd_nxt[4]; /**< The sequence number that was last sent by + us. */ + u16_t len; /**< Length of the data that was previously sent. */ + u16_t mss; /**< Current maximum segment size for the + connection. */ + u16_t initialmss; /**< Initial maximum segment size for the + connection. */ + u8_t sa; /**< Retransmission time-out calculation state + variable. */ + u8_t sv; /**< Retransmission time-out calculation state + variable. */ + u8_t rto; /**< Retransmission time-out. */ + u8_t tcpstateflags; /**< TCP state and flags. */ + u8_t timer; /**< The retransmission timer. */ + u8_t nrtx; /**< The number of retransmissions for the last + segment sent. */ + + /** The application state. */ + uip_tcp_appstate_t appstate; +}; + + +/** + * Pointer to the current TCP connection. + * + * The uip_conn pointer can be used to access the current TCP + * connection. + */ +extern struct uip_conn *uip_conn; +/* The array containing all uIP connections. */ +extern struct uip_conn uip_conns[UIP_CONNS]; +/** + * \addtogroup uiparch + * @{ + */ + +/** + * 4-byte array used for the 32-bit sequence number calculations. + */ +extern u8_t uip_acc32[4]; + +/** @} */ + + +#if UIP_UDP +/** + * Representation of a uIP UDP connection. + */ +struct uip_udp_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote peer. */ + u16_t lport; /**< The local port number in network byte order. */ + u16_t rport; /**< The remote port number in network byte order. */ + u8_t ttl; /**< Default time-to-live. */ + + /** The application state. */ + uip_udp_appstate_t appstate; +}; + +/** + * The current UDP connection. + */ +extern struct uip_udp_conn *uip_udp_conn; +extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +/** + * The structure holding the TCP/IP statistics that are gathered if + * UIP_STATISTICS is set to 1. + * + */ +struct uip_stats { + struct { + uip_stats_t drop; /**< Number of dropped packets at the IP + layer. */ + uip_stats_t recv; /**< Number of received packets at the IP + layer. */ + uip_stats_t sent; /**< Number of sent packets at the IP + layer. */ + uip_stats_t vhlerr; /**< Number of packets dropped due to wrong + IP version or header length. */ + uip_stats_t hblenerr; /**< Number of packets dropped due to wrong + IP length, high byte. */ + uip_stats_t lblenerr; /**< Number of packets dropped due to wrong + IP length, low byte. */ + uip_stats_t fragerr; /**< Number of packets dropped since they + were IP fragments. */ + uip_stats_t chkerr; /**< Number of packets dropped due to IP + checksum errors. */ + uip_stats_t protoerr; /**< Number of packets dropped since they + were neither ICMP, UDP nor TCP. */ + } ip; /**< IP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped ICMP packets. */ + uip_stats_t recv; /**< Number of received ICMP packets. */ + uip_stats_t sent; /**< Number of sent ICMP packets. */ + uip_stats_t typeerr; /**< Number of ICMP packets with a wrong + type. */ + } icmp; /**< ICMP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped TCP segments. */ + uip_stats_t recv; /**< Number of recived TCP segments. */ + uip_stats_t sent; /**< Number of sent TCP segments. */ + uip_stats_t chkerr; /**< Number of TCP segments with a bad + checksum. */ + uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK + number. */ + uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */ + uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */ + uip_stats_t syndrop; /**< Number of dropped SYNs due to too few + connections was avaliable. */ + uip_stats_t synrst; /**< Number of SYNs for closed ports, + triggering a RST. */ + } tcp; /**< TCP statistics. */ +#if UIP_UDP + struct { + uip_stats_t drop; /**< Number of dropped UDP segments. */ + uip_stats_t recv; /**< Number of recived UDP segments. */ + uip_stats_t sent; /**< Number of sent UDP segments. */ + uip_stats_t chkerr; /**< Number of UDP segments with a bad + checksum. */ + } udp; /**< UDP statistics. */ +#endif /* UIP_UDP */ +}; + +/** + * The uIP TCP/IP statistics. + * + * This is the variable in which the uIP TCP/IP statistics are gathered. + */ +extern struct uip_stats uip_stat; + + +/*---------------------------------------------------------------------------*/ +/* All the stuff below this point is internal to uIP and should not be + * used directly by an application or by a device driver. + */ +/*---------------------------------------------------------------------------*/ +/* u8_t uip_flags: + * + * When the application is called, uip_flags will contain the flags + * that are defined in this file. Please read below for more + * infomation. + */ +extern u8_t uip_flags; + +/* The following flags may be set in the global variable uip_flags + before calling the application callback. The UIP_ACKDATA, + UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time, + whereas the others are mutualy exclusive. Note that these flags + should *NOT* be accessed directly, but only through the uIP + functions/macros. */ + +#define UIP_ACKDATA 1 /* Signifies that the outstanding data was + acked and the application should send + out new data instead of retransmitting + the last data. */ +#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent + us new data. */ +#define UIP_REXMIT 4 /* Tells the application to retransmit the + data that was last sent. */ +#define UIP_POLL 8 /* Used for polling the application, to + check if the application has data that + it wants to send. */ +#define UIP_CLOSE 16 /* The remote host has closed the + connection, thus the connection has + gone away. Or the application signals + that it wants to close the + connection. */ +#define UIP_ABORT 32 /* The remote host has aborted the + connection, thus the connection has + gone away. Or the application signals + that it wants to abort the + connection. */ +#define UIP_CONNECTED 64 /* We have got a connection from a remote + host and have set up a new connection + for it, or an active connection has + been successfully established. */ + +#define UIP_TIMEDOUT 128 /* The connection has been aborted due to + too many retransmissions. */ + +/* uip_process(flag): + * + * The actual uIP function which does all the work. + */ +void uip_process(u8_t flag); + +/* The following flags are passed as an argument to the uip_process() + function. They are used to distinguish between the two cases where + uip_process() is called. It can be called either because we have + incoming data that should be processed, or because the periodic + timer has fired. These values are never used directly, but only in + the macrose defined in this file. */ + +#define UIP_DATA 1 /* Tells uIP that there is incoming + data in the uip_buf buffer. The + length of the data is stored in the + global variable uip_len. */ +#define UIP_TIMER 2 /* Tells uIP that the periodic timer + has fired. */ +#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should + be polled. */ +#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram + should be constructed in the + uip_buf buffer. */ +#if UIP_UDP +#define UIP_UDP_TIMER 5 +#endif /* UIP_UDP */ + +/* The TCP states used in the uip_conn->tcpstateflags. */ +#define UIP_CLOSED 0 +#define UIP_SYN_RCVD 1 +#define UIP_SYN_SENT 2 +#define UIP_ESTABLISHED 3 +#define UIP_FIN_WAIT_1 4 +#define UIP_FIN_WAIT_2 5 +#define UIP_CLOSING 6 +#define UIP_TIME_WAIT 7 +#define UIP_LAST_ACK 8 +#define UIP_TS_MASK 15 + +#define UIP_STOPPED 16 + +/* The TCP and IP headers. */ +struct uip_tcpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcflow; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* TCP header. */ + u16_t srcport, + destport; + u8_t seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + u16_t tcpchksum; + u8_t urgp[2]; + u8_t optdata[4]; +}; + +/* The ICMP and IP headers. */ +struct uip_icmpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* ICMP (echo) header. */ + u8_t type, icode; + u16_t icmpchksum; +#if !UIP_CONF_IPV6 + u16_t id, seqno; +#else /* !UIP_CONF_IPV6 */ + u8_t flags, reserved1, reserved2, reserved3; + u8_t icmp6data[16]; + u8_t options[1]; +#endif /* !UIP_CONF_IPV6 */ +}; + + +/* The UDP and IP headers. */ +struct uip_udpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* UDP header. */ + u16_t srcport, + destport; + u16_t udplen; + u16_t udpchksum; +}; + + + +/** + * The buffer size available for user data in the \ref uip_buf buffer. + * + * This macro holds the available size for user data in the \ref + * uip_buf buffer. The macro is intended to be used for checking + * bounds of available user data. + * + * Example: + \code + snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i); + \endcode + * + * \hideinitializer + */ +#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) + + +#define UIP_PROTO_ICMP 1 +#define UIP_PROTO_TCP 6 +#define UIP_PROTO_UDP 17 +#define UIP_PROTO_ICMP6 58 + +/* Header sizes. */ +#if UIP_CONF_IPV6 +#define UIP_IPH_LEN 40 +#else /* UIP_CONF_IPV6 */ +#define UIP_IPH_LEN 20 /* Size of IP header */ +#endif /* UIP_CONF_IPV6 */ +#define UIP_UDPH_LEN 8 /* Size of UDP header */ +#define UIP_TCPH_LEN 20 /* Size of TCP header */ +#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN) /* Size of IP + + UDP + header */ +#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN) /* Size of IP + + TCP + header */ +#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN + + +#if UIP_FIXEDADDR +extern const uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#else /* UIP_FIXEDADDR */ +extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#endif /* UIP_FIXEDADDR */ + + + +/** + * Representation of a 48-bit Ethernet address. + */ +struct uip_eth_addr { + u8_t addr[6]; +}; + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +/** + * Calculate the UDP checksum of the packet in uip_buf and uip_appdata. + * + * The UDP checksum is the Internet checksum of data contents of the + * UDP segment, and a pseudo-header as defined in RFC768. + * + * \return The UDP checksum of the UDP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_udpchksum(void); + + +#endif /* __UIP_H__ */ + + +/** @} */ diff --git a/uip/uip/uip_arch.h b/uip/uip/uip_arch.h new file mode 100644 index 0000000..71fd84b --- /dev/null +++ b/uip/uip/uip_arch.h @@ -0,0 +1,138 @@ +/** + * \addtogroup uip + * {@ + */ + +/** + * \defgroup uiparch Architecture specific uIP functions + * @{ + * + * The functions in the architecture specific module implement the IP + * check sum and 32-bit additions. + * + * The IP checksum calculation is the most computationally expensive + * operation in the TCP/IP stack and it therefore pays off to + * implement this in efficient assembler. The purpose of the uip-arch + * module is to let the checksum functions to be implemented in + * architecture specific assembler. + * + */ + +/** + * \file + * Declarations of architecture specific functions. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arch.h,v 1.2 2006/06/07 09:15:19 adam Exp $ + * + */ + +#ifndef __UIP_ARCH_H__ +#define __UIP_ARCH_H__ + +#include "uip.h" + +/** + * Carry out a 32-bit addition. + * + * Because not all architectures for which uIP is intended has native + * 32-bit arithmetic, uIP uses an external C function for doing the + * required 32-bit additions in the TCP protocol processing. This + * function should add the two arguments and place the result in the + * global variable uip_acc32. + * + * \note The 32-bit integer pointed to by the op32 parameter and the + * result in the uip_acc32 variable are in network byte order (big + * endian). + * + * \param op32 A pointer to a 4-byte array representing a 32-bit + * integer in network byte order (big endian). + * + * \param op16 A 16-bit integer in host byte order. + */ +void uip_add32(u8_t *op32, u16_t op16); + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \note This function is not called in the current version of uIP, + * but future versions might make use of it. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \note The uip_appdata pointer that points to the packet data may + * point anywhere in memory, so it is not possible to simply calculate + * the Internet checksum of the contents of the uip_buf buffer. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +u16_t uip_udpchksum(void); + +/** @} */ +/** @} */ + +#endif /* __UIP_ARCH_H__ */ diff --git a/uip/uip/uip_arp.c b/uip/uip/uip_arp.c new file mode 100644 index 0000000..75ade64 --- /dev/null +++ b/uip/uip/uip_arp.c @@ -0,0 +1,423 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uiparp uIP Address Resolution Protocol + * @{ + * + * The Address Resolution Protocol ARP is used for mapping between IP + * addresses and link level addresses such as the Ethernet MAC + * addresses. ARP uses broadcast queries to ask for the link level + * address of a known IP address and the host which is configured with + * the IP address for which the query was meant, will respond with its + * link level address. + * + * \note This ARP implementation only supports Ethernet. + */ + +/** + * \file + * Implementation of the ARP Address Resolution Protocol. + * \author Adam Dunkels + * + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $ + * + */ + + +#include "uip_arp.h" + +#include + +struct arp_hdr { + struct uip_eth_hdr ethhdr; + u16_t hwtype; + u16_t protocol; + u8_t hwlen; + u8_t protolen; + u16_t opcode; + struct uip_eth_addr shwaddr; + u16_t sipaddr[2]; + struct uip_eth_addr dhwaddr; + u16_t dipaddr[2]; +}; + +struct ethip_hdr { + struct uip_eth_hdr ethhdr; + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +}; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARP_HWTYPE_ETH 1 + +struct arp_entry { + u16_t ipaddr[2]; + struct uip_eth_addr ethaddr; + u8_t time; +}; + +static const struct uip_eth_addr broadcast_ethaddr = + {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff}; + +static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; +static u16_t ipaddr[2]; +static u8_t i, c; + +static u8_t arptime; +static u8_t tmpage; + +#define BUF ((struct arp_hdr *)&uip_buf[0]) +#define IPBUF ((struct ethip_hdr *)&uip_buf[0]) +/*-----------------------------------------------------------------------------------*/ +/** + * Initialize the ARP module. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_init(void) +{ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + memset(arp_table[i].ipaddr, 0, 4); + } +} +/*-----------------------------------------------------------------------------------*/ +/** + * Periodic ARP processing function. + * + * This function performs periodic timer processing in the ARP module + * and should be called at regular intervals. The recommended interval + * is 10 seconds between the calls. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_timer(void) +{ + struct arp_entry *tabptr; + + ++arptime; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 && + arptime - tabptr->time >= UIP_ARP_MAXAGE) { + memset(tabptr->ipaddr, 0, 4); + } + } + +} +/*-----------------------------------------------------------------------------------*/ +static void +uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr) +{ + register struct arp_entry *tabptr; + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + + tabptr = &arp_table[i]; + /* Only check those entries that are actually in use. */ + if(tabptr->ipaddr[0] != 0 && + tabptr->ipaddr[1] != 0) { + + /* Check if the source IP address of the incoming packet matches + the IP address in this ARP table entry. */ + if(ipaddr[0] == tabptr->ipaddr[0] && + ipaddr[1] == tabptr->ipaddr[1]) { + + /* An old entry found, update this and return. */ + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; + + return; + } + } + } + + /* If we get here, no existing ARP table entry was found, so we + create one. */ + + /* First, we try to find an unused entry in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(tabptr->ipaddr[0] == 0 && + tabptr->ipaddr[1] == 0) { + break; + } + } + + /* If no unused entry is found, we try to find the oldest entry and + throw it away. */ + if(i == UIP_ARPTAB_SIZE) { + tmpage = 0; + c = 0; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(arptime - tabptr->time > tmpage) { + tmpage = arptime - tabptr->time; + c = i; + } + } + i = c; + tabptr = &arp_table[i]; + } + + /* Now, i is the ARP table entry which we will fill with the new + information. */ + memcpy(tabptr->ipaddr, ipaddr, 4); + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; +} +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming IP packets + * + * This function should be called by the device driver when an IP + * packet has been received. The function will check if the address is + * in the ARP cache, and if so the ARP cache entry will be + * refreshed. If no ARP cache entry was found, a new one is created. + * + * This function expects an IP packet with a prepended Ethernet header + * in the uip_buf[] buffer, and the length of the packet in the global + * variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +#if 0 +void +uip_arp_ipin(void) +{ + uip_len -= sizeof(struct uip_eth_hdr); + + /* Only insert/update an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + if((IPBUF->srcipaddr[0] & uip_netmask[0]) != + (uip_hostaddr[0] & uip_netmask[0])) { + return; + } + if((IPBUF->srcipaddr[1] & uip_netmask[1]) != + (uip_hostaddr[1] & uip_netmask[1])) { + return; + } + uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src)); + + return; +} +#endif /* 0 */ +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming ARP packets. + * + * This function should be called by the device driver when an ARP + * packet has been received. The function will act differently + * depending on the ARP packet type: if it is a reply for a request + * that we previously sent out, the ARP cache will be filled in with + * the values from the ARP reply. If the incoming ARP packet is an ARP + * request for our IP address, an ARP reply packet is created and put + * into the uip_buf[] buffer. + * + * When the function returns, the value of the global variable uip_len + * indicates whether the device driver should send out a packet or + * not. If uip_len is zero, no packet should be sent. If uip_len is + * non-zero, it contains the length of the outbound packet that is + * present in the uip_buf[] buffer. + * + * This function expects an ARP packet with a prepended Ethernet + * header in the uip_buf[] buffer, and the length of the packet in the + * global variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_arpin(void) +{ + + if(uip_len < sizeof(struct arp_hdr)) { + uip_len = 0; + return; + } + uip_len = 0; + + switch(BUF->opcode) { + case HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + reply. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + /* First, we register the one who made the request in our ARP + table, since it is likely that we will do more communication + with this host in the future. */ + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + + /* The reply opcode is 2. */ + BUF->opcode = HTONS(2); + + memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); + + BUF->dipaddr[0] = BUF->sipaddr[0]; + BUF->dipaddr[1] = BUF->sipaddr[1]; + BUF->sipaddr[0] = uip_hostaddr[0]; + BUF->sipaddr[1] = uip_hostaddr[1]; + + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + uip_len = sizeof(struct arp_hdr); + } + break; + case HTONS(ARP_REPLY): + /* ARP reply. We insert or update the ARP table if it was meant + for us. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + } + break; + } + + return; +} +/*-----------------------------------------------------------------------------------*/ +/** + * Prepend Ethernet header to an outbound IP packet and see if we need + * to send out an ARP request. + * + * This function should be called before sending out an IP packet. The + * function checks the destination IP address of the IP packet to see + * what Ethernet MAC address that should be used as a destination MAC + * address on the Ethernet. + * + * If the destination IP address is in the local network (determined + * by logical ANDing of netmask and our IP address), the function + * checks the ARP cache to see if an entry for the destination IP + * address is found. If so, an Ethernet header is prepended and the + * function returns. If no ARP cache entry is found for the + * destination IP address, the packet in the uip_buf[] is replaced by + * an ARP request packet for the IP address. The IP packet is dropped + * and it is assumed that they higher level protocols (e.g., TCP) + * eventually will retransmit the dropped packet. + * + * If the destination IP address is not on the local network, the IP + * address of the default router is used instead. + * + * When the function returns, a packet is present in the uip_buf[] + * buffer, and the length of the packet is in the global variable + * uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_out(void) +{ + struct arp_entry *tabptr; + + /* Find the destination IP address in the ARP table and construct + the Ethernet header. If the destination IP addres isn't on the + local network, we use the default router's IP address instead. + + If not ARP table entry is found, we overwrite the original IP + packet with an ARP request for the IP address. */ + + /* First check if destination is a local broadcast. */ + if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) { + memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); + } else { + /* Check if the destination address is on the local network. */ + if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ipaddr_copy(ipaddr, uip_draddr); + } else { + /* Else, we use the destination IP address. */ + uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); + } + + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) { + break; + } + } + + if(i == UIP_ARPTAB_SIZE) { + /* The destination address was not in our ARP table, so we + overwrite the IP packet with an ARP request. */ + + memset(BUF->ethhdr.dest.addr, 0xff, 6); + memset(BUF->dhwaddr.addr, 0x00, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + + uip_ipaddr_copy(BUF->dipaddr, ipaddr); + uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); + BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ + BUF->hwtype = HTONS(ARP_HWTYPE_ETH); + BUF->protocol = HTONS(UIP_ETHTYPE_IP); + BUF->hwlen = 6; + BUF->protolen = 4; + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + + uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; + + uip_len = sizeof(struct arp_hdr); + return; + } + + /* Build an ethernet header. */ + memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); + } + memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + + IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); + + uip_len += sizeof(struct uip_eth_hdr); +} +/*-----------------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/uip/uip/uip_arp.h b/uip/uip/uip_arp.h new file mode 100644 index 0000000..e32594d --- /dev/null +++ b/uip/uip/uip_arp.h @@ -0,0 +1,144 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \addtogroup uiparp + * @{ + */ + +/** + * \file + * Macros and definitions for the ARP module. + * \author Adam Dunkels + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.h,v 1.5 2006/06/11 21:46:39 adam Exp $ + * + */ + +#ifndef __UIP_ARP_H__ +#define __UIP_ARP_H__ + +#include "uip.h" + + +extern struct uip_eth_addr uip_ethaddr; + +/** + * The Ethernet header. + */ +struct uip_eth_hdr { + struct uip_eth_addr dest; + struct uip_eth_addr src; + u16_t type; +}; + +#define UIP_ETHTYPE_ARP 0x0806 +#define UIP_ETHTYPE_IP 0x0800 +#define UIP_ETHTYPE_IP6 0x86dd + + +/* The uip_arp_init() function must be called before any of the other + ARP functions. */ +void uip_arp_init(void); + +/* The uip_arp_ipin() function should be called whenever an IP packet + arrives from the Ethernet. This function refreshes the ARP table or + inserts a new mapping if none exists. The function assumes that an + IP packet with an Ethernet header is present in the uip_buf buffer + and that the length of the packet is in the uip_len variable. */ +/*void uip_arp_ipin(void);*/ +#define uip_arp_ipin() + +/* The uip_arp_arpin() should be called when an ARP packet is received + by the Ethernet driver. This function also assumes that the + Ethernet frame is present in the uip_buf buffer. When the + uip_arp_arpin() function returns, the contents of the uip_buf + buffer should be sent out on the Ethernet if the uip_len variable + is > 0. */ +void uip_arp_arpin(void); + +/* The uip_arp_out() function should be called when an IP packet + should be sent out on the Ethernet. This function creates an + Ethernet header before the IP header in the uip_buf buffer. The + Ethernet header will have the correct Ethernet MAC destination + address filled in if an ARP table entry for the destination IP + address (or the IP address of the default router) is present. If no + such table entry is found, the IP packet is overwritten with an ARP + request and we rely on TCP to retransmit the packet that was + overwritten. In any case, the uip_len variable holds the length of + the Ethernet frame that should be transmitted. */ +void uip_arp_out(void); + +/* The uip_arp_timer() function should be called every ten seconds. It + is responsible for flushing old entries in the ARP table. */ +void uip_arp_timer(void); + +/** @} */ + +/** + * \addtogroup uipconffunc + * @{ + */ + + +/** + * Specifiy the Ethernet MAC address. + * + * The ARP code needs to know the MAC address of the Ethernet card in + * order to be able to respond to ARP queries and to generate working + * Ethernet headers. + * + * \note This macro only specifies the Ethernet MAC address to the ARP + * code. It cannot be used to change the MAC address of the Ethernet + * card. + * + * \param eaddr A pointer to a struct uip_eth_addr containing the + * Ethernet MAC address of the Ethernet card. + * + * \hideinitializer + */ +#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \ + uip_ethaddr.addr[1] = eaddr.addr[1];\ + uip_ethaddr.addr[2] = eaddr.addr[2];\ + uip_ethaddr.addr[3] = eaddr.addr[3];\ + uip_ethaddr.addr[4] = eaddr.addr[4];\ + uip_ethaddr.addr[5] = eaddr.addr[5];} while(0) + +/** @} */ +/** @} */ + +#endif /* __UIP_ARP_H__ */ diff --git a/uip/uip/uiplib.c b/uip/uip/uiplib.c new file mode 100644 index 0000000..cb5af2c --- /dev/null +++ b/uip/uip/uiplib.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004, Adam Dunkels and the Swedish Institute of + * Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: uiplib.c,v 1.2 2006/06/12 08:00:31 adam Exp $ + * + */ + + +#include "uip.h" +#include "uiplib.h" + + +/*-----------------------------------------------------------------------------------*/ +unsigned char +uiplib_ipaddrconv(char *addrstr, unsigned char *ipaddr) +{ + unsigned char tmp; + char c; + unsigned char i, j; + + tmp = 0; + + for(i = 0; i < 4; ++i) { + j = 0; + do { + c = *addrstr; + ++j; + if(j > 4) { + return 0; + } + if(c == '.' || c == 0) { + *ipaddr = tmp; + ++ipaddr; + tmp = 0; + } else if(c >= '0' && c <= '9') { + tmp = (tmp * 10) + (c - '0'); + } else { + return 0; + } + ++addrstr; + } while(c != '.' && c != 0); + } + return 1; +} + +/*-----------------------------------------------------------------------------------*/ diff --git a/uip/uip/uiplib.h b/uip/uip/uiplib.h new file mode 100644 index 0000000..c676849 --- /dev/null +++ b/uip/uip/uiplib.h @@ -0,0 +1,71 @@ +/** + * \file + * Various uIP library functions. + * \author + * Adam Dunkels + * + */ + +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: uiplib.h,v 1.1 2006/06/07 09:15:19 adam Exp $ + * + */ +#ifndef __UIPLIB_H__ +#define __UIPLIB_H__ + +/** + * \addtogroup uipconvfunc + * @{ + */ + +/** + * Convert a textual representation of an IP address to a numerical representation. + * + * This function takes a textual representation of an IP address in + * the form a.b.c.d and converts it into a 4-byte array that can be + * used by other uIP functions. + * + * \param addrstr A pointer to a string containing the IP address in + * textual form. + * + * \param addr A pointer to a 4-byte array that will be filled in with + * the numerical representation of the address. + * + * \retval 0 If the IP address could not be parsed. + * \retval Non-zero If the IP address was parsed. + */ +unsigned char uiplib_ipaddrconv(char *addrstr, unsigned char *addr); + +/** @} */ + +#endif /* __UIPLIB_H__ */ diff --git a/uip/uip/uipopt.h b/uip/uip/uipopt.h new file mode 100644 index 0000000..8feabf6 --- /dev/null +++ b/uip/uip/uipopt.h @@ -0,0 +1,544 @@ +/** + * \defgroup uipopt Configuration options for uIP + * @{ + * + * uIP is configured using the per-project configuration file + * uipopt.h. This file contains all compile-time options for uIP and + * should be tweaked to match each specific project. The uIP + * distribution contains a documented example "uipopt.h" that can be + * copied and modified for each project. + * + * \note Most of the configuration options in the uipopt.h should not + * be changed, but rather the per-project uip-conf.h file. + */ + +/** + * \file + * Configuration options for uIP. + * \author Adam Dunkels + * + * This file is used for tweaking various configuration options for + * uIP. You should make a copy of this file into one of your project's + * directories instead of editing this example "uipopt.h" file that + * comes with the uIP distribution. + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uipopt.h,v 1.4 2006/06/12 08:00:31 adam Exp $ + * + */ + +#ifndef __UIPOPT_H__ +#define __UIPOPT_H__ + +#ifndef UIP_LITTLE_ENDIAN +#define UIP_LITTLE_ENDIAN 3412 +#endif /* UIP_LITTLE_ENDIAN */ +#ifndef UIP_BIG_ENDIAN +#define UIP_BIG_ENDIAN 1234 +#endif /* UIP_BIG_ENDIAN */ + +#include "uip-conf.h" + +/*------------------------------------------------------------------------------*/ + +/** + * \name Static configuration options + * @{ + * + * These configuration options can be used for setting the IP address + * settings statically, but only if UIP_FIXEDADDR is set to 1. The + * configuration options for a specific node includes IP address, + * netmask and default router as well as the Ethernet address. The + * netmask, default router and Ethernet address are appliciable only + * if uIP should be run over Ethernet. + * + * All of these should be changed to suit your project. +*/ + +/** + * Determines if uIP should use a fixed IP address or not. + * + * If uIP should use a fixed IP address, the settings are set in the + * uipopt.h file. If not, the macros uip_sethostaddr(), + * uip_setdraddr() and uip_setnetmask() should be used instead. + * + * \hideinitializer + */ +#define UIP_FIXEDADDR 0 + +/** + * Ping IP address asignment. + * + * uIP uses a "ping" packets for setting its own IP address if this + * option is set. If so, uIP will start with an empty IP address and + * the destination IP address of the first incoming "ping" (ICMP echo) + * packet will be used for setting the hosts IP address. + * + * \note This works only if UIP_FIXEDADDR is 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_PINGADDRCONF +#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF +#else /* UIP_CONF_PINGADDRCONF */ +#define UIP_PINGADDRCONF 0 +#endif /* UIP_CONF_PINGADDRCONF */ + + +/** + * Specifies if the uIP ARP module should be compiled with a fixed + * Ethernet MAC address or not. + * + * If this configuration option is 0, the macro uip_setethaddr() can + * be used to specify the Ethernet address at run-time. + * + * \hideinitializer + */ +#define UIP_FIXEDETHADDR 0 + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name IP configuration options + * @{ + * + */ +/** + * The IP TTL (time to live) of IP packets sent by uIP. + * + * This should normally not be changed. + */ +#define UIP_TTL 64 + +/** + * Turn on support for IP packet reassembly. + * + * uIP supports reassembly of fragmented IP packets. This features + * requires an additonal amount of RAM to hold the reassembly buffer + * and the reassembly code size is approximately 700 bytes. The + * reassembly buffer is of the same size as the uip_buf buffer + * (configured by UIP_BUFSIZE). + * + * \note IP packet reassembly is not heavily tested. + * + * \hideinitializer + */ +#define UIP_REASSEMBLY 0 + +/** + * The maximum time an IP fragment should wait in the reassembly + * buffer before it is dropped. + * + */ +#define UIP_REASS_MAXAGE 40 + +/** @} */ + +/*------------------------------------------------------------------------------*/ +/** + * \name UDP configuration options + * @{ + */ + +/** + * Toggles wether UDP support should be compiled in or not. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP +#define UIP_UDP UIP_CONF_UDP +#else /* UIP_CONF_UDP */ +#define UIP_UDP 0 +#endif /* UIP_CONF_UDP */ + +/** + * Toggles if UDP checksums should be used or not. + * + * \note Support for UDP checksums is currently not included in uIP, + * so this option has no function. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CHECKSUMS +#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS +#else +#define UIP_UDP_CHECKSUMS 0 +#endif + +/** + * The maximum amount of concurrent UDP connections. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CONNS +#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS +#else /* UIP_CONF_UDP_CONNS */ +#define UIP_UDP_CONNS 10 +#endif /* UIP_CONF_UDP_CONNS */ + +/** + * The name of the function that should be called when UDP datagrams arrive. + * + * \hideinitializer + */ + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name TCP configuration options + * @{ + */ + +/** + * Determines if support for opening connections from uIP should be + * compiled in. + * + * If the applications that are running on top of uIP for this project + * do not need to open outgoing TCP connections, this configration + * option can be turned off to reduce the code size of uIP. + * + * \hideinitializer + */ +#define UIP_ACTIVE_OPEN 1 + +/** + * The maximum number of simultaneously open TCP connections. + * + * Since the TCP connections are statically allocated, turning this + * configuration knob down results in less RAM used. Each TCP + * connection requires approximatly 30 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_CONNECTIONS +#define UIP_CONNS 10 +#else /* UIP_CONF_MAX_CONNECTIONS */ +#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS +#endif /* UIP_CONF_MAX_CONNECTIONS */ + + +#ifdef UIP_CONF_TCP_LISTEN +#define UIP_TCP_LISTEN +#endif + +/** + * The maximum number of simultaneously listening TCP ports. + * + * Each listening TCP port requires 2 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_LISTENPORTS +#define UIP_LISTENPORTS 20 +#else /* UIP_CONF_MAX_LISTENPORTS */ +#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS +#endif /* UIP_CONF_MAX_LISTENPORTS */ + +/** + * Determines if support for TCP urgent data notification should be + * compiled in. + * + * Urgent data (out-of-band data) is a rarely used TCP feature that + * very seldom would be required. + * + * \hideinitializer + */ +#define UIP_URGDATA 0 + +/** + * The initial retransmission timeout counted in timer pulses. + * + * This should not be changed. + */ +#define UIP_RTO 3 + +/** + * The maximum number of times a segment should be retransmitted + * before the connection should be aborted. + * + * This should not be changed. + */ +#define UIP_MAXRTX 8 + +/** + * The maximum number of times a SYN segment should be retransmitted + * before a connection request should be deemed to have been + * unsuccessful. + * + * This should not need to be changed. + */ +#define UIP_MAXSYNRTX 5 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than + * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. + */ +/* 20081115 bkw: edited */ +#define UIP_TCP_MSS (160 - UIP_LLH_LEN - UIP_TCPIP_HLEN) + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) is the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#ifndef UIP_CONF_RECEIVE_WINDOW +#define UIP_RECEIVE_WINDOW UIP_TCP_MSS +#else +#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW +#endif + +/** + * How long a connection should stay in the TIME_WAIT state. + * + * This configiration option has no real implication, and it should be + * left untouched. + */ +#define UIP_TIME_WAIT_TIMEOUT 120 + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name ARP configuration options + * @{ + */ + +/** + * The size of the ARP table. + * + * This option should be set to a larger value if this uIP node will + * have many connections from the local network. + * + * \hideinitializer + */ +#ifdef UIP_CONF_ARPTAB_SIZE +#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE +#else +#define UIP_ARPTAB_SIZE 8 +#endif + +/** + * The maxium age of ARP table entries measured in 10ths of seconds. + * + * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD + * default). + */ +#define UIP_ARP_MAXAGE 120 + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \name General configuration options + * @{ + */ + +/** + * The size of the uIP packet buffer. + * + * The uIP packet buffer should not be smaller than 60 bytes, and does + * not need to be larger than 1500 bytes. Lower size results in lower + * TCP throughput, larger size results in higher TCP throughput. + * + * \hideinitializer + */ +#ifndef UIP_CONF_BUFFER_SIZE +#define UIP_BUFSIZE 400 +#else /* UIP_CONF_BUFFER_SIZE */ +#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE +#endif /* UIP_CONF_BUFFER_SIZE */ + + +/** + * Determines if statistics support should be compiled in. + * + * The statistics is useful for debugging and to show the user. + * + * \hideinitializer + */ +#ifndef UIP_CONF_STATISTICS +#define UIP_STATISTICS 0 +#else /* UIP_CONF_STATISTICS */ +#define UIP_STATISTICS UIP_CONF_STATISTICS +#endif /* UIP_CONF_STATISTICS */ + +/** + * Determines if logging of certain events should be compiled in. + * + * This is useful mostly for debugging. The function uip_log() + * must be implemented to suit the architecture of the project, if + * logging is turned on. + * + * \hideinitializer + */ +#ifndef UIP_CONF_LOGGING +#define UIP_LOGGING 0 +#else /* UIP_CONF_LOGGING */ +#define UIP_LOGGING UIP_CONF_LOGGING +#endif /* UIP_CONF_LOGGING */ + +/** + * Broadcast support. + * + * This flag configures IP broadcast support. This is useful only + * together with UDP. + * + * \hideinitializer + * + */ +#ifndef UIP_CONF_BROADCAST +#define UIP_BROADCAST 0 +#else /* UIP_CONF_BROADCAST */ +#define UIP_BROADCAST UIP_CONF_BROADCAST +#endif /* UIP_CONF_BROADCAST */ + +/** + * Print out a uIP log message. + * + * This function must be implemented by the module that uses uIP, and + * is called by uIP whenever a log message is generated. + */ +void uip_log(char *msg); + +/** + * The link level header length. + * + * This is the offset into the uip_buf where the IP header can be + * found. For Ethernet, this should be set to 14. For SLIP, this + * should be set to 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_LLH_LEN +#define UIP_LLH_LEN UIP_CONF_LLH_LEN +#else /* UIP_CONF_LLH_LEN */ +#define UIP_LLH_LEN 14 +#endif /* UIP_CONF_LLH_LEN */ + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name CPU architecture configuration + * @{ + * + * The CPU architecture configuration is where the endianess of the + * CPU on which uIP is to be run is specified. Most CPUs today are + * little endian, and the most notable exception are the Motorolas + * which are big endian. The BYTE_ORDER macro should be changed to + * reflect the CPU architecture on which uIP is to be run. + */ + +/** + * The byte order of the CPU architecture on which uIP is to be run. + * + * This option can be either BIG_ENDIAN (Motorola byte order) or + * LITTLE_ENDIAN (Intel byte order). + * + * \hideinitializer + */ +#ifdef UIP_CONF_BYTE_ORDER +#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER +#else /* UIP_CONF_BYTE_ORDER */ +#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN +#endif /* UIP_CONF_BYTE_ORDER */ + +/** @} */ +/*------------------------------------------------------------------------------*/ + +/** + * \name Appication specific configurations + * @{ + * + * An uIP application is implemented using a single application + * function that is called by uIP whenever a TCP/IP event occurs. The + * name of this function must be registered with uIP at compile time + * using the UIP_APPCALL definition. + * + * uIP applications can store the application state within the + * uip_conn structure by specifying the type of the application + * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t. + * + * The file containing the definitions must be included in the + * uipopt.h file. + * + * The following example illustrates how this can look. + \code + +void httpd_appcall(void); +#define UIP_APPCALL httpd_appcall + +struct httpd_state { + u8_t state; + u16_t count; + char *dataptr; + char *script; +}; +typedef struct httpd_state uip_tcp_appstate_t + \endcode + */ + +/** + * \var #define UIP_APPCALL + * + * The name of the application function that uIP should call in + * response to TCP/IP events. + * + */ + +/** + * \var typedef uip_tcp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ + +/** + * \var typedef uip_udp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ +/** @} */ +/** @} */ + +#endif /* __UIPOPT_H__ */ diff --git a/uip/unix/Makefile b/uip/unix/Makefile new file mode 100644 index 0000000..ed64927 --- /dev/null +++ b/uip/unix/Makefile @@ -0,0 +1,44 @@ +# Copyright (c) 2001, Adam Dunkels. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote +# products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# This file is part of the uIP TCP/IP stack. +# +# $Id: Makefile,v 1.13 2006/06/11 21:55:03 adam Exp $ +# + +all: uip + +CC = gcc +AR = ar +APPS = webserver +CFLAGS = -Wall -g -I../uip -I. -fpack-struct -Os +-include ../uip/Makefile.include + +uip: $(addprefix $(OBJECTDIR)/, main.o tapdev.o clock-arch.o) apps.a uip.a + +clean: + rm -fr *.o *~ *core uip $(OBJECTDIR) *.a diff --git a/uip/unix/clock-arch.c b/uip/unix/clock-arch.c new file mode 100644 index 0000000..d140aaf --- /dev/null +++ b/uip/unix/clock-arch.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: clock-arch.c,v 1.2 2006/06/12 08:00:31 adam Exp $ + */ + +/** + * \file + * Implementation of architecture-specific clock functionality + * \author + * Adam Dunkels + */ + +#include "clock-arch.h" +#include + +/*---------------------------------------------------------------------------*/ +clock_time_t +clock_time(void) +{ + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/unix/clock-arch.h b/uip/unix/clock-arch.h new file mode 100644 index 0000000..e51eee9 --- /dev/null +++ b/uip/unix/clock-arch.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: clock-arch.h,v 1.2 2006/06/12 08:00:31 adam Exp $ + */ + +#ifndef __CLOCK_ARCH_H__ +#define __CLOCK_ARCH_H__ + +typedef int clock_time_t; +#define CLOCK_CONF_SECOND 1000 + +#endif /* __CLOCK_ARCH_H__ */ diff --git a/uip/unix/main.c b/uip/unix/main.c new file mode 100644 index 0000000..e4130e9 --- /dev/null +++ b/uip/unix/main.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Dunkels. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: main.c,v 1.16 2006/06/11 21:55:03 adam Exp $ + * + */ + + +#include "uip.h" +#include "uip_arp.h" +#include "tapdev.h" + +#include "timer.h" + +#define BUF ((struct uip_eth_hdr *)&uip_buf[0]) + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/*---------------------------------------------------------------------------*/ +int +main(void) +{ + int i; + uip_ipaddr_t ipaddr; + struct timer periodic_timer, arp_timer; + + timer_set(&periodic_timer, CLOCK_SECOND / 2); + timer_set(&arp_timer, CLOCK_SECOND * 10); + + tapdev_init(); + uip_init(); + + uip_ipaddr(ipaddr, 192,168,0,2); + uip_sethostaddr(ipaddr); + uip_ipaddr(ipaddr, 192,168,0,1); + uip_setdraddr(ipaddr); + uip_ipaddr(ipaddr, 255,255,255,0); + uip_setnetmask(ipaddr); + + httpd_init(); + + /* telnetd_init();*/ + + /* hello_world_init();*/ + + /* { + u8_t mac[6] = {1,2,3,4,5,6}; + dhcpc_init(&mac, 6); + }*/ + + /*uip_ipaddr(ipaddr, 127,0,0,1); + smtp_configure("localhost", ipaddr); + SMTP_SEND("adam@sics.se", NULL, "uip-testing@example.com", + "Testing SMTP from uIP", + "Test message sent by uIP\r\n");*/ + + /* + webclient_init(); + resolv_init(); + uip_ipaddr(ipaddr, 195,54,122,204); + resolv_conf(ipaddr); + resolv_query("www.sics.se");*/ + + + + while(1) { + uip_len = tapdev_read(); + if(uip_len > 0) { + if(BUF->type == htons(UIP_ETHTYPE_IP)) { + uip_arp_ipin(); + uip_input(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + uip_arp_out(); + tapdev_send(); + } + } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + tapdev_send(); + } + } + + } else if(timer_expired(&periodic_timer)) { + timer_reset(&periodic_timer); + for(i = 0; i < UIP_CONNS; i++) { + uip_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + uip_arp_out(); + tapdev_send(); + } + } + +#if UIP_UDP + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + uip_arp_out(); + tapdev_send(); + } + } +#endif /* UIP_UDP */ + + /* Call the ARP timer function every 10 seconds. */ + if(timer_expired(&arp_timer)) { + timer_reset(&arp_timer); + uip_arp_timer(); + } + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +void +uip_log(char *m) +{ + printf("uIP log message: %s\n", m); +} +void +resolv_found(char *name, u16_t *ipaddr) +{ + u16_t *ipaddr2; + + if(ipaddr == NULL) { + printf("Host '%s' not found.\n", name); + } else { + printf("Found name '%s' = %d.%d.%d.%d\n", name, + htons(ipaddr[0]) >> 8, + htons(ipaddr[0]) & 0xff, + htons(ipaddr[1]) >> 8, + htons(ipaddr[1]) & 0xff); + /* webclient_get("www.sics.se", 80, "/~adam/uip");*/ + } +} +#ifdef __DHCPC_H__ +void +dhcpc_configured(const struct dhcpc_state *s) +{ + uip_sethostaddr(s->ipaddr); + uip_setnetmask(s->netmask); + uip_setdraddr(s->default_router); + resolv_conf(s->dnsaddr); +} +#endif /* __DHCPC_H__ */ +void +smtp_done(unsigned char code) +{ + printf("SMTP done with code %d\n", code); +} +void +webclient_closed(void) +{ + printf("Webclient: connection closed\n"); +} +void +webclient_aborted(void) +{ + printf("Webclient: connection aborted\n"); +} +void +webclient_timedout(void) +{ + printf("Webclient: connection timed out\n"); +} +void +webclient_connected(void) +{ + printf("Webclient: connected, waiting for data...\n"); +} +void +webclient_datahandler(char *data, u16_t len) +{ + printf("Webclient: got %d bytes of data.\n", len); +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/unix/tapdev.c b/uip/unix/tapdev.c new file mode 100644 index 0000000..417b288 --- /dev/null +++ b/uip/unix/tapdev.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Adam Dunkels + * + * $Id: tapdev.c,v 1.8 2006/06/07 08:39:58 adam Exp $ + */ + +#define UIP_DRIPADDR0 192 +#define UIP_DRIPADDR1 168 +#define UIP_DRIPADDR2 0 +#define UIP_DRIPADDR3 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef linux +#include +#include +#include +#define DEVTAP "/dev/net/tun" +#else /* linux */ +#define DEVTAP "/dev/tap0" +#endif /* linux */ + +#include "uip.h" + +static int drop = 0; +static int fd; + + +/*---------------------------------------------------------------------------*/ +void +tapdev_init(void) +{ + char buf[1024]; + + fd = open(DEVTAP, O_RDWR); + if(fd == -1) { + perror("tapdev: tapdev_init: open"); + exit(1); + } + +#ifdef linux + { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) { + perror(buf); + exit(1); + } + } +#endif /* Linux */ + + snprintf(buf, sizeof(buf), "ifconfig tap0 inet %d.%d.%d.%d", + UIP_DRIPADDR0, UIP_DRIPADDR1, UIP_DRIPADDR2, UIP_DRIPADDR3); + system(buf); + +} +/*---------------------------------------------------------------------------*/ +unsigned int +tapdev_read(void) +{ + fd_set fdset; + struct timeval tv, now; + int ret; + + tv.tv_sec = 0; + tv.tv_usec = 1000; + + + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + + ret = select(fd + 1, &fdset, NULL, NULL, &tv); + if(ret == 0) { + return 0; + } + ret = read(fd, uip_buf, UIP_BUFSIZE); + if(ret == -1) { + perror("tap_dev: tapdev_read: read"); + } + + /* printf("--- tap_dev: tapdev_read: read %d bytes\n", ret);*/ + /* { + int i; + for(i = 0; i < 20; i++) { + printf("%x ", uip_buf[i]); + } + printf("\n"); + }*/ + /* check_checksum(uip_buf, ret);*/ + return ret; +} +/*---------------------------------------------------------------------------*/ +void +tapdev_send(void) +{ + int ret; + /* printf("tapdev_send: sending %d bytes\n", size);*/ + /* check_checksum(uip_buf, size);*/ + + /* drop++; + if(drop % 8 == 7) { + printf("Dropped a packet!\n"); + return; + }*/ + ret = write(fd, uip_buf, uip_len); + if(ret == -1) { + perror("tap_dev: tapdev_send: writev"); + exit(1); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/unix/tapdev.h b/uip/unix/tapdev.h new file mode 100644 index 0000000..280bc52 --- /dev/null +++ b/uip/unix/tapdev.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Dunkels. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: tapdev.h,v 1.1 2002/01/10 06:22:56 adam Exp $ + * + */ + +#ifndef __TAPDEV_H__ +#define __TAPDEV_H__ + +void tapdev_init(void); +unsigned int tapdev_read(void); +void tapdev_send(void); + +#endif /* __TAPDEV_H__ */ diff --git a/uip/unix/uip-conf.h b/uip/unix/uip-conf.h new file mode 100644 index 0000000..2878c85 --- /dev/null +++ b/uip/unix/uip-conf.h @@ -0,0 +1,157 @@ +/** + * \addtogroup uipopt + * @{ + */ + +/** + * \name Project-specific configuration options + * @{ + * + * uIP has a number of configuration options that can be overridden + * for each project. These are kept in a project-specific uip-conf.h + * file and all configuration names have the prefix UIP_CONF. + */ + +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: uip-conf.h,v 1.6 2006/06/12 08:00:31 adam Exp $ + */ + +/** + * \file + * An example uIP configuration file + * \author + * Adam Dunkels + */ + +#ifndef __UIP_CONF_H__ +#define __UIP_CONF_H__ + +#include + +/** + * 8 bit datatype + * + * This typedef defines the 8-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef uint8_t u8_t; + +/** + * 16 bit datatype + * + * This typedef defines the 16-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef uint16_t u16_t; + +/** + * Statistics datatype + * + * This typedef defines the dataype used for keeping statistics in + * uIP. + * + * \hideinitializer + */ +typedef unsigned short uip_stats_t; + +/** + * Maximum number of TCP connections. + * + * \hideinitializer + */ +#define UIP_CONF_MAX_CONNECTIONS 40 + +/** + * Maximum number of listening TCP ports. + * + * \hideinitializer + */ +#define UIP_CONF_MAX_LISTENPORTS 40 + +/** + * uIP buffer size. + * + * \hideinitializer + */ +#define UIP_CONF_BUFFER_SIZE 420 + +/** + * CPU byte order. + * + * \hideinitializer + */ +#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN + +/** + * Logging on or off + * + * \hideinitializer + */ +#define UIP_CONF_LOGGING 1 + +/** + * UDP support on or off + * + * \hideinitializer + */ +#define UIP_CONF_UDP 0 + +/** + * UDP checksums on or off + * + * \hideinitializer + */ +#define UIP_CONF_UDP_CHECKSUMS 1 + +/** + * uIP statistics on or off + * + * \hideinitializer + */ +#define UIP_CONF_STATISTICS 1 + +/* Here we include the header file for the application(s) we use in + our project. */ +/*#include "smtp.h"*/ +/*#include "hello-world.h"*/ +/*#include "telnetd.h"*/ +#include "webserver.h" +/*#include "dhcpc.h"*/ +/*#include "resolv.h"*/ +/*#include "webclient.h"*/ + +#endif /* __UIP_CONF_H__ */ + +/** @} */ +/** @} */ -- cgit v1.2.3
LocalRemoteStateRetransmissionsTimerFlags