Initial commit
[pdp8.git] / sw / speed8 / pc / rktool.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <getopt.h>
9
10 #include "speed8.h"
11 #include "link.h"
12 #include "rk05.h"
13 #include "memory.h"
14 #include "log.h"
15
16 #define PORT "/dev/ttyUSB0"
17
18 int fd;
19
20 static const struct option longopts[]={
21 {"help",0,NULL,'h'},
22 {"read",0,NULL,'r'},
23 {"write",0,NULL,'w'},
24 {"verbose",0,NULL,'v'},
25 {"port",1,NULL,'p'},
26 {"drive",1,NULL,'d'},
27 {"quiet",0,NULL,'q'},
28 {"loglevel",1,NULL,'l'},
29 {"verify",0,NULL,'V'},
30 {NULL}
31 };
32
33 static const char optstring[]="hrwvp:d:l:qV";
34
35 static void help(void){
36 fprintf(stderr, "\
37 \n\
38 Usage: rktool {-r|-w} [-v] [-V] [-h] [-d<unit_number>] [-l<loglevel>] <imagefile>\n\
39 \n\
40 This tool will help you to backup restore RK05 media on a PDP8 running speed8.\n\
41 \n\
42 Options:\n\
43 \n\
44 -r, --read Read disk (default if nothing specified)\n\
45 -w, --write Write disk\n\
46 -d, --drive= Select drive number 0-3 (defaults to 0)\n\
47 -p, --port= Serial port to use (defaults to /dev/ttyUSB0)\n\
48 -V, --verify Verify after read or write\n\
49 -v, --verbose Be verbose\n\
50 -q, --quiet Be quiet, opposite of -v\n\
51 -l, --loglevel= Set loglevel for debugging purposes\n\
52 -h, --help Display this help and exit\n\
53 \n\
54 ");
55 exit(100);
56 }
57
58 static char defaultport[]=PORT;
59
60 int main(int argc, char ** argv){
61 int res;
62 int e;
63
64 int drive=0;
65 #define READ 0
66 #define WRITE 1
67 int action=READ;
68 char * port=defaultport;
69 char * file=NULL;
70 int verify=0;
71 char opt;
72
73 opterr=1;
74 opt=getopt_long(argc,argv,optstring,longopts,NULL);
75
76 while(opt>0){
77 switch(opt){
78 case 'v':
79 loglevel++;
80 break;
81 case 'h':
82 help();
83 break;
84 case 'r':
85 action=READ;
86 break;
87 case 'w':
88 action=WRITE;
89 break;
90 case 'p':
91 if (!optarg) {
92 error("-p needs an argument!\n");
93 exit(1);
94 }
95 port=optarg;
96 break;
97 case 'd':
98 if (!optarg) {
99 error("-d needs an argument!\n");
100 exit(1);
101 }
102 drive=strtol(optarg, NULL, 0);
103 break;
104 case 'q':
105 loglevel=LL_QUIET;
106 break;
107 case 'l':
108 if (!optarg) {
109 error("-l needs an argument!\n");
110 exit(1);
111 }
112 loglevel=strtol(optarg,NULL,0);
113 break;
114 case 'V':
115 verify=1;
116 break;
117 case '?':
118 help();
119 break;
120 }
121 opt=getopt_long(argc,argv,optstring,longopts,NULL);
122 }
123
124 file=argv[optind];
125
126 if (!file) {
127 fprintf(stderr,"Error: No file specified!\n");
128 help();
129 }
130
131 debug("Opening port \"%s\".\n",port);
132 debug("Image file: %s\n", file);
133 debug("Flushing first\n");
134
135 res=link_flush(port);
136
137 if (res <0){
138 ERROR perror("While initializing link");
139 return -1;
140 }
141 debug("Opening for real now\n");
142 res=link_open(port);
143 if (res <0){
144 ERROR perror("While initializing link");
145 return -1;
146 }
147
148 if (action==WRITE){
149 uint16_t origin[RK05_DISKSIZE];
150 uint16_t readback[RK05_DISKSIZE];
151
152 int fd=open(file,O_RDONLY);
153 if (fd<0){
154 ERROR perror("While opening file");
155 exit(2);
156 }
157 res=read(fd,(char*)origin,sizeof(origin));
158 WARN if (res<RK05_DISKSIZE*2)
159 warn("Read only %i bytes! Hope, that's ok.\n",res);
160 close(fd);
161
162 res=rk05_write_disk(drive,origin);
163 if(res<0){
164 ERROR perror("While writing disk image");
165 exit(3);
166 }
167
168 if (verify){
169 info("Reading back image.\n");
170 res=rk05_read_disk(drive,readback);
171 if(res<0){
172 ERROR perror("While reading disk image");
173 exit(3);
174 }
175 int i;
176 e=0;
177 int cylinder,side,sector,word;
178 for (cylinder=0; cylinder<RK05_CYLINDERS;cylinder++)
179 for (side=0; side<1; side++)
180 for (sector=0; sector<16; sector++)
181 for (word=0; word<256; word++){
182 i=cylinder*2*16*256+side*16*256+sector*256+word;
183 if (readback[i]!=origin[i]){
184 error("Verify mismatch! Cylinder %i, Side %i, Sector %i, Word %i\n",
185 cylinder,side,sector,word);
186 e++;
187 }
188 }
189 if (e) {
190 error("Found %i verify errors!\n",e);
191 exit(3);
192 }
193 } // verify
194 } // WRITE
195
196 if (action==READ){
197
198 uint16_t target[RK05_DISKSIZE];
199 uint16_t target2[RK05_DISKSIZE];
200
201 info("Reading drive %i\n",drive);
202 res=0;
203 res=rk05_read_disk(drive,target);
204 if(res<0){
205 ERROR perror("While reading disk image");
206 exit(3);
207 }
208 if (verify){
209 e=0;
210 info("Reading again\n");
211 res=rk05_read_disk(drive,target2);
212 if(res<0){
213 ERROR perror("While reading disk image");
214 exit(3);
215 }
216 int i;
217 for (i=0; i<RK05_DISKSIZE ;i++){
218 debug("verify: %i\n",i);
219 if (target[i]!=target2[i]){
220 error("Verify mismatch! Cylinder %i, Side %i, Sector %i, Word %i\n",
221 i>>13,(i>>12)&1,(i>>8)&15,i&256);
222 e++;
223 }
224 }
225 }
226 int fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,0640);
227 if (fd<0){
228 ERROR perror("While opening file");
229 exit(2);
230 }
231 debug("File \"%s\" opened.\n",file);
232 res=write(fd,target,sizeof(target));
233 if (res!=sizeof(target)){
234 ERROR perror ("While writing file to disk");
235 exit(1);
236 }
237
238 }
239
240 link_close();
241 link_flush(file);
242 if (e) {
243 error("Found %i verify errors!\n",e);
244 exit(5);
245 }
246 return 0;
247 }