mirror of
https://github.com/deater/dos33fsprogs.git
synced 2025-01-26 16:33:43 +00:00
Merge branch 'master' of git://github.com/deater/dos33fsprogs
This commit is contained in:
commit
f1aab6e953
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
55
asoft_basic-utils/bin2data.c
Normal file
55
asoft_basic-utils/bin2data.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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,§or_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,§or_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;
|
||||
}
|
||||
|
@ -1,2 +1,4 @@
|
||||
Test hello
|
||||
Test init
|
||||
Test copy
|
||||
Test over-writing existing 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
|
||||
|
||||
|
@ -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
66
ethernet/memcpy.s
Normal 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
46
ethernet/memcpy.txt
Normal 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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user