/*
|
/*
|
* diskserv.c -- serial line disk server
|
* diskserv.c -- serial line disk server
|
*/
|
*/
|
|
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <termios.h>
|
#include <termios.h>
|
|
|
|
|
#define SERIAL_PORT "/dev/tty01"
|
|
|
|
#define SYN 0x16
|
#define SYN 0x16
|
#define ACK 0x06
|
#define ACK 0x06
|
|
|
#define RESULT_OK 0x00
|
#define RESULT_OK 0x00
|
#define RESULT_UNCMD 0x01
|
#define RESULT_UNCMD 0x01
|
#define RESULT_TOOBIG 0x02
|
#define RESULT_TOOBIG 0x02
|
#define RESULT_POSERR 0x03
|
#define RESULT_POSERR 0x03
|
#define RESULT_RDERR 0x04
|
#define RESULT_RDERR 0x04
|
#define RESULT_WRERR 0x05
|
#define RESULT_WRERR 0x05
|
|
|
|
|
static int debugCmds = 1;
|
static int debugCmds = 1;
|
static int debugData = 0;
|
static int debugData = 0;
|
|
|
static FILE *diskFile = NULL;
|
static FILE *diskFile = NULL;
|
static unsigned int numSectors;
|
static unsigned int numSectors;
|
static int sfd = 0;
|
static int sfd = 0;
|
static struct termios origOptions;
|
static struct termios origOptions;
|
static struct termios currOptions;
|
static struct termios currOptions;
|
|
|
|
|
void serialClose(void);
|
void serialClose(void);
|
|
|
|
|
void error(char *fmt, ...) {
|
void error(char *fmt, ...) {
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
printf("Error: ");
|
printf("Error: ");
|
vprintf(fmt, ap);
|
vprintf(fmt, ap);
|
printf("\n");
|
printf("\n");
|
va_end(ap);
|
va_end(ap);
|
if (diskFile != NULL) {
|
if (diskFile != NULL) {
|
fclose(diskFile);
|
fclose(diskFile);
|
diskFile = NULL;
|
diskFile = NULL;
|
}
|
}
|
if (sfd != 0) {
|
if (sfd != 0) {
|
serialClose();
|
serialClose();
|
sfd = 0;
|
sfd = 0;
|
}
|
}
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
|
|
void serialOpen(void) {
|
void serialOpen(char *serialPort) {
|
sfd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
|
sfd = open(serialPort, O_RDWR | O_NOCTTY | O_NDELAY);
|
if (sfd == -1) {
|
if (sfd == -1) {
|
error("cannot open serial port '%s'", SERIAL_PORT);
|
error("cannot open serial port '%s'", serialPort);
|
}
|
}
|
tcgetattr(sfd, &origOptions);
|
tcgetattr(sfd, &origOptions);
|
currOptions = origOptions;
|
currOptions = origOptions;
|
cfsetispeed(&currOptions, B38400);
|
cfsetispeed(&currOptions, B38400);
|
cfsetospeed(&currOptions, B38400);
|
cfsetospeed(&currOptions, B38400);
|
currOptions.c_cflag |= (CLOCAL | CREAD);
|
currOptions.c_cflag |= (CLOCAL | CREAD);
|
currOptions.c_cflag &= ~PARENB;
|
currOptions.c_cflag &= ~PARENB;
|
currOptions.c_cflag &= ~CSTOPB;
|
currOptions.c_cflag &= ~CSTOPB;
|
currOptions.c_cflag &= ~CSIZE;
|
currOptions.c_cflag &= ~CSIZE;
|
currOptions.c_cflag |= CS8;
|
currOptions.c_cflag |= CS8;
|
currOptions.c_cflag &= ~CRTSCTS;
|
currOptions.c_cflag &= ~CRTSCTS;
|
currOptions.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | IEXTEN);
|
currOptions.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | IEXTEN);
|
currOptions.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK);
|
currOptions.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK);
|
currOptions.c_iflag &= ~(INPCK | ISTRIP | INLCR | IGNCR | ICRNL);
|
currOptions.c_iflag &= ~(INPCK | ISTRIP | INLCR | IGNCR | ICRNL);
|
currOptions.c_iflag &= ~(IXON | IXOFF | IXANY);
|
currOptions.c_iflag &= ~(IXON | IXOFF | IXANY);
|
currOptions.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
|
currOptions.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
|
tcsetattr(sfd, TCSANOW, &currOptions);
|
tcsetattr(sfd, TCSANOW, &currOptions);
|
}
|
}
|
|
|
|
|
void serialClose(void) {
|
void serialClose(void) {
|
tcsetattr(sfd, TCSANOW, &origOptions);
|
tcsetattr(sfd, TCSANOW, &origOptions);
|
close(sfd);
|
close(sfd);
|
}
|
}
|
|
|
|
|
int serialSnd(unsigned char b) {
|
int serialSnd(unsigned char b) {
|
int n;
|
int n;
|
|
|
n = write(sfd, &b, 1);
|
n = write(sfd, &b, 1);
|
return n == 1;
|
return n == 1;
|
}
|
}
|
|
|
|
|
int serialRcv(unsigned char *bp) {
|
int serialRcv(unsigned char *bp) {
|
int n;
|
int n;
|
|
|
n = read(sfd, bp, 1);
|
n = read(sfd, bp, 1);
|
return n == 1;
|
return n == 1;
|
}
|
}
|
|
|
|
|
void connect(void) {
|
void connect(void) {
|
unsigned char b;
|
unsigned char b;
|
|
|
printf("SYN... ");
|
printf("SYN... ");
|
fflush(stdout);
|
fflush(stdout);
|
while (!serialSnd(ACK)) ;
|
while (!serialSnd(ACK)) ;
|
tcdrain(sfd);
|
tcdrain(sfd);
|
printf("ACK... ");
|
printf("ACK... ");
|
fflush(stdout);
|
fflush(stdout);
|
while (!serialRcv(&b)) ;
|
while (!serialRcv(&b)) ;
|
if (b != ACK) {
|
if (b != ACK) {
|
error("cannot synchronize with client");
|
error("cannot synchronize with client");
|
}
|
}
|
printf("connected\n");
|
printf("connected\n");
|
}
|
}
|
|
|
|
|
void sendResult(unsigned char result) {
|
void sendResult(unsigned char result) {
|
while (!serialSnd(result)) ;
|
while (!serialSnd(result)) ;
|
tcdrain(sfd);
|
tcdrain(sfd);
|
}
|
}
|
|
|
|
|
void showData(unsigned char buffer[512]) {
|
void showData(unsigned char buffer[512]) {
|
int i, j;
|
int i, j;
|
unsigned char c;
|
unsigned char c;
|
|
|
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
printf("%03X ", i * 16);
|
printf("%03X ", i * 16);
|
for (j = 0; j < 16; j++) {
|
for (j = 0; j < 16; j++) {
|
c = buffer[i * 16 + j];
|
c = buffer[i * 16 + j];
|
printf("%02X ", c);
|
printf("%02X ", c);
|
}
|
}
|
printf(" ");
|
printf(" ");
|
for (j = 0; j < 16; j++) {
|
for (j = 0; j < 16; j++) {
|
c = buffer[i * 16 + j];
|
c = buffer[i * 16 + j];
|
if (c >= 0x20 && c < 0x7F) {
|
if (c >= 0x20 && c < 0x7F) {
|
printf("%c", c);
|
printf("%c", c);
|
} else {
|
} else {
|
printf(".");
|
printf(".");
|
}
|
}
|
}
|
}
|
printf("\n");
|
printf("\n");
|
}
|
}
|
}
|
}
|
|
|
|
|
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
|
char *serialPort;
|
char *diskName;
|
char *diskName;
|
int i;
|
int i;
|
unsigned char b;
|
unsigned char b;
|
unsigned char cmd;
|
unsigned char cmd;
|
unsigned int sector;
|
unsigned int sector;
|
unsigned char buffer[512];
|
unsigned char buffer[512];
|
|
|
if (argc != 2) {
|
if (argc != 3) {
|
printf("Usage: %s <disk image file>\n", argv[0]);
|
printf("Usage: %s <serial port> <disk image file>\n", argv[0]);
|
exit(1);
|
exit(1);
|
}
|
}
|
diskName = argv[1];
|
serialPort = argv[1];
|
|
diskName = argv[2];
|
diskFile = fopen(diskName, "r+b");
|
diskFile = fopen(diskName, "r+b");
|
if (diskFile == NULL) {
|
if (diskFile == NULL) {
|
error("cannot open disk image file '%s'", diskName);
|
error("cannot open disk image file '%s'", diskName);
|
}
|
}
|
fseek(diskFile, 0, SEEK_END);
|
fseek(diskFile, 0, SEEK_END);
|
numSectors = ftell(diskFile) / 512;
|
numSectors = ftell(diskFile) / 512;
|
fseek(diskFile, 0, SEEK_SET);
|
fseek(diskFile, 0, SEEK_SET);
|
printf("Disk '%s' has 0x%08X sectors.\n", diskName, numSectors);
|
printf("Disk '%s' has 0x%08X sectors.\n", diskName, numSectors);
|
/* open serial interface */
|
/* open serial interface */
|
serialOpen();
|
serialOpen(serialPort);
|
/* wait for client to connect */
|
/* wait for client to connect */
|
printf("Waiting for client...\n");
|
printf("Waiting for client...\n");
|
while (1) {
|
while (1) {
|
if (serialRcv(&b) && b == SYN) {
|
if (serialRcv(&b) && b == SYN) {
|
break;
|
break;
|
}
|
}
|
}
|
}
|
connect();
|
connect();
|
/* connected, now handle requests */
|
/* connected, now handle requests */
|
while (1) {
|
while (1) {
|
while (!serialRcv(&cmd)) ;
|
while (!serialRcv(&cmd)) ;
|
if (cmd == 'q') {
|
if (cmd == 'q') {
|
/* for tests only, a real client would never quit */
|
/* for tests only, a real client would never quit */
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("quit\n");
|
printf("quit\n");
|
}
|
}
|
break;
|
break;
|
}
|
}
|
if (cmd == SYN) {
|
if (cmd == SYN) {
|
/* this happens if the client has been reset */
|
/* this happens if the client has been reset */
|
connect();
|
connect();
|
continue;
|
continue;
|
}
|
}
|
if (cmd == 'c') {
|
if (cmd == 'c') {
|
/* client asks for disk capacity */
|
/* client asks for disk capacity */
|
sendResult(RESULT_OK);
|
sendResult(RESULT_OK);
|
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
b = (numSectors >> (8 * (3 - i))) & 0xFF;
|
b = (numSectors >> (8 * (3 - i))) & 0xFF;
|
while (!serialSnd(b)) ;
|
while (!serialSnd(b)) ;
|
}
|
}
|
tcdrain(sfd);
|
tcdrain(sfd);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("capacity... OK\n");
|
printf("capacity... OK\n");
|
}
|
}
|
continue;
|
continue;
|
}
|
}
|
if (cmd != 'r' && cmd != 'w') {
|
if (cmd != 'r' && cmd != 'w') {
|
/* unknown command */
|
/* unknown command */
|
sendResult(RESULT_UNCMD);
|
sendResult(RESULT_UNCMD);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("unknown... UNCMD\n");
|
printf("unknown... UNCMD\n");
|
}
|
}
|
continue;
|
continue;
|
}
|
}
|
/* only read and write requests get here */
|
/* only read and write requests get here */
|
sector = 0;
|
sector = 0;
|
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
while (!serialRcv(&b)) ;
|
while (!serialRcv(&b)) ;
|
sector = (sector << 8) | b;
|
sector = (sector << 8) | b;
|
}
|
}
|
if (cmd == 'r') {
|
if (cmd == 'r') {
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("reading sector 0x%08X... ", sector);
|
printf("reading sector 0x%08X... ", sector);
|
fflush(stdout);
|
fflush(stdout);
|
}
|
}
|
if (sector >= numSectors) {
|
if (sector >= numSectors) {
|
sendResult(RESULT_TOOBIG);
|
sendResult(RESULT_TOOBIG);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("TOOBIG\n");
|
printf("TOOBIG\n");
|
}
|
}
|
} else
|
} else
|
if (fseek(diskFile, sector * 512, SEEK_SET) != 0) {
|
if (fseek(diskFile, sector * 512, SEEK_SET) != 0) {
|
sendResult(RESULT_POSERR);
|
sendResult(RESULT_POSERR);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("POSERR\n");
|
printf("POSERR\n");
|
}
|
}
|
} else
|
} else
|
if (fread(buffer, 1, 512, diskFile) != 512) {
|
if (fread(buffer, 1, 512, diskFile) != 512) {
|
sendResult(RESULT_RDERR);
|
sendResult(RESULT_RDERR);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("RDERR\n");
|
printf("RDERR\n");
|
}
|
}
|
} else {
|
} else {
|
sendResult(RESULT_OK);
|
sendResult(RESULT_OK);
|
for (i = 0; i < 512; i++) {
|
for (i = 0; i < 512; i++) {
|
while (!serialSnd(buffer[i])) ;
|
while (!serialSnd(buffer[i])) ;
|
}
|
}
|
tcdrain(sfd);
|
tcdrain(sfd);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("OK\n");
|
printf("OK\n");
|
}
|
}
|
if (debugData) {
|
if (debugData) {
|
showData(buffer);
|
showData(buffer);
|
}
|
}
|
}
|
}
|
continue;
|
continue;
|
}
|
}
|
if (cmd == 'w') {
|
if (cmd == 'w') {
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("writing sector 0x%08X... ", sector);
|
printf("writing sector 0x%08X... ", sector);
|
fflush(stdout);
|
fflush(stdout);
|
}
|
}
|
for (i = 0; i < 512; i++) {
|
for (i = 0; i < 512; i++) {
|
while (!serialRcv(buffer + i)) ;
|
while (!serialRcv(buffer + i)) ;
|
}
|
}
|
if (sector >= numSectors) {
|
if (sector >= numSectors) {
|
sendResult(RESULT_TOOBIG);
|
sendResult(RESULT_TOOBIG);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("TOOBIG\n");
|
printf("TOOBIG\n");
|
}
|
}
|
} else
|
} else
|
if (fseek(diskFile, sector * 512, SEEK_SET) != 0) {
|
if (fseek(diskFile, sector * 512, SEEK_SET) != 0) {
|
sendResult(RESULT_POSERR);
|
sendResult(RESULT_POSERR);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("POSERR\n");
|
printf("POSERR\n");
|
}
|
}
|
} else
|
} else
|
if (fwrite(buffer, 1, 512, diskFile) != 512) {
|
if (fwrite(buffer, 1, 512, diskFile) != 512) {
|
sendResult(RESULT_WRERR);
|
sendResult(RESULT_WRERR);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("WRERR\n");
|
printf("WRERR\n");
|
}
|
}
|
} else {
|
} else {
|
sendResult(RESULT_OK);
|
sendResult(RESULT_OK);
|
if (debugCmds) {
|
if (debugCmds) {
|
printf("OK\n");
|
printf("OK\n");
|
}
|
}
|
if (debugData) {
|
if (debugData) {
|
showData(buffer);
|
showData(buffer);
|
}
|
}
|
}
|
}
|
continue;
|
continue;
|
}
|
}
|
}
|
}
|
if (diskFile != NULL) {
|
if (diskFile != NULL) {
|
fclose(diskFile);
|
fclose(diskFile);
|
diskFile = NULL;
|
diskFile = NULL;
|
}
|
}
|
if (sfd != 0) {
|
if (sfd != 0) {
|
serialClose();
|
serialClose();
|
sfd = 0;
|
sfd = 0;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|