Merge branch 'master' of git://github.com/deater/dos33fsprogs

This commit is contained in:
Vince Weaver 2017-01-04 14:08:50 -05:00
commit f1aab6e953
12 changed files with 1007 additions and 436 deletions

View File

@ -1,6 +1,7 @@
include ../Makefile.inc
all: asoft_detoken tokenize_asoft integer_detoken asoft_compact
all: asoft_detoken tokenize_asoft integer_detoken asoft_compact bin2data
asoft_compact: asoft_compact.o
$(CC) $(LFLAGS) -o asoft_compact asoft_compact.o
@ -14,6 +15,12 @@ asoft_detoken: asoft_detoken.o
asoft_detoken.o: asoft_detoken.c
$(CC) $(CFLAGS) -c asoft_detoken.c
bin2data: bin2data.o
$(CC) $(LFLAGS) -o bin2data bin2data.o
bin2data.o: bin2data.c
$(CC) $(CFLAGS) -c bin2data.c
integer_detoken: integer_detoken.o
$(CC) $(LFLAGS) -o integer_detoken integer_detoken.o
@ -31,7 +38,7 @@ install:
cp asoft_detoken tokenize_asoft integer_detoken $(INSTALL_LOC)
clean:
rm -f *~ *.o asoft_detoken tokenize_asoft \
rm -f *~ *.o asoft_detoken tokenize_asoft bin2data \
integer_detoken asoft_compact

View File

@ -29,3 +29,10 @@ asoft_compact: tries to compress your Applesoft basic program
to make it as small as possible
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bin2data: takes binary image and converts it to suitable
BASIC to poke into memory.
Useful for getting machine language routines usable
in BASIC programs

View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
int address=0x300;
int bytes=0,line=10,i;
struct stat file_info;
int fd;
unsigned char c;
if (argc<2) {
printf("Usage:\t%s binfile [addr]\n\n",argv[0]);
return -1;
}
if (argc>2) {
address=strtol(argv[2],NULL,0);
}
if (stat(argv[1],&file_info)<0) {
fprintf(stderr,"Could not stat file %s\n\n",argv[1]);
return -1;
}
bytes=(int)file_info.st_size;
fd=open(argv[1],O_RDONLY);
if (fd<0) {
fprintf(stderr,"Could not open file %s\n\n",argv[1]);
return -1;
}
printf("%d FOR I=0 TO %d: READ X: POKE %d+I,X:NEXT I\n",
line,bytes-1,address);
line+=10;
for(i=0;i<bytes;i++) {
read(fd,&c,1);
if (i%16==0) {
printf("%d DATA ",line);
line+=10;
}
printf("%d",c);
if ((i%16!=15) && (i!=(bytes-1))) printf(",");
else printf("\n");
}
close(fd);
return 0;
}

View File

@ -14,7 +14,7 @@ dos33: dos33.o
$(CC) $(LFLAGS) -o dos33 dos33.o
dos33.o: dos33.c dos33.h
$(CC) $(CFLAGS) -c dos33.c
$(CC) $(CFLAGS) -g -c dos33.c
dos33_text2ascii: dos33_text2ascii.o
$(CC) $(LFLGAS) -o dos33_text2ascii dos33_text2ascii.o

View File

@ -429,10 +429,14 @@ found_one:
#define ERROR_IMAGE_NOT_FOUND 4
#define ERROR_CATALOG_FULL 5
#define ADD_RAW 0
#define ADD_BINARY 1
/* creates file apple_filename on the image from local file filename */
/* returns ?? */
static int dos33_add_file(int fd,char type,char *filename,
char *apple_filename) {
static int dos33_add_file(int fd, char dos_type,
int file_type, int address, int length,
char *filename, char *apple_filename) {
int free_space,file_size,needed_sectors;
struct stat file_info;
@ -441,6 +445,7 @@ static int dos33_add_file(int fd,char type,char *filename,
int catalog_track,catalog_sector,sectors_used=0;
int input_fd;
int result;
int first_write=1;
if (apple_filename[0]<64) {
fprintf(stderr,"Error! First char of filename "
@ -471,6 +476,12 @@ static int dos33_add_file(int fd,char type,char *filename,
if (debug) printf("Filesize: %d\n",file_size);
if (file_type==ADD_BINARY) {
if (debug) printf("Adding 4 bytes for size/offset\n");
if (length==0) length=file_size;
file_size+=4;
}
/* We need to round up to nearest sector size */
/* Add an extra sector for the T/S list */
/* Then add extra sector for a T/S list every 122*256 bytes (~31k) */
@ -506,88 +517,105 @@ static int dos33_add_file(int fd,char type,char *filename,
i=0;
while (i<size_in_sectors) {
/* Create new T/S list if necessary */
if (i%TSL_MAX_NUMBER==0) {
old_ts_list=ts_list;
/* Create new T/S list if necessary */
if (i%TSL_MAX_NUMBER==0) {
old_ts_list=ts_list;
/* allocate a sector for the new list */
ts_list=dos33_allocate_sector(fd);
/* allocate a sector for the new list */
ts_list=dos33_allocate_sector(fd);
sectors_used++;
if (ts_list<0) return -1;
/* clear the t/s sector */
for(x=0;x<BYTES_PER_SECTOR;x++) {
sector_buffer[x]=0;
}
lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
if (i==0) {
initial_ts_list=ts_list;
}
else {
/* we aren't the first t/s list so do special stuff */
/* load in the old t/s list */
lseek(fd,
DISK_OFFSET(get_high_byte(old_ts_list),
get_low_byte(old_ts_list)),
SEEK_SET);
result=read(fd,&sector_buffer,BYTES_PER_SECTOR);
/* point from old ts list to new one we just made */
sector_buffer[TSL_NEXT_TRACK]=get_high_byte(ts_list);
sector_buffer[TSL_NEXT_SECTOR]=get_low_byte(ts_list);
/* set offset into file */
sector_buffer[TSL_OFFSET_H]=get_high_byte((i-122)*256);
sector_buffer[TSL_OFFSET_L]=get_low_byte((i-122)*256);
/* write out the old t/s list with updated info */
lseek(fd,
DISK_OFFSET(get_high_byte(old_ts_list),
get_low_byte(old_ts_list)),
SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
}
}
/* allocate a sector */
data_ts=dos33_allocate_sector(fd);
sectors_used++;
if (ts_list<0) return -1;
/* clear the t/s sector */
for(x=0;x<BYTES_PER_SECTOR;x++) sector_buffer[x]=0;
lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
if (i==0) initial_ts_list=ts_list;
else {
/* we aren't the first t/s list so do special stuff */
if (data_ts<0) return -1;
/* load in the old t/s list */
lseek(fd,
DISK_OFFSET(get_high_byte(old_ts_list),
get_low_byte(old_ts_list)),
SEEK_SET);
/* clear sector */
for(x=0;x<BYTES_PER_SECTOR;x++) sector_buffer[x]=0;
result=read(fd,&sector_buffer,BYTES_PER_SECTOR);
/* point from old ts list to new one we just made */
sector_buffer[TSL_NEXT_TRACK]=get_high_byte(ts_list);
sector_buffer[TSL_NEXT_SECTOR]=get_low_byte(ts_list);
/* set offset into file */
sector_buffer[TSL_OFFSET_H]=get_high_byte((i-122)*256);
sector_buffer[TSL_OFFSET_L]=get_low_byte((i-122)*256);
/* write out the old t/s list with updated info */
lseek(fd,
DISK_OFFSET(get_high_byte(old_ts_list),
get_low_byte(old_ts_list)),
SEEK_SET);
/* read from input */
if ((first_write) && (file_type==ADD_BINARY)) {
first_write=0;
sector_buffer[0]=address&0xff;
sector_buffer[1]=(address>>8)&0xff;
sector_buffer[2]=(length)&0xff;
sector_buffer[3]=((length)>>8)&0xff;
bytes_read=read(input_fd,sector_buffer+4,
BYTES_PER_SECTOR-4);
bytes_read+=4;
}
else {
bytes_read=read(input_fd,sector_buffer,
BYTES_PER_SECTOR);
}
first_write=0;
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
}
}
/* allocate a sector */
data_ts=dos33_allocate_sector(fd);
sectors_used++;
if (data_ts<0) return -1;
/* clear sector */
for(x=0;x<BYTES_PER_SECTOR;x++) sector_buffer[x]=0;
if (bytes_read<0) fprintf(stderr,"Error reading bytes!\n");
/* read from input */
bytes_read=read(input_fd,sector_buffer,BYTES_PER_SECTOR);
if (bytes_read<0) fprintf(stderr,"Error reading bytes!\n");
/* write to disk image */
lseek(fd,DISK_OFFSET((data_ts>>8)&0xff,data_ts&0xff),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
/* write to disk image */
lseek(fd,DISK_OFFSET((data_ts>>8)&0xff,data_ts&0xff),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
// printf("Writing %i bytes to %i/%i\n",bytes_read,(data_ts>>8)&0xff,
// data_ts&0xff);
if (debug) printf("Writing %i bytes to %i/%i\n",
bytes_read,(data_ts>>8)&0xff,data_ts&0xff);
/* add to T/s table */
/* read in t/s list */
lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET);
result=read(fd,sector_buffer,BYTES_PER_SECTOR);
/* point to new data sector */
sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST]=(data_ts>>8)&0xff;
sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST+1]=(data_ts&0xff);
/* write t/s list back out */
lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
i++;
}
/* add to T/s table */
/* read in t/s list */
lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET);
result=read(fd,sector_buffer,BYTES_PER_SECTOR);
/* point to new data sector */
sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST]=(data_ts>>8)&0xff;
sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST+1]=(data_ts&0xff);
/* write t/s list back out */
lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
i++;
}
/* Add new file to Catalog */
@ -632,43 +660,43 @@ continue_parsing_catalog:
goto continue_parsing_catalog;
got_a_dentry:
// printf("Adding file at entry %i of catalog 0x%x:0x%x\n",
// i,catalog_track,catalog_sector);
/* Point entry to initial t/s list */
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)]=(initial_ts_list>>8)&0xff;
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+1]=(initial_ts_list&0xff);
/* set file type */
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_TYPE]=
dos33_char_to_type(type,0);
got_a_dentry:
// printf("Adding file at entry %i of catalog 0x%x:0x%x\n",
// i,catalog_track,catalog_sector);
// printf("Pointing T/S to %x/%x\n",(initial_ts_list>>8)&0xff,initial_ts_list&0xff);
/* Point entry to initial t/s list */
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)]=(initial_ts_list>>8)&0xff;
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+1]=(initial_ts_list&0xff);
/* set file type */
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_TYPE]=
dos33_char_to_type(dos_type,0);
/* copy over filename */
for(x=0;x<strlen(apple_filename);x++) {
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_NAME+x]=
apple_filename[x]^0x80;
}
/* pad out the filename with spaces */
for(x=strlen(apple_filename);x<FILE_NAME_SIZE;x++) {
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_NAME+x]=' '^0x80;
}
/* fill in filesize in sectors */
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_SIZE_L]=
sectors_used&0xff;
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_SIZE_H]=
(sectors_used>>8)&0xff;
/* write out catalog sector */
lseek(fd,DISK_OFFSET(catalog_track,catalog_sector),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
// printf("Pointing T/S to %x/%x\n",(initial_ts_list>>8)&0xff,initial_ts_list&0xff);
if (result<0) fprintf(stderr,"Error on I/O\n");
return 0;
/* copy over filename */
for(x=0;x<strlen(apple_filename);x++) {
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_NAME+x]=
apple_filename[x]^0x80;
}
/* pad out the filename with spaces */
for(x=strlen(apple_filename);x<FILE_NAME_SIZE;x++) {
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_NAME+x]=' '^0x80;
}
/* fill in filesize in sectors */
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_SIZE_L]=
sectors_used&0xff;
sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_SIZE_H]=
(sectors_used>>8)&0xff;
/* write out catalog sector */
lseek(fd,DISK_OFFSET(catalog_track,catalog_sector),SEEK_SET);
result=write(fd,sector_buffer,BYTES_PER_SECTOR);
if (result<0) fprintf(stderr,"Error on I/O\n");
return 0;
}
/* load a file. fts=entry/track/sector */
@ -1174,10 +1202,13 @@ static int dos33_rename_hello(int fd, char *new_name) {
return 0;
}
static int display_help(char *name) {
static void display_help(char *name, int version_only) {
printf("\ndos33 version %s\n",VERSION);
printf("by Vince Weaver <vince@deater.net>\n");
printf("\n");
if (version_only) return;
printf("Usage: %s [-h] [-y] disk_image COMMAND [options]\n",name);
printf("\t-h : this help message\n");
printf("\t-y : always answer yes for anying warning questions\n");
@ -1187,7 +1218,7 @@ static int display_help(char *name) {
printf("\tCATALOG\n");
printf("\tLOAD apple_file <local_file>\n");
printf("\tSAVE type local_file <apple_file>\n");
printf("\tBSAVE type local_file <apple_file>\n");
printf("\tBSAVE [-a addr] [-l len] local_file <apple_file>\n");
printf("\tDELETE apple_file\n");
printf("\tLOCK apple_file\n");
printf("\tUNLOCK apple_file\n");
@ -1200,24 +1231,26 @@ static int display_help(char *name) {
printf("\tCOPY\n");
#endif
printf("\n");
return 0;
return;
}
#define COMMAND_UNKNOWN 0
#define COMMAND_LOAD 1
#define COMMAND_SAVE 2
#define COMMAND_CATALOG 3
#define COMMAND_DELETE 4
#define COMMAND_UNDELETE 5
#define COMMAND_LOCK 6
#define COMMAND_UNLOCK 7
#define COMMAND_INIT 8
#define COMMAND_RENAME 9
#define COMMAND_COPY 10
#define COMMAND_DUMP 11
#define COMMAND_HELLO 12
#define COMMAND_BSAVE 13
#define COMMAND_LOAD 0
#define COMMAND_SAVE 1
#define COMMAND_CATALOG 2
#define COMMAND_DELETE 3
#define COMMAND_UNDELETE 4
#define COMMAND_LOCK 5
#define COMMAND_UNLOCK 6
#define COMMAND_INIT 7
#define COMMAND_RENAME 8
#define COMMAND_COPY 9
#define COMMAND_DUMP 10
#define COMMAND_HELLO 11
#define COMMAND_BSAVE 12
#define COMMAND_BLOAD 13
#define MAX_COMMAND 14
#define COMMAND_UNKNOWN 255
static struct command_type {
int type;
@ -1242,7 +1275,7 @@ static int lookup_command(char *name) {
int which=COMMAND_UNKNOWN,i;
for(i=1;i<MAX_COMMAND;i++) {
for(i=0;i<MAX_COMMAND;i++) {
if(!strncmp(name,commands[i].name,strlen(commands[i].name))) {
which=commands[i].type;
break;
@ -1252,6 +1285,21 @@ static int lookup_command(char *name) {
}
static int truncate_filename(char *out, char *in) {
int truncated=0;
/* Truncate filename if too long */
if (strlen(in)>30) {
fprintf(stderr,"Warning! Truncating %s to 30 chars\n",in);
truncated=1;
}
strncpy(out,in,30);
out[30]='\0';
return truncated;
}
int main(int argc, char **argv) {
char image[BUFSIZ];
@ -1261,85 +1309,105 @@ int main(int argc, char **argv) {
int command,catalog_entry;
char temp_string[BUFSIZ];
char apple_filename[31],new_filename[31];
char output_filename[BUFSIZ];
char local_filename[BUFSIZ];
char *result_string;
int always_yes=0,firstarg=1,extra_ops=0;
int always_yes=0;
char *temp,*endptr;
int c;
int address=0, length=0;
/* Check command line arguments */
/* Ugh I should use getopt() or something similar here */
while ((c = getopt (argc, argv,"a:l:hvy"))!=-1) {
switch (c) {
if (argc<2) {
display_help(argv[0]);
goto exit_program;
case 'a':
address=strtol(optarg,&endptr,0);
if (debug) printf("Address=%d\n",address);
break;
case 'l':
length=strtol(optarg,&endptr,0);
if (debug) printf("Length=%d\n",address);
break;
case 'v':
display_help(argv[0],1);
return 0;
case 'h': display_help(argv[0],0);
return 0;
case 'y':
always_yes=1;
break;
}
}
if (!strncmp(argv[1],"-h",2)) {
display_help(argv[1]);
goto exit_program;
}
if (!strncmp(argv[1],"-y",2)) {
always_yes=1;
extra_ops++;
firstarg++;
}
if (argc<3) {
printf("\nInvalid arguments!\n");
display_help(argv[0]);
goto exit_program;
if (optind==argc) {
fprintf(stderr,"ERROR! Must specify disk image!\n\n");
return -1;
}
/* get argument 1, which is image name */
strncpy(image,argv[firstarg],BUFSIZ);
strncpy(image,argv[optind],BUFSIZ);
dos_fd=open(image,O_RDWR);
if (dos_fd<0) {
fprintf(stderr,"Error opening disk_image: %s\n",image);
exit(4);
return -1;
}
/* Check argument #2 which is command */
strncpy(temp_string,argv[firstarg+1],BUFSIZ);
/* Move to next argument */
optind++;
if (optind==argc) {
fprintf(stderr,"ERROR! Must specify command!\n\n");
return -2;
}
/* Grab command */
strncpy(temp_string,argv[optind],BUFSIZ);
/* Make command be uppercase */
for(i=0;i<strlen(temp_string);i++) {
temp_string[i]=toupper(temp_string[i]);
}
/* Move to next argument */
optind++;
command=lookup_command(temp_string);
switch(command) {
case COMMAND_UNKNOWN:
display_help(argv[0]);
goto exit_program;
fprintf(stderr,"ERROR! Unknown command %s\n",temp_string);
fprintf(stderr,"\tTry \"%s -h\" for help.\n\n",argv[0]);
goto exit_and_close;
break;
/* Load a file from disk image to local machine */
case COMMAND_LOAD:
/* check and make sure we have apple_filename */
if (argc<4+extra_ops) {
if (argc==optind) {
fprintf(stderr,"Error! Need apple file_name\n");
fprintf(stderr,"%s %s LOAD apple_filename\n",
argv[0],image);
goto exit_and_close;
}
/* Truncate filename if too long */
if (strlen(argv[firstarg+2])>30) {
fprintf(stderr,"Warning! Truncating %s to 30 chars\n",
argv[firstarg+2]);
}
strncpy(apple_filename,argv[firstarg+2],30);
apple_filename[30]='\0';
truncate_filename(apple_filename,argv[optind]);
if (debug) printf("\tApple filename: %s\n",apple_filename);
/* get output filename */
if (argc==5+extra_ops) {
strncpy(output_filename,argv[firstarg+3],BUFSIZ);
optind++;
if (argc>=optind) {
strncpy(local_filename,argv[optind],BUFSIZ);
}
else {
strncpy(output_filename,apple_filename,30);
strncpy(local_filename,apple_filename,30);
}
if (debug) printf("\tOutput filename: %s\n",local_filename);
/* get the entry/track/sector for file */
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
@ -1350,243 +1418,276 @@ int main(int argc, char **argv) {
goto exit_and_close;
}
dos33_load_file(dos_fd,catalog_entry,output_filename);
dos33_load_file(dos_fd,catalog_entry,local_filename);
break;
case COMMAND_CATALOG:
/* get first catalog */
catalog_entry=dos33_get_catalog_ts(dos_fd);
/* get first catalog */
catalog_entry=dos33_get_catalog_ts(dos_fd);
printf("\nDISK VOLUME %i\n\n",sector_buffer[VTOC_DISK_VOLUME]);
while(catalog_entry>0) {
catalog_entry=dos33_find_next_file(dos_fd,catalog_entry);
if (catalog_entry>0) {
dos33_print_file_info(dos_fd,catalog_entry);
catalog_entry+=(1<<16);
/* dos33_find_next_file() handles wrapping issues */
}
}
printf("\n");
break;
printf("\nDISK VOLUME %i\n\n",sector_buffer[VTOC_DISK_VOLUME]);
while(catalog_entry>0) {
catalog_entry=dos33_find_next_file(dos_fd,catalog_entry);
if (catalog_entry>0) {
dos33_print_file_info(dos_fd,catalog_entry);
/* why 1<<16 ? */
catalog_entry+=(1<<16);
/* dos33_find_next_file() handles wrapping issues */
}
}
printf("\n");
break;
case COMMAND_SAVE:
/* argv3 == type == A,B,T,I,N,L etc */
/* argv4 == name of local file */
/* argv5 == optional name of file on disk image */
if (argc<5+extra_ops) {
if (argc==optind) {
fprintf(stderr,"Error! Need type and file_name\n");
fprintf(stderr,"%s %s SAVE type "
"file_name apple_filename\n",
"file_name apple_filename\n\n",
argv[0],image);
goto exit_and_close;
}
type=argv[firstarg+2][0];
type=argv[optind][0];
optind++;
case COMMAND_BSAVE:
if (debug) printf("\ttype=%c\n",type);
if (argc==optind) {
fprintf(stderr,"Error! Need file_name\n");
if (command==COMMAND_BSAVE) {
fprintf(stderr,"%s %s BSAVE "
"file_name apple_filename\n\n",
argv[0],image);
if (argc==6+extra_ops) {
if (strlen(argv[firstarg+4])>30) {
fprintf(stderr,
"Warning! Truncating filename "
"to 30 chars!\n");
}
strncpy(apple_filename,argv[firstarg+4],30);
apple_filename[30]=0;
else {
fprintf(stderr,"%s %s SAVE type "
"file_name apple_filename\n\n",
argv[0],image);
}
goto exit_and_close;
}
strncpy(local_filename,argv[optind],BUFSIZ);
optind++;
if (debug) printf("\tLocal filename: %s\n",local_filename);
if (argc>optind) {
/* apple filename specified */
truncate_filename(apple_filename,argv[optind]);
}
else {
/* If no filename specified for apple name */
/* Then use the input name. Note, we strip */
/* everything up to the last slash so useless */
/* path info isn't used */
{
char *temp;
temp=argv[firstarg+3]+(strlen(argv[firstarg+3])-1);
while(temp!=argv[firstarg+3]) {
temp--;
if (*temp == '/') {
temp++;
break;
}
}
if (strlen(temp)>30) {
fprintf(stderr,
"Warning! Truncating filename to 30 chars!\n");
}
strncpy(apple_filename,temp,30);
apple_filename[30]=0;
}
}
catalog_entry=dos33_check_file_exists(dos_fd,apple_filename,
FILE_NORMAL);
if (catalog_entry>=0) {
fprintf(stderr,"Warning! %s exists!\n",apple_filename);
if (!always_yes) {
printf("Over-write (y/n)?");
result_string=fgets(temp_string,BUFSIZ,stdin);
if ((result_string==NULL) || (temp_string[0]!='y')) {
printf("Exiting early...\n");
goto exit_and_close;
}
}
fprintf(stderr,"Deleting previous version...\n");
dos33_delete_file(dos_fd,catalog_entry);
}
dos33_add_file(dos_fd,type,argv[firstarg+3],apple_filename);
temp=local_filename+(strlen(local_filename)-1);
while(temp!=local_filename) {
temp--;
if (*temp == '/') {
temp++;
break;
}
}
truncate_filename(apple_filename,temp);
}
if (debug) printf("\tApple filename: %s\n",apple_filename);
catalog_entry=dos33_check_file_exists(dos_fd,apple_filename,
FILE_NORMAL);
if (catalog_entry>=0) {
fprintf(stderr,"Warning! %s exists!\n",apple_filename);
if (!always_yes) {
printf("Over-write (y/n)?");
result_string=fgets(temp_string,BUFSIZ,stdin);
if ((result_string==NULL) || (temp_string[0]!='y')) {
printf("Exiting early...\n");
goto exit_and_close;
}
}
fprintf(stderr,"Deleting previous version...\n");
dos33_delete_file(dos_fd,catalog_entry);
}
if (command==COMMAND_SAVE) {
dos33_add_file(dos_fd,type,
ADD_RAW, address, length,
local_filename,apple_filename);
}
else {
dos33_add_file(dos_fd,type,
ADD_BINARY, address, length,
local_filename,apple_filename);
}
break;
case COMMAND_DELETE:
if (argc==optind) {
fprintf(stderr,"Error! Need file_name\n");
fprintf(stderr,"%s %s DELETE apple_filename\n",
argv[0],image);
goto exit_and_close;
}
truncate_filename(apple_filename,argv[optind]);
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr, "Error! File %s does not exist\n",
apple_filename);
goto exit_and_close;
}
dos33_delete_file(dos_fd,catalog_entry);
break;
case COMMAND_DELETE:
if (argc+extra_ops<4) {
fprintf(stderr,"Error! Need file_name\n");
fprintf(stderr,"%s %s DELETE apple_filename\n",argv[0],image);
goto exit_and_close;
}
catalog_entry=dos33_check_file_exists(dos_fd,argv[firstarg+2],
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,
"Error! File %s does not exist\n",argv[firstarg+2]);
goto exit_and_close;
}
dos33_delete_file(dos_fd,catalog_entry);
break;
case COMMAND_DUMP:
printf("Dumping %s!\n",argv[firstarg]);
dos33_dump(dos_fd);
break;
case COMMAND_LOCK:
case COMMAND_UNLOCK:
/* check and make sure we have apple_filename */
if (argc<4+extra_ops) {
fprintf(stderr,"Error! Need apple file_name\n");
fprintf(stderr,"%s %s LOCK apple_filename\n",argv[0],image);
goto exit_and_close;
}
/* Truncate filename if too long */
if (strlen(argv[firstarg+2])>30) {
fprintf(stderr,
"Warning! Truncating %s to 30 chars\n",argv[firstarg+2]);
}
strncpy(apple_filename,argv[firstarg+2],30);
apple_filename[30]='\0';
/* get the entry/track/sector for file */
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,"Error! %s not found!\n",apple_filename);
goto exit_and_close;
}
case COMMAND_DUMP:
printf("Dumping %s!\n",image);
dos33_dump(dos_fd);
break;
dos33_lock_file(dos_fd,catalog_entry,command==COMMAND_LOCK);
break;
case COMMAND_RENAME:
/* check and make sure we have apple_filename */
if (argc<5+extra_ops) {
fprintf(stderr,"Error! Need two filenames\n");
fprintf(stderr,"%s %s LOCK apple_filename_old "
"apple_filename_new\n",
argv[0],image);
goto exit_and_close;
}
/* Truncate filename if too long */
if (strlen(argv[firstarg+2])>30) {
fprintf(stderr,
"Warning! Truncating %s to 30 chars\n",argv[firstarg+2]);
}
strncpy(apple_filename,argv[firstarg+2],30);
apple_filename[30]='\0';
/* Truncate filename if too long */
if (strlen(argv[firstarg+3])>30) {
fprintf(stderr,
"Warning! Truncating %s to 30 chars\n",argv[firstarg+3]);
}
strncpy(new_filename,argv[firstarg+3],30);
new_filename[30]='\0';
/* get the entry/track/sector for file */
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,"Error! %s not found!\n",apple_filename);
goto exit_and_close;
}
case COMMAND_LOCK:
case COMMAND_UNLOCK:
/* check and make sure we have apple_filename */
if (argc==optind) {
fprintf(stderr,"Error! Need apple file_name\n");
fprintf(stderr,"%s %s %s apple_filename\n",
argv[0],image,temp_string);
goto exit_and_close;
}
dos33_rename_file(dos_fd,catalog_entry,new_filename);
break;
truncate_filename(apple_filename,argv[optind]);
/* get the entry/track/sector for file */
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,"Error! %s not found!\n",
apple_filename);
goto exit_and_close;
}
dos33_lock_file(dos_fd,catalog_entry,command==COMMAND_LOCK);
break;
case COMMAND_RENAME:
/* check and make sure we have apple_filename */
if (argc==optind) {
fprintf(stderr,"Error! Need two filenames\n");
fprintf(stderr,"%s %s LOCK apple_filename_old "
"apple_filename_new\n",
argv[0],image);
goto exit_and_close;
}
/* Truncate filename if too long */
truncate_filename(apple_filename,argv[optind]);
optind++;
if (argc==optind) {
fprintf(stderr,"Error! Need two filenames\n");
fprintf(stderr,"%s %s LOCK apple_filename_old "
"apple_filename_new\n",
argv[0],image);
goto exit_and_close;
}
truncate_filename(new_filename,argv[optind]);
/* get the entry/track/sector for file */
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,"Error! %s not found!\n",
apple_filename);
goto exit_and_close;
}
dos33_rename_file(dos_fd,catalog_entry,new_filename);
break;
case COMMAND_UNDELETE:
/* check and make sure we have apple_filename */
if (argc<4) {
if (argc==optind) {
fprintf(stderr,"Error! Need apple file_name\n");
fprintf(stderr,"%s %s LOCK apple_filename\n",argv[0],image);
fprintf(stderr,"%s %s UNDELETE apple_filename\n\n",
argv[0],image);
goto exit_and_close;
}
/* Truncate filename if too long */
/* what to do about last char ? */
if (strlen(argv[firstarg+2])>30) {
fprintf(stderr,
"Warning! Truncating %s to 30 chars\n",argv[firstarg+2]);
}
strncpy(apple_filename,argv[firstarg+2],30);
apple_filename[30]='\0';
truncate_filename(apple_filename,argv[optind]);
/* get the entry/track/sector for file */
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_DELETED);
if (catalog_entry<0) {
fprintf(stderr,"Error! %s not found!\n",apple_filename);
fprintf(stderr,"Error! %s not found!\n",
apple_filename);
goto exit_and_close;
}
dos33_undelete_file(dos_fd,catalog_entry,apple_filename);
break;
case COMMAND_HELLO:
if (argc+extra_ops<4) {
fprintf(stderr,"Error! Need file_name\n");
fprintf(stderr,"%s %s HELLO apple_filename\n",argv[0],image);
goto exit_and_close;
}
catalog_entry=dos33_check_file_exists(dos_fd,argv[firstarg+2],
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,
"Warning! File %s does not exist\n",argv[firstarg+2]);
}
dos33_rename_hello(dos_fd,argv[firstarg+2]);
break;
case COMMAND_INIT:
/* use common code from mkdos33fs? */
case COMMAND_COPY:
/* use temp file? Walking a sector at a time seems a pain */
default:
fprintf(stderr,"Sorry, unsupported command\n");
case COMMAND_HELLO:
if (argc==optind) {
fprintf(stderr,"Error! Need file_name\n");
fprintf(stderr,"%s %s HELLO apple_filename\n\n",
argv[0],image);
goto exit_and_close;
}
truncate_filename(apple_filename,argv[optind]);
catalog_entry=dos33_check_file_exists(dos_fd,
apple_filename,
FILE_NORMAL);
if (catalog_entry<0) {
fprintf(stderr,
"Warning! File %s does not exist\n",
apple_filename);
}
dos33_rename_hello(dos_fd,apple_filename);
break;
case COMMAND_INIT:
/* use common code from mkdos33fs? */
case COMMAND_COPY:
/* use temp file? Walking a sector at a time seems a pain */
default:
fprintf(stderr,"Sorry, unsupported command %s\n\n",temp_string);
goto exit_and_close;
}
exit_and_close:
close(dos_fd);
exit_program:
return 0;
}

View File

@ -1,2 +1,4 @@
Test hello
Test init
Test copy
Test over-writing existing file

View File

@ -4,38 +4,33 @@ MAKEB = ../dos33fs-utils/make_b
all: ethernet.dsk
memcpy: memcpy.o
ld65 -o memcpy memcpy.o -t none
memcpy.o: memcpy.s
ca65 -o memcpy.o memcpy.s -l memcpy.lst
SETUP.BAS: setup.bas
$(TXT2BAS) < setup.bas > SETUP.BAS
WEBSERVER.BAS: webserver.bas
$(TXT2BAS) < webserver.bas > WEBSERVER.BAS
about.html: ./c/about.html
$(MAKEB) ./c/about.html about.html 0xc000
index.html: ./c/index.html
$(MAKEB) ./c/index.html index.html 0xc000
favicon.ico: ./c/favicon.ico
$(MAKEB) ./c/favicon.ico favicon.ico 0xc000
vmw_logo.png: ./c/vmw_logo.png
$(MAKEB) ./c/vmw_logo.png vmw_logo.png 0xc000
R.TXT: request.txt
$(MAKEB) request.txt R.TXT 0xc000
ethernet.dsk: SETUP.BAS \
WEBSERVER.BAS \
R.TXT \
about.html index.html favicon.ico vmw_logo.png
./c/about.html ./c/index.html ./c/favicon.ico ./c/vmw_logo.png
$(DOS33) -y ethernet.dsk SAVE A SETUP.BAS
$(DOS33) -y ethernet.dsk SAVE A WEBSERVER.BAS
$(DOS33) -y ethernet.dsk SAVE B R.TXT
$(DOS33) -y ethernet.dsk SAVE B about.html
$(DOS33) -y ethernet.dsk SAVE B index.html
$(DOS33) -y ethernet.dsk SAVE B favicon.ico
$(DOS33) -y ethernet.dsk SAVE B vmw_logo.png
$(DOS33) -y ethernet.dsk BSAVE R.TXT
$(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/about.html
$(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/index.html
$(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/favicon.ico
$(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/vmw_logo.png
clean:
rm -f *~ *.BAS R.TXT
rm -f *~ *.BAS R.TXT *.o *.lst memcpy

View File

@ -1,2 +1,29 @@
Working on getting the Uthernet II card to do something interesting.
http://a2retrosystems.com/
Hardware Background:
This board has a WIZnet W5100 on board. You can get raw Ethernet
packets on the board, but I am using it in hardware TCP/IP mode
where I set up the MAC/IP and then get raw packets from a TCP socket
(up to 4 sockets can be active at once).
Webserver:
Included is a webserver written for Fall 2015 ECE435
It is written entirely in Applesoft BASIC
It runs very slowly, but works.
firefox and wget can get files just fine,
although they tend to send duplicate requests for some reason.
You can serve arbitrary png, jpg, txt, or html files, however
they currently have to be less than 8kB.
Much of the slowness is using peek/poke as a memcpy routine.
Of course this would all be faster in assembly language, but
what's the fun of that.

Binary file not shown.

66
ethernet/memcpy.s Normal file
View File

@ -0,0 +1,66 @@
.define EQU =
PTR EQU $06
PTRH EQU $07
WRAPL EQU $08
WRAPH EQU $09
SIZEL EQU $0A
SIZEH EQU $0B
tx_copy:
lda #0 ; always copying from 0x4000
sta PTR
lda #$40
sta PTR+1
ldx #SIZEH ; number of 256-byte blocks
beq copy_remainder ; if none, skip ahead
ldy #0
copy256:
lda (PTR),y
sta $C0B7 ; change based on uthernet slot
cmp WRAPH,x
bne nowrap256
cmp WRAPL,y
bne nowrap256
lda #$40
sta $C0B5
lda #$00
sta $C0B6 ; wrap tx buffer address to 0x4000
nowrap256:
iny
bne copy256
inc PTR+1 ; update 16-bit pointer
dex ; finish a 256 byte block
bne copy256
ldx #SIZEL
copy_remainder:
lda (PTR),y
sta $C0B7 ; change based on uthernet slot
cmp WRAPL,y
bne nowrap_r
lda #$40
sta $C0B5
lda #$00
sta $C0B6 ; wrap tx buffer address to 0x4000
nowrap_r:
iny
dex
bne copy_remainder
rts

46
ethernet/memcpy.txt Normal file
View File

@ -0,0 +1,46 @@
Test 1:
5 FOR J=1 to 1000: NEXT J
10 PRINT CHR$(7)
20 FOR I=16384 to 20479
30 POKE 20480,PEEK(I)
40 NEXT I
100 PRINT CHR$(7)
Time (linapple2) 38s
All one one line
5 FOR J=1 to 1000: NEXT J
10 PRINT CHR$(7)
20 FOR I=16384 to 20479
30 POKE 20480,PEEK(I)
40 NEXT I
100 PRINT CHR$(7)
Time (linapple2) 37s
Assembly language:
PTR EQU $06
lda #0
sta PTR
lda #$40
sta PTR+1
ldx #8
ldy #0
copy_loop:
lda (PTR),y
sta $5000
iny
bne copy_loop
dex
bne copy_loop
rts
Runs more or less instantaenously

View File

@ -1,30 +1,48 @@
' Applesoft BASIC Webserver
' by Vince Weaver <vince@deater.net>
'
1 REM *** Setup UTHERNET II - W5100
2 REM *** Assumes slot 5 ($C0D0)
3 SLOT=49360: REM *** $C0D0
4 MR=SLOT+4: REM *** MODE REGISTER C0D4
5 HA=SLOT+5:LA=SLOT+6: REM *** HIGH/LOW ADDR $C0D5,$C0D6
7 DP=SLOT+7: REM *** DATA PORT $C0D7
' SLOT0=$C080 49280 SLOT4=$C0C0 49344
' SLOT1=$C090 49296 SLOT5=$C0D0 49360
' SLOT2=$C0A0 49312 SLOT6=$C0E0 49376
' SLOT3=$C0B0 49328 SLOT7=$C0F0 49392
'
' Set up the memory addresses to use
'
2 REM *** OURS IS IN SLOT3 ($C0B0)
3 SLOT=49328: REM *** $C0B0
4 MR=SLOT+4: REM *** MODE REGISTER C0B4
5 HA=SLOT+5:LA=SLOT+6: REM *** HIGH/LOW ADDR $C0B5,$C0B6
7 DP=SLOT+7: REM *** DATA PORT $C0B7
'
' Init the W5100
'
10 REM *** Init W5100
12 POKE MR,128 : REM RESET W5100
14 POKE MR,3 : REM AUTOINCREMENT
20 REM *** Setup MAC Address
21 REM *** 41:50:50:4c:45:32
20 REM *** Setup MAC Address 41:50:50:4c:45:32
22 POKE HA,0:POKE LA,9
23 POKE DP,65
23 POKE DP,80
23 POKE DP,80
23 POKE DP,76
23 POKE DP,69
23 POKE DP,50
30 REM *** Setup IP Address
31 REM *** 192.168.8.15
23 POKE DP,65:POKE DP,80:POKE DP,80:POKE DP,76:POKE DP,69:POKE DP,50
30 REM *** Setup IP Address 192.168.8.15
32 POKE LA,15
33 POKE DP,192
34 POKE DP,168
35 POKE DP,8
36 POKE DP,15
33 POKE DP,192:POKE DP,168:POKE DP,8:POKE DP,15
40 PRINT "UTHERNET II READY: 192.168.8.15"
100 REM *** Setup Socket
'
' Setup Machine Language Memcpy routine
' NOTE! This code assumes the Uthernet is in slot 3
' FIXME: patch on the fly once it works
' See Appendix 1 at the end of this for more details
'
50 FOR I=0 TO 72: READ X: POKE 768+I,X:NEXT I
51 DATA 169,0,133,6,169,64,133,7,162,11,240,36,160,0,177,6
52 DATA 141,183,192,213,9,208,15,217,8,0,208,10,169,64,141,181
53 DATA 192,169,0,141,182,192,200,208,229,230,7,202,208,224,162,10
54 DATA 177,6,141,183,192,217,8,0,208,10,169,64,141,181,192,169
55 DATA 0,141,182,192,200,202,208,232,96
'
' Setup Socket 0
'
100 REM *** Setup Socket 0
102 PRINT "** Setting up Socket 0"
105 POKE HA,0:POKE LA,26: REM RX MEMSIZE
110 POKE DP,3: REM 8kB RX buffer
@ -36,106 +54,353 @@
303 PRINT "** Setting up to use TCP port 80"
305 POKE HA,4: POKE LA,4: REM *** 0x404 port
310 POKE DP,0:POKE DP, 80: REM *** http port 80
'
' OPEN the socket
'
400 REM *** OPEN socket
404 PRINT "** OPENing socket"
405 POKE HA,4: POKE LA,1: REM *** 0x401 command register
410 POKE DP, 1: REM *** OPEN
'
' Check return value
'
500 REM *** Check if opened
505 POKE HA,4: POKE LA,3: REM *** 0x403 status register
510 RE=PEEK(DP)
515 PRINT "** STATUS IS ";RE;
520 IF RE=19 THEN PRINT " OPENED":GOTO 600
530 IF RE=0 THEN PRINT " CLOSED, ERROR"
540 POKE HA,4: POKE LA,1: REM *** 0x401 command register
550 POKE DP, 16: REM *** CLOSE
560 END
530 IF RE=0 THEN PRINT " CLOSED, ERROR": GOTO 5000
540 PRINT "UNKNOWN ERROR ";RE
550 GOTO 5000
'
' LISTEN on the socket
'
600 REM *** Connection opened, Listen
605 POKE HA,4: POKE LA,1: REM *** 0x401 command register
610 POKE DP, 2: REM *** LISTEN
'
' Check return value
'
620 REM *** Check if successful
625 POKE HA,4: POKE LA,3: REM *** 0x403 status register
630 RE=PEEK(DP)
635 PRINT "** STATUS IS ";RE;
640 IF RE=20 THEN PRINT " LISTENING":GOTO 700
650 IF RE=0 THEN PRINT " CLOSED, ERROR"
655 PRINT "UNKNOWN"
660 POKE HA,4: POKE LA,1: REM *** 0x401 command register
670 POKE DP, 16: REM *** CLOSE
675 END
650 IF RE=0 THEN PRINT " CLOSED, ERROR":GOTO 5000
655 PRINT "UNKNOWN ERROR ";RE
675 GOTO 5000
'
' Wait for incoming connection
'
700 REM *** Wait for incoming connection
705 POKE HA,4: POKE LA,1: REM *** 0x401 command register
710 POKE DP, 2: REM *** LISTEN
'
' Check for result
'
720 REM *** Check if successful
725 POKE HA,4: POKE LA,3: REM *** 0x403 status register
730 RE=PEEK(DP)
740 IF RE=23 THEN GOTO 800
745 IF RE<>20 THEN PRINT "WAITING: STATUS=";RE
740 IF RE=23 THEN GOTO 800: REM ESTABLISHED
745 IF RE<>20 THEN PRINT "WAITING: UNEXPECTED STATUS=";RE
750 GOTO 700: REM *** Repeat until connected
'
800 PRINT "CONNECTED"
' Established, repeat waiting for incoming data
'
800 PRINT "ESTABLISHED"
802 POKE HA,4: POKE LA,38: REM *** 0x426 Received Size
805 SH=PEEK(DP):SL=PEEK(DP)
810 SI=(SH*256)+SL
820 IF SI<>0 THEN GOTO 900
'
' Should we delay? busy polling seems wasteful
'
830 REM DELAY?
840 GOTO 800
840 GOTO 802
'
' We have some data, let's read it
'
900 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr
905 OH=PEEK(DP):OL=PEEK(DP)
910 RO=(OH*256)+OL
920 REM *** SHOULD MASK WITH 0x1ff but how?
930 RA=RO+24576:REM $6000
940 PRINT "READ OFFSET=";RO;" READ ADDRESS=";RA;" READ SIZE=";SI
910 RF=(OH*256)+OL
920 REM *** MASK WITH 0x1ff
925 R%=RF/8192:RM=RF-(8192*R%)
930 RA=RM+24576:REM $6000
940 PRINT "READ OFFSET=";RM;" READ ADDRESS=";RA;" READ SIZE=";SI
'
' Check for buffer wraparound
'
942 BW=0
945 IF (SI+TA>=32768) THEN BW=1:BO=32768-TA:PRINT "RX BUFFER WRAPAROUND IN ";BO
'
' Print received packet
'
1000 REM *** PRINT PACKET
1005 POKE HA,RA/256: POKE LA,RA-((RA/256)*256)
1001 FL=1:FL$=""
1003 R%=RA/256
1005 POKE HA,R%: POKE LA,RA-(R%*256)
1010 FOR I=1 TO SI
1020 C=PEEK(DP)
1030 IF C<>13 THEN PRINT CHR$(C);
1020 C=PEEK(DP):C$=CHR$(C)
1025 IF FL=1 THEN FL$=FL$+C$
1027 IF C=10 THEN FL=0
1030 IF C<>10 THEN PRINT C$;
1032 IF BW=0 THEN GOTO 1040
1033 BO=BO-1: IF BO=0 THEN POKE HA,96:POKE LA,0:BW=0
1040 NEXT I
'
' Deal with first line
'
1050 PRINT "FIRST LINE=";FL$
1060 IF LEFT$(FL$,3)<>"GET" GOTO 7000
1065 N$=""
1070 FOR I=6 TO LEN(FL$)
1075 M$=MID$(FL$,I,1)
1080 IF M$=" " GOTO 1090
1085 N$=N$+M$
1087 NEXT I
1090 IF N$="" THEN N$="index.html"
1095 PRINT "SENDING FILE: ";N$
'
' TODO: handle wraparound of 8kb buffer
'
'
' Update read pointer
'
1100 REM *** Update read pointer
'"HTTP/1.1 200 OK\r\n"
'"Date: %s\r\n"
'"Server: VMW-web\r\n"
'"Last-Modified: %s\r\n"
'"Content-Length: %ld\r\n"
'"Content-Type: %s\r\n"
'"\r\n",
1200 REM *** SEND RESPONSE
1205 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10)
1210 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10)
1220 A$=A$+"Content-Length: 65"+CHR$(13)+CHR$(10)
1230 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10)
1250 A$=A$+CHR$(13)+CHR$(10)
1260 A$=A$+"<html><head>test</head><body><h3>Apple2 Test</h3></body></html>"
1270 A$=A$+CHR$(13)+CHR$(10)
1280 PRINT "SENDING:":PRINT A$
' TODO: read TX free size reg (0x420)
1900 POKE HA,4: POKE LA,34: REM *** 0x422 TX read ptr
1110 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr
1120 RA=RF+SI
1130 R%=RA/256
1140 POKE DP,R%: POKE DP,RA-(R%*256)
1150 REM *** RECEIVE
1160 POKE HA,4: POKE LA,1: REM *** 0x401 command register
1170 POKE DP, 64: REM *** RECV
'
' Load file from disk
'
1200 REM *** LOAD FILE
1202 X$=RIGHT$(N$,3):M$="text/html"
1203 IF X$="txt" THEN M$="text/plain"
1204 IF X$="png" THEN M$="image/png"
1205 IF X$="jpg" THEN M$="image/jpg"
1206 IF X$="ico" THEN M$="image/x-icon"
1207 IF N$="teapot.html" GOTO 9000
1208 ONERR GOTO 8000
1209 PRINT "LOADING ";N$
1210 PRINT CHR$(4)+"BLOAD ";N$
1215 POKE 216,0: REM CANCEL ONERR
1220 FS=PEEK(43616)+256*PEEK(43617): REM FILESIZE
1225 PRINT "DONE LOADING"
' assume loaded at 0x4000, text page 2
' and that max size is 8kb
1240 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10)
1250 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10)
1260 A$=A$+"Content-Length: "+STR$(FS)+CHR$(13)+CHR$(10)
1280 A$=A$+"Content-Type: "+M$+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10)
'
1380 PRINT "SENDING:":PRINT A$
1385 C=0
'
' read TX free size reg (0x420)
'
1700 SI=LEN(A$)+FS
1710 IF (SI>8192) THEN PRINT "FILE TOO BIG!": REM GOTO 403?
1800 POKE HA,4: POKE LA,32: REM *** 0x420 FREESIZE
1810 OH=PEEK(DP):OL=PEEK(DP)
1815 FR=(OH*256)+OL
1820 PRINT "FREE: ";FR
1830 IF SI>FR GOTO 1800: REM REPEAT UNTIL FREE
'
' Read tx offset
'
1900 POKE HA,4: POKE LA,36: REM *** 0x424 TX write ptr
1905 OH=PEEK(DP):OL=PEEK(DP)
1910 TF=(OH*256)+OL
1920 REM *** SHOULD MASK WITH 0x1ff
1925 T%=TF/8192:TF=TF-(8192*T%)
1930 TA=TF+16384:REM $4000
1935 SI=LEN(A$)
1940 PRINT "TX OFFSET=";TF;" TX ADDRESS=";TA;" TX SIZE=";SI
1920 REM *** MASK WITH 0x1ff
1925 T%=TF/8192:TM=TF-(8192*T%)
1930 TA=TM+16384:REM $4000
1940 PRINT "OH/OL=";OH;"/";OL;" TX OFFSET=";TM;" TX ADDRESS=";TA;" TX SIZE=";SI
'
' Check for buffer wraparound
'
1942 BW=0:BO=0
1945 IF (SI+TA>=24576) THEN BW=1:BO=24576-TA:PRINT "TX BUFFER WRAPAROUND IN ";BO
'
' Write data to TX buffer
' First write header
'
2000 T%=TA/256
2005 POKE HA,T%: POKE LA,TA-(T%*256)
2010 FOR I=1 TO SI
2020 POKE DP,ASC(MID$(A$,I,1))
2040 NEXT I
2010 FOR I=1 TO LEN(A$)
2015 POKE DP,ASC(MID$(A$,I,1))
2017 IF BW=0 THEN GOTO 2020
2018 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0
2020 NEXT I
'
' Write disk part
'
2025 FOR I=1 TO FS
2026 C=C+1: IF C=50 THEN PRINT ".";:C=0
2030 POKE DP,PEEK(16383+I)
2032 IF BW=0 THEN GOTO 2035
2033 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0
2035 NEXT I
2040 PRINT
'
' The above is slow
' Intead use our machine language routine
'
'2025 B%=BO/256:POKE 9,B%:POKE 8,BO-(B%*256)
'2027 B%=FS/256:POKE 11,B%:POKE 10,FS-(B%*256)
'2030 CALL 768
'
' Update TX write ptr
'
2050 REM ** UPDATE TX WRITE PTR
2060 POKE HA,4: POKE LA,36: REM *** 0x424 TX write ptr
2075 TA=TA+SI
2075 TA=TF+SI
2080 T%=TA/256
2085 POKE HA,T%: POKE LA,TA-(T%*256)
2085 POKE DP,T%: POKE DP,TA-(T%*256)
2090 PRINT "UPDATE TX TO ";T%;"/";TA-(T%*256)
'
' SEND packet
'
2100 REM *** SEND
2102 PRINT "SENDING"
2105 POKE HA,4: POKE LA,1: REM *** 0x401 command register
2110 POKE DP, 32: REM *** SEND
5000 REM *** CLOSE
'
' Return to reading
'
4000 REM *** Check if successful
4010 POKE HA,4: POKE LA,3: REM *** 0x403 status register
4020 RE=PEEK(DP)
4030 PRINT "STATUS AFTER SEND ";RE
4035 IF RE=28 THEN GOTO 6000: REM CLOSE_WAIT
4040 IF RE=0 THEN GOTO 400: REM CLOSED
4060 REM *** RECEIVE
4075 POKE HA,4: POKE LA,1: REM *** 0x401 command register
4080 POKE DP, 64: REM *** RECV
4090 GOTO 800
'
' Close the socket
'
5000 REM *** CLOSE AND EXIT
5010 POKE HA,4: POKE LA,1: REM *** 0x401 command register
5020 POKE DP, 16: REM *** CLOSE
5030 END
6000 REM *** CLOSE AND RELISTEN
6010 POKE HA,4: POKE LA,1: REM *** 0x401 command register
6020 POKE DP, 16: REM *** CLOSE
' Check status?
6030 GOTO 400
'
'
' ERROR MESSAGES
'
'
7000 REM 400 BAD REQUEST
7005 S$="400 Bad Request"
7010 M$="<html><head><title>400 Bad Request</title></head><body><h1>Bad Request</h1><p>Your browser sent a request that this server could not understand.<br /></p></body></html>"+CHR$(13)+CHR$(10)
7020 GOTO 9100
8000 REM 404 NOT FOUND
8003 POKE 216,0: REM CANCEL ONERR
8004 PRINT "DISK ERROR: ";PEEK(222)
8005 S$="404 Not Found"
8010 M$="<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>File not found.<br /></p></body></html>"+CHR$(13)+CHR$(10)
8020 GOTO 9100
9000 REM 418 TEAPOT
9005 S$="418 I'm a Teapot"
9010 M$="<html><head><title>418 I'm a Teapot</title></head><body><h1>I'm a Teapot</h1><p>Short *and* stout.<br /></p></body></html>"+CHR$(13)+CHR$(10)
'
' Make header
'
9100 A$="HTTP/1.1 "+S$+CHR$(13)+CHR$(10)+"Server: VMW-web"+CHR$(13)+CHR$(10)
9105 A$=A$+"Content-Length: "+STR$(LEN(M$))+CHR$(13)+CHR$(10)
9110 A$=A$+"Connection: close"+CHR$(13)+CHR$(10)+"Content-Type: text/html; charset=iso-8859-1"+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10)
' Poke as if we had loaded from disk
9200 FS=LEN(M$)
9210 FOR I=1 TO FS
9220 POKE 16383+I,ASC(MID$(M$,I,1))
9300 NEXT I
9310 GOTO 1380
'
' STATUSES
' p28 of W5100 manual
' 0x0 0 SOCK_CLOSED
' 0x13 SOCK_INIT
' 0x14 SOCK_LISTEN
' 0x17 23 SOCK_ESTABLISHED
' 0x1C 28 SOCK_CLOSE_WAIT
' 0x22 SOCK_UDP
' 0x32 SOCK_IPRAW
' 0x42 SOCK_MACRAW
' 0x5f SOCK_PPOE
'
' Appendix 1: The memcpy machine code
'
'
'PTR EQU $06
'PTRH EQU $07
'
'WRAPL EQU $08
'WRAPH EQU $09
'
'SIZEL EQU $0A
'SIZEH EQU $0B
'
'tx_copy:
'
' lda #0 ; always copying from 0x4000
' sta PTR
' lda #$40
' sta PTR+1
'
' ldx #SIZEH ; number of 256-byte blocks
' beq copy_remainder ; if none, skip ahead
'
' ldy #0
'copy256:
' lda (PTR),y
' sta $C0B7 ; change based on uthernet slot
'
' cmp WRAPH,x
' bne nowrap256
'
' cmp WRAPL,y
' bne nowrap256
'
' lda #$40
' sta $C0B5
' lda #$00
' sta $C0B6 ; wrap tx buffer address to 0x4000
'
'nowrap256:
' iny
' bne copy256
'
' inc PTR+1 ; update 16-bit pointer
' dex ; finish a 256 byte block
' bne copy256
'
' ldx #SIZEL
'copy_remainder:
' lda (PTR),y
' sta $C0B7 ; change based on uthernet slot
'
' cmp WRAPL,y
' bne nowrap_r
'
' lda #$40
' sta $C0B5
' lda #$00
' sta $C0B6 ; wrap tx buffer address to 0x4000
'
'nowrap_r:
' iny
' dex
' bne copy_remainder
'
' rts