/**************************************************************************************/ /* Sendrec.c, Libcyc source file */ /* Functions for sending and receiving text, integers and commands to/from PC/PSX */ /* Copyright(C)1999 Peter Armstrong */ /* Release 2.0 */ /**************************************************************************************/ /* includes */ #include #include "stdlib.h" #include "memory.h" #include "sys\ioctl.h" #include "sys\file.h" #include "pad.h" #include "misc.h" #include "sendrec.h" #include "packets.h" #include "cycfcntl.h" /* externs */ extern struct link_info link; extern volatile struct cmds *cmd; extern int port_fd; /* serial port's file descriptor */ extern volatile u_int vs_timer; extern u_int time[]; /* globals */ int retries; /*------------------------------------------------------------------------------------*/ /* Read in text message from the PC */ /* Arguments: */ /* *text_str - ptr to message storage */ /* *hdr_str - ptr to header, if already received */ /* Return value: */ /* 1 message received */ /* 0 error occurred */ /*------------------------------------------------------------------------------------*/ int Read_Text(char *text_str, char *hdr_p) { int size; if(size = Read_Header(hdr_p)) /* get string size from header */ { if(Read_Text_Str(text_str,size)) /* get string */ return OK; } return NG; } /*------------------------------------------------------------------------------------*/ /* Read in header for incoming string */ /* Arguments: */ /* *hdr_p - ptr to header, if already received */ /* Return value: */ /* >0 length of string, including null and checksum */ /* 0 error occurred */ /*------------------------------------------------------------------------------------*/ int Read_Header(char *hdr_p) { char header[HDR_SIZE]; /* header - °HEADR */ int i; char getsum; retries = MAX_RETRIES; while(retries--) { if(!hdr_p) /* read header */ { if(!Port_Read(header,HDR_SIZE,time[FIVE_SEC])) break; /* no data, timeout */ } else /* header already received */ { memcpy(header,hdr_p,HDR_SIZE); hdr_p = NULL; } getsum = 0; for(i = 0; i < (HDR_SIZE - 1); i++) { getsum += header[i]; /* create checksum */ } if(getsum == header[H_CHKSUM]) /* compare checksums */ { Send_Reply(OK); return header[H_SIZE]; /* return string size */ } else { Send_Reply(BAD); } } return NG; } /*------------------------------------------------------------------------------------*/ /* Read in text string from the PC */ /* Arguments: */ /* *text_p - ptr to message storage */ /* size - length of string, including null and checksum */ /* Return value: */ /* 1 - string received */ /* 0 - error */ /*------------------------------------------------------------------------------------*/ int Read_Text_Str(char *text_p, int size) { int i; char getsum; retries = MAX_RETRIES; while(retries--) { if(!Port_Read(text_p,size,time[FIVE_SEC])) /* read in string */ break; /* timeout, no data arrived */ getsum = 0; /* checksum */ for(i = 0; i < (size - 1); i++) { getsum += text_p[i]; } /* compare checksums */ if(getsum == text_p[(size - 1)]) { Send_Reply(OK); return OK; /* string good */ } /* string bad */ Send_Reply(BAD); } return NG; } /*------------------------------------------------------------------------------------*/ /* Send a text message to the PC */ /* Arguments: */ /* *text_p - ptr to string to send, 96 chars max */ /* Return value: */ /* 1 - string sent */ /* 0 - error */ /*------------------------------------------------------------------------------------*/ int Send_Text(char *text_p) { int size; size = (strlen(text_p)+2); /* length + null and chksum */ if(Send_Header(size)) /* send header, containing string size */ { if(Send_Text_Str(text_p,size)) /* send string */ return OK; } return NG; } /*------------------------------------------------------------------------------------*/ /* Send header for outgoing string */ /* Arguments: */ /* size - length of string, plus null and checksum */ /* Return value: */ /* 1 - header sent successfully */ /* 0 - error */ /*------------------------------------------------------------------------------------*/ int Send_Header(int size) { int i; char header[HDR_SIZE] = {FS_CMD,'H','E','A','D','R',0x00,0x00}; /* °HEADR */ header[H_SIZE] = size; /* put string size in header */ /* calc checksum */ for(i = 0; i < (HDR_SIZE - 1); i++) { header[H_CHKSUM] += header[i]; } return(Port_Write(header,HDR_SIZE)); /* send header to PC */ } /*------------------------------------------------------------------------------------*/ /* Send text string */ /* Arguments: */ /* *text_p - ptr to string to send */ /* size - length of string, including null and checksum */ /* Return value: */ /* 1 - string sent successfully */ /* 0 - error */ /*------------------------------------------------------------------------------------*/ int Send_Text_Str(char *text_p, int size) { int i; char send_str[100]; int chksum; chksum = (size - 1); strcpy(send_str,text_p); send_str[chksum] = 0; /* calc checksum */ for(i = 0; i < (size - 1); i++) { send_str[chksum] += *(text_p++); } return(Port_Write(send_str,size)); /* send out string to PC */ } /*------------------------------------------------------------------------------------*/ /* Send 4-byte integer */ /* Arguments: */ /* num - number to send */ /* Return value: */ /* 1 - sent successfully */ /* 0 - error */ /*------------------------------------------------------------------------------------*/ int Send_Integer(int num) { int i; u_char inter[INTER_SIZE] = {FS_CMD,'I','T'}; /* °IT<4byte integer> */ u_char *inter_p = &inter[INTER_NUM]; u_char *int_p = (u_char *)# u_char chksum = inter[0]+inter[1]+inter[2]; for(i = 0; i < (INTER_SIZE - 4); i++) { chksum += inter_p[i] = int_p[i]; /* calc checksum */ } inter_p[i] = chksum; return(Port_Write((char *)inter,INTER_SIZE)); } /*------------------------------------------------------------------------------------*/ /* Read in 4-byte integer */ /* Arguments: */ /* *int_p - ptr to number store */ /* Return value: */ /* 1 - integer number received */ /* 0 - error */ /*------------------------------------------------------------------------------------*/ int Read_Integer(int *int_p) { int i,read_int; u_char inter[INTER_SIZE]; u_char *inter_p = &inter[INTER_NUM]; u_char *int_ptr = (u_char *)&read_int; u_char getsum; retries = MAX_RETRIES; while(retries--) { if(!Port_Read(inter,INTER_SIZE,time[FIVE_SEC])) /* read in integer array */ break; /* timeout */ getsum = inter[0]+inter[1]+inter[2]; for(i = 0; i < (INTER_SIZE - 4); i++) { getsum += int_ptr[i] = inter_p[i]; } if(getsum == inter_p[i]) /* compare checksums */ { Send_Reply(OK); *int_p = read_int; /* return integer value */ return OK; /* integer received */ } Send_Reply(BAD); /* integer bad */ } return NG; } /*------------------------------------------------------------------------------------*/ /* Read reply from psx after a block send */ /* Arguments: */ /* timer - length of time to wait for response (in vsyncs) */ /* Return value: */ /* 1 - data received okay */ /* -1 - data bad, re-send */ /* -2 - no response from psx, failure of attempt to recover */ /*------------------------------------------------------------------------------------*/ int Read_WrReply(u_int timer) { int count = 200; char rpy = TIMEOUT; if(!Port_Read(&rpy,REPLY_SIZE,timer)) { /* no remote response, bytes may have been dropped, send until response */ while(count--) { write(port_fd,&rpy,1); VSync(0); if(read(port_fd,&rpy,REPLY_SIZE) == REPLY_SIZE) break; } } return rpy; } /*------------------------------------------------------------------------------------*/ /* Read reply from PC for sent text or integer */ /* Arguments: */ /* timer - length of time to wait for response (in vsyncs) */ /* Return value: */ /* 1 - good data received by PC */ /* 0 - data received, but could not be processed */ /* -1 - data bad, re-send */ /* -2 - timeout, no reponse */ /*------------------------------------------------------------------------------------*/ int Read_Reply(u_int timer) { char rtn = TIMEOUT; Port_Read(&rtn,REPLY_SIZE,timer); return rtn; } /*------------------------------------------------------------------------------------*/ /* Send reply to acknowledge data received */ /* Arguments: */ /* status */ /* 1 - data received good */ /* 0 - bad data received */ /* Return value: */ /* none */ /*------------------------------------------------------------------------------------*/ void Send_Reply(char rpy_val) { if(rpy_val == BAD) /* bad checksum */ { VSync(0); Sio_Flush(); } write(port_fd,&rpy_val,REPLY_SIZE); } /*------------------------------------------------------------------------------------*/ /* Send out data through serial port */ /* Arguments: */ /* *data_p - ptr to data */ /* size - number of bytes to send */ /* Return value: */ /* 1 - data sent and received successfully */ /* 0 - error, timeout, can't process or max retries exceeded */ /*------------------------------------------------------------------------------------*/ int Port_Write(char *data_p,int size) { int error = 0,rpy; retries = MAX_RETRIES; while((!error) && (retries--)) { write(port_fd,data_p,size); /* send data to PC */ rpy = Read_Reply(time[SIX_SEC]); /* read reply */ switch(rpy) { case OK: /* data received okay */ return OK; case BAD: /* bad data, re-send */ break; case NG: /* data cannot be processed */ case TIMEOUT: /* no response */ error = 1; } } return NG; } /*------------------------------------------------------------------------------------*/ /* Read data from port */ /* Arguments: */ /* *read_p - ptr to buffer to store data */ /* to_read - number of bytes to read */ /* timer - length of time to wait before time-out */ /* Return value: */ /* >0 - number of bytes received */ /* 0 - timeout, no data */ /*------------------------------------------------------------------------------------*/ int Port_Read(char *read_p, int to_read, u_int timer) { int r_num,size = 0; u_int starttime; starttime = vs_timer; /* start timer */ while((vs_timer - starttime) < timer) { ioctl(port_fd,FIOCSCAN,1); if((r_num = read(port_fd,read_p,to_read)) > 0) { read_p += r_num; to_read -= r_num; size += r_num; starttime = vs_timer; while((to_read) && ((vs_timer - starttime) < time[HALF_SEC])) { ioctl(port_fd,FIOCSCAN,1); if((r_num = read(port_fd,read_p,to_read)) > 0) { read_p += r_num; to_read -= r_num; size += r_num; } } break; } } return size; } /*------------------------------------------------------------------------------------*/ /* Send and receive commands etc within callback function */ /* Arguments: */ /* none */ /* Return value: */ /* none */ /*------------------------------------------------------------------------------------*/ void vs_PsxCmds(void) { int r_num; u_char rem_msg[8]; if((r_num = vs_Sio_CmdRead(rem_msg,CMD_SIZE))) /* look for data at port */ { if(r_num == REPLY_SIZE) /* 1 byte, assume command reply */ { vs_Read_PsxReply(*rem_msg); /* check remote received last command */ } else { vs_Read_PsxCmd(rem_msg); /* else read in remote command */ } } if(cmd->loc_reply) /* reply whether remote command was received correctly */ { write(port_fd,(char *)&cmd->loc_rpy,REPLY_SIZE); cmd->loc_reply = 0; } else { if(cmd->command) /* a local command needs to be sent to remote */ { write(port_fd,(char *)cmd->cmd,CMD_SIZE); cmd->command = 0; } } } /*------------------------------------------------------------------------------------*/ /* Within callback, read in commands and replies, in 1 or 2 passes */ /* Arguments: */ /* *buffer - ptr to command/reply storage */ /* num - number of bytes to read */ /* Return value: */ /* >0 - number of bytes received */ /* 0 - no data received */ /*------------------------------------------------------------------------------------*/ int vs_Sio_CmdRead(char *buffer, int num) { static int stored = 0,pass = 0; int r_num,response = 0,rtn; num -= stored; if((r_num = read(port_fd,(buffer+stored),num)) > 0) { pass++; stored += r_num; /* look for command reply */ if(stored == REPLY_SIZE) { if(r_num == REPLY_SIZE) { if((*buffer >= BAD) && (*buffer <= OK)) response = 1; } } else { if(stored == CMD_SIZE) response = 1; } } else { if(pass) /* second pass?, return as data read */ response = 1; } if((pass == 2) || (response)) { rtn = stored; /* return byte number received */ pass = stored = 0; /* reset static variables */ return rtn; } return NG; } /*------------------------------------------------------------------------------------*/ /* Test value of remote's reply to a local command */ /* Arguments: */ /* rpy - remote's rpy */ /* Return value: */ /* none */ /*------------------------------------------------------------------------------------*/ void vs_Read_PsxReply(char rpy) { if(cmd->reply_await) /* psx waiting for a reply to a command */ { if((rpy == BAD) && (retries--)) /* remote bad chksum, cmd not received */ { cmd->command = 1; /* re-send command */ } else /* inform Send_PsxCmd() a reply has been received */ { cmd->rem_rpy = rpy; cmd->rem_reply = 1; } } } /*------------------------------------------------------------------------------------*/ /* Process the remote command received */ /* Arguments: */ /* *rem_cmd - remote command */ /* Return value: */ /* none */ /*------------------------------------------------------------------------------------*/ void vs_Read_PsxCmd(u_char *rem_cmd) { int i; u_char id; u_char getsum = 0; /* checksum received command */ for(i = 0; i < (CMD_SIZE - 1); i++) { getsum += rem_cmd[i]; } if(getsum == rem_cmd[CMD_CHKSUM]) /* checksum compare */ { id = rem_cmd[MSG_ID]; switch(id) /* general command */ { case PC_CMD: /* file server command */ case FS_CMD: /* file server data send */ cmd->loc_rpy = NG; /* commands of this type cannot be processed */ cmd->loc_reply = 1; break; case PSX_CMD: /* playstation command */ cmd->loc_rpy = OK; cmd->loc_reply = 1; id = rem_cmd[CMD_ID]; switch(id) /* psx specific command */ { case PCMD_CNT: /* remote connect cmd */ cmd->cnt_type = rem_cmd[CNT_TYPE]; /* store connect value */ cmd->connect = 1; /* remote wishes to connect */ break; case PCMD_XCNT: /* remote cancelling connection attempt */ cmd->connect = 0; break; case PCMD_START: /* remote ready to start transfer session */ cmd->st_size = rem_cmd[ST_SIZE]; /* store packet data size */ cmd->st_diff = rem_cmd[ST_DIFF]; /* store frame diff */ cmd->start = 1; break; case PCMD_ACK: /* command reply received */ cmd->ack_val = rem_cmd[ACK_VAL]; cmd->acknowledge = 1; break; case PCMD_BLOCK: /* read/write block, or cancel block command */ rem_cmd += 2; /* move pointer to command value */ if(*rem_cmd == B_CANX) /* remote cancelling block command */ cmd->block = 0; else /* store block command */ { cmd->block = *(rem_cmd++); memcpy((u_char *)&cmd->blk_id,rem_cmd,4); /* store block identifier */ } break; case PCMD_EXIT: /* received psx exit notification */ link.connected = 0; /* prevent receiving psx sending it's own exit command */ cmd->exit = 1; break; case PCMD_DISC: /* remote psx disconnecting */ link.connected = 0; break; } } } else /* bad command checksum */ { Sio_Flush(); cmd->loc_rpy = BAD; cmd->loc_reply = 1; } } /*------------------------------------------------------------------------------------*/ /* Register a command send, command sent within callback function */ /* Arguments: */ /* *loc_cmd - command to be sent */ /* Return value: */ /* 1 - remote received and accepted command */ /* 0 - remote received but cannot process command */ /* -1 - error, time-out or max retries exceeded */ /*------------------------------------------------------------------------------------*/ int Send_PsxCmd(u_char *loc_cmd) { int i,rtn = -1; u_int start_time; u_char chksum = 0; retries = MAX_RETRIES; /* vs_Read_PsxReply() */ cmd->cmd = loc_cmd; /* point to command to send */ /* checksum command */ for(i = 0; i < (CMD_SIZE - 1);i++) { chksum+= *(loc_cmd++); } *loc_cmd = chksum; /* place checksum value in command */ cmd->reply_await = cmd->command = 1; /* command stored to be sent, await reply */ /* read back remote's reply to command */ start_time = vs_timer; while((vs_timer - start_time) < time[ONE_SEC]) { if(cmd->rem_reply) { cmd->rem_reply = 0; rtn = cmd->rem_rpy; break; } } cmd->reply_await = 0; return rtn; } /*------------------------------------------------------------------------------------*/ /* Acknowledge some port commands */ /* Arguments: */ /* ack_val - reply value */ /* Return value: */ /* 1 - Acknowledge received */ /* 0 - cannot be processed */ /* -1 - time-out error */ /*------------------------------------------------------------------------------------*/ int Cmd_Reply(int ack_val) { u_char ack[8] = {PSX_CMD,'A','C','K',0x00,0,0,0x00}; /* ˛ACK00 */ ack[ACK_VAL] = ack_val; return(Send_PsxCmd(ack)); }