jancity/src/net/ps1/src/net.c

262 lines
4.6 KiB
C

#include <net.h>
#include <net/serial.h>
#include <net_serial_private.h>
#include <transport.h>
#include <psx.h>
#include <psxsio.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
static struct net_host
{
enum net_role role;
bool used, sending;
struct transport_handle h;
struct net_event ev;
struct net_host_fifo
{
char buf[32];
size_t pending, read;
} in, out;
} host;
enum {TX_INT_ENABLE = 1 << 10};
int net_write(struct net_host *const h, const net_peer peer,
const void *const buf, size_t n)
{
return transport_send(&h->h, buf, n);
}
int net_close(struct net_host *const h)
{
SIOStop();
RemoveSIOHandler();
h->used = false;
return 0;
}
static void send_byte(struct net_host *const h)
{
struct net_host_fifo *const f = &h->out;
if (f->pending != f->read)
{
if (SIOCheckOutBuffer())
{
size_t new = f->read + 1;
if (new >= sizeof f->buf)
new = 0;
h->sending = true;
SIOSendByte(f->buf[f->read = new]);
}
}
else
{
h->sending = false;
SIO_CTRL &= ~TX_INT_ENABLE;
}
}
int net_update(struct net_host *const h)
{
return transport_update(&h->h);
}
static void on_received(const struct transport_event *const ev,
void *const arg)
{
struct net_host *const h = arg;
net_serial_on_received(ev, &h->ev);
}
static int on_write(const void *const buf, size_t n, void *const arg)
{
const size_t orig = n;
struct net_host *const h = arg;
EnterCriticalSection();
for (const uint8_t *b = buf; n; n--, b++)
{
struct net_host_fifo *const f = &h->out;
size_t new = f->pending + 1;
if (new >= sizeof f->buf)
new = 0;
if (new == f->read)
{
fprintf(stderr, "%s: out FIFO full\n", __func__);
goto end;
}
f->buf[f->pending = new] = *b;
}
if (n != orig)
SIO_CTRL |= TX_INT_ENABLE;
end:
ExitCriticalSection();
return orig - n;
}
static int on_read(void *const buf, const size_t n, void *const arg)
{
size_t rem = n;
struct net_host *const h = arg;
struct net_host_fifo *const f = &h->in;
EnterCriticalSection();
for (uint8_t *b = buf; rem; rem--, b++)
{
if (f->read == f->pending)
goto end;
size_t new = f->read + 1;
if (new >= sizeof f->buf)
new = 0;
*b = f->buf[f->read = new];
}
end:
ExitCriticalSection();
return n - rem;
}
static struct transport_cfg get_transport_cfg(void)
{
return (const struct transport_cfg)
{
.arg = &host,
.received = on_received,
.read = on_read,
.write = on_write
};
}
static void on_byte_received(struct net_host *const h, const char ch)
{
struct net_host_fifo *const f = &h->in;
size_t new = f->pending + 1;
if (new >= sizeof f->buf)
new = 0;
f->buf[f->pending = new] = ch;
}
static void sio(void)
{
struct net_host *const h = &host;
if (SIOCheckInBuffer())
on_byte_received(h, SIOReadByte());
send_byte(h);
}
static void start_sio(const unsigned long baud)
{
enum
{
RX_INT_MODE_1_BYTE = 1 << 8,
RX_INT_ENABLE = 1 << 11
};
SIOStartEx(baud, SIO_DATA_LEN_8, SIO_PARITY_NONE, SIO_STOP_BIT_1);
SetSIOHandler(sio);
SIO_CTRL |= RX_INT_ENABLE | RX_INT_MODE_1_BYTE;
}
struct net_host *net_connect(const union net_connect *const c)
{
struct net_host *const h = &host;
if (h->used)
goto failure;
start_sio(c->serial.cfg.baud);
*h = (const struct net_host)
{
.role = NET_ROLE_CLIENT,
.used = true,
.h =
{
.cfg = get_transport_cfg()
}
};
if (transport_connect(&h->h))
goto failure;
return h;
failure:
net_close(h);
return NULL;
}
struct net_host *net_server(const union net_server *const c)
{
struct net_host *const h = &host;
if (h->used)
return NULL;
*h = (const struct net_host)
{
.role = NET_ROLE_SERVER,
.used = true,
.h =
{
.cfg = get_transport_cfg()
}
};
start_sio(c->serial.cfg.baud);
return h;
}
int net_init(void)
{
return 0;
}
void net_deinit(void)
{
}
int net_set_event(struct net_host *const h,
const struct net_event *const ev)
{
h->ev = *ev;
return 0;
}
bool net_available(const enum net_domain d)
{
return d == NET_DOMAIN_SERIAL;
}
bool net_serial_unique(void)
{
return true;
}
enum net_role net_role(const struct net_host *s)
{
return s->role;
}