2020-08-22 22:30:12 -04:00
|
|
|
/*!
|
|
|
|
* @file kdsnetm.cpp
|
|
|
|
* Low-level DECI2 wrapper for ksocket
|
|
|
|
* DONE!
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdio>
|
|
|
|
#include "game/sce/deci2.h"
|
|
|
|
#include "game/system/deci_common.h" // todo, reorganize to avoid this include
|
|
|
|
#include "kdsnetm.h"
|
|
|
|
#include "kprint.h"
|
2022-01-02 18:02:10 -05:00
|
|
|
#include "common/util/assert.h"
|
2020-08-22 22:30:12 -04:00
|
|
|
|
|
|
|
using namespace ee;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Current state of the GOAL Protocol
|
|
|
|
*/
|
|
|
|
|
|
|
|
GoalProtoBlock protoBlock;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Initialize global variables for kdsnetm
|
|
|
|
*/
|
|
|
|
void kdsnetm_init_globals() {
|
|
|
|
protoBlock.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Register GOAL DECI2 Protocol Driver with DECI2 service
|
|
|
|
* DONE, EXACT
|
2020-09-03 22:24:50 -04:00
|
|
|
*/
|
2020-08-22 22:30:12 -04:00
|
|
|
void InitGoalProto() {
|
|
|
|
protoBlock.socket = sceDeci2Open(DECI2_PROTOCOL, &protoBlock, GoalProtoHandler);
|
|
|
|
if (protoBlock.socket < 0) {
|
|
|
|
MsgErr("gproto: open proto error\n");
|
|
|
|
} else {
|
|
|
|
protoBlock.send_buffer = nullptr;
|
2020-10-31 14:07:43 -04:00
|
|
|
protoBlock.receive_buffer = MessBufArea.cast<ListenerMessageHeader>().c();
|
2020-08-22 22:30:12 -04:00
|
|
|
protoBlock.send_status = -1;
|
|
|
|
protoBlock.last_receive_size = -1;
|
|
|
|
protoBlock.receive_progress = 0;
|
|
|
|
protoBlock.deci2count.offset = 0;
|
|
|
|
Msg(6, "gproto: proto open at socket %d\n", protoBlock.socket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Close the DECI2 Protocol Driver
|
|
|
|
* DONE, EXACT
|
2020-09-03 22:24:50 -04:00
|
|
|
*/
|
2020-08-22 22:30:12 -04:00
|
|
|
void ShutdownGoalProto() {
|
|
|
|
if (protoBlock.socket > 0) {
|
|
|
|
sceDeci2Close(protoBlock.socket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Handle a DECI2 Protocol Event for the GOAL Proto.
|
|
|
|
* Called by the DECI2 Protocol driver
|
|
|
|
* DONE, added print statements on errors for debugging, EI and SYNC at the end were removed
|
2020-09-03 22:24:50 -04:00
|
|
|
*/
|
2020-08-22 22:30:12 -04:00
|
|
|
void GoalProtoHandler(int event, int param, void* opt) {
|
|
|
|
// verify we got the correct opt pointer. It's not clear why the opt pointer is used
|
|
|
|
// like this?
|
|
|
|
GoalProtoBlock* pb = (GoalProtoBlock*)opt;
|
|
|
|
if (&protoBlock != pb) {
|
|
|
|
Msg(6, "gproto: BAD OPT POINTER PASSED IN!!!!\n"); // this print statement is in the game.
|
|
|
|
pb = &protoBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
// increment deci2count, if it's set up
|
|
|
|
if (pb->deci2count.offset) {
|
|
|
|
*pb->deci2count = *pb->deci2count + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remember what event this is
|
|
|
|
pb->most_recent_event = event;
|
|
|
|
pb->most_recent_param = param;
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
// get some data - param is the size
|
|
|
|
case DECI2_READ:
|
|
|
|
// sanity check the size
|
|
|
|
if (pb->receive_progress + param <= (int)DEBUG_MESSAGE_BUFFER_SIZE) {
|
|
|
|
// actually get data from DECI2
|
|
|
|
s32 received =
|
|
|
|
sceDeci2ExRecv(pb->socket, ((u8*)pb->receive_buffer) + pb->receive_progress, param);
|
|
|
|
|
|
|
|
if (received < 0) {
|
|
|
|
// receive failure
|
|
|
|
pb->last_receive_size = -1;
|
|
|
|
protoBlock.receive_progress = 0; // why use protoBlock instead of pb here?
|
|
|
|
printf("gproto: read error with sceDeci2ExRecv\n");
|
|
|
|
} else {
|
|
|
|
pb->receive_progress += received;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// size was too large
|
|
|
|
pb->last_receive_size = -1;
|
|
|
|
protoBlock.receive_progress = 0; // why use protoBlock here?
|
|
|
|
printf("gproto: read error, message too large!\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// read is finished!
|
|
|
|
case DECI2_READDONE:
|
|
|
|
// set last_receive_size to indicate that there is a pending message in the buffer.
|
|
|
|
pb->last_receive_size = pb->receive_progress;
|
|
|
|
pb->receive_progress = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// send some data
|
|
|
|
case DECI2_WRITE: {
|
|
|
|
// note that we should not attempt to send more than 0xffff bytes at a time, or this will be
|
|
|
|
// wrong. This is correctly checked for prints, but not for outputs.
|
|
|
|
assert(pb->send_remaining < 0xffff);
|
|
|
|
// why and it with 0xffff? Seems like saturation would be better. Either way some data
|
|
|
|
// will be lost, so I guess it doesn't matter.
|
|
|
|
s32 sent = sceDeci2ExSend(pb->socket, (void*)pb->send_ptr, pb->send_remaining & 0xffff);
|
|
|
|
if (sent < 0) {
|
|
|
|
// if we got an error, put it in send status, signaling a send error (negative)
|
|
|
|
pb->send_status = sent;
|
|
|
|
} else {
|
|
|
|
// otherwise don't touch send status, leave it positive to indicate we're still sending
|
|
|
|
pb->send_ptr += sent;
|
|
|
|
pb->send_remaining -= sent;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
// done sending!
|
|
|
|
case DECI2_WRITEDONE:
|
|
|
|
if (pb->send_remaining <= 0) {
|
|
|
|
// if we've send everything we want, set status to zero to indicate success
|
|
|
|
pb->send_status = 0;
|
|
|
|
} else {
|
|
|
|
// otherwise, set send status to a negative number (the negative absolute value of
|
|
|
|
// remaining)
|
|
|
|
s32 a = pb->send_remaining;
|
|
|
|
if (a < 0) {
|
|
|
|
a = -a;
|
|
|
|
}
|
|
|
|
pb->send_status = -a;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DECI2_CHSTATUS:
|
|
|
|
break;
|
|
|
|
|
|
|
|
// other events are undefined, so we just error.
|
|
|
|
default:
|
|
|
|
pb->last_receive_size = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Low level DECI2 send
|
|
|
|
* Will block until send is complete.
|
|
|
|
* DONE, original version used an uncached address and had a FlushCache call, which were both
|
|
|
|
* removed
|
2020-09-03 22:24:50 -04:00
|
|
|
*/
|
2020-12-28 18:37:05 -05:00
|
|
|
s32 SendFromBufferD(s32 msg_kind, u64 msg_id, char* data, s32 size) {
|
2020-08-22 22:30:12 -04:00
|
|
|
// wait for send to finish or error first...
|
|
|
|
while (protoBlock.send_status > 0) {
|
|
|
|
// on actual PS2, the kernel will run this in another thread.
|
|
|
|
LIBRARY_sceDeci2_run_sends();
|
|
|
|
}
|
|
|
|
|
|
|
|
// retry at most 10 times until we complete without an error.
|
|
|
|
for (s32 i = 0; i < 10; i++) {
|
|
|
|
// or'd with 0x20000000 to get noncache version
|
2020-10-31 14:07:43 -04:00
|
|
|
ListenerMessageHeader* header = (ListenerMessageHeader*)(data - sizeof(ListenerMessageHeader));
|
|
|
|
protoBlock.send_remaining = size + sizeof(ListenerMessageHeader);
|
2020-08-22 22:30:12 -04:00
|
|
|
protoBlock.send_buffer = header;
|
|
|
|
protoBlock.send_ptr = (u8*)header;
|
|
|
|
|
2020-10-31 14:07:43 -04:00
|
|
|
protoBlock.send_status = size + sizeof(ListenerMessageHeader);
|
2020-08-22 22:30:12 -04:00
|
|
|
// FlushCache(0);
|
|
|
|
|
|
|
|
// set DECI2 message header
|
2020-10-31 14:07:43 -04:00
|
|
|
header->deci2_header.len = protoBlock.send_remaining;
|
|
|
|
header->deci2_header.rsvd = 0;
|
|
|
|
header->deci2_header.proto = DECI2_PROTOCOL;
|
|
|
|
header->deci2_header.src = 'E'; // from EE
|
|
|
|
header->deci2_header.dst = 'H'; // to HOST
|
2020-08-22 22:30:12 -04:00
|
|
|
|
|
|
|
// set GOAL message header
|
2020-10-31 14:07:43 -04:00
|
|
|
header->msg_kind = (ListenerMessageKind)msg_kind;
|
2020-08-22 22:30:12 -04:00
|
|
|
header->u6 = 0;
|
|
|
|
header->msg_size = size;
|
2020-12-28 18:37:05 -05:00
|
|
|
header->msg_id = msg_id;
|
2020-08-22 22:30:12 -04:00
|
|
|
|
|
|
|
// start send!
|
2020-10-31 14:07:43 -04:00
|
|
|
auto rv = sceDeci2ReqSend(protoBlock.socket, header->deci2_header.dst);
|
2020-08-22 22:30:12 -04:00
|
|
|
if (rv < 0) {
|
|
|
|
printf("1sceDeci2ReqSend fail, reason code = %08x\n", rv);
|
|
|
|
return 0xfffffffa;
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait for send to complete or error.
|
|
|
|
while (protoBlock.send_status > 0) {
|
|
|
|
LIBRARY_sceDeci2_run_sends();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if send completes, exit. Otherwise if there's an error, just try again.
|
|
|
|
if (protoBlock.send_status == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Print GOAL Protocol status
|
2020-09-03 22:24:50 -04:00
|
|
|
*/
|
2020-08-22 22:30:12 -04:00
|
|
|
void GoalProtoStatus() {
|
|
|
|
Msg(6, "gproto: got %d %d\n", protoBlock.most_recent_event, protoBlock.most_recent_param);
|
|
|
|
Msg(6, "gproto: %d %d\n", protoBlock.last_receive_size, protoBlock.send_remaining);
|
2020-08-26 22:23:22 -04:00
|
|
|
}
|