You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
5.2 KiB
225 lines
5.2 KiB
3 years ago
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include "dwt.h"
|
||
|
#include "server.h"
|
||
|
#include "libtelnet.h"
|
||
|
#include "socket.h"
|
||
|
#include "w5500.h"
|
||
|
#include "tick.h"
|
||
|
#include "config.h"
|
||
|
#include "cmd.h"
|
||
|
|
||
|
struct server {
|
||
|
telnet_t *telnet;
|
||
|
|
||
|
zcHandle console;
|
||
|
|
||
|
SOCKET tcp;
|
||
|
int port;
|
||
|
|
||
|
volatile uint8_t *rx_buffer;
|
||
|
uint16_t rx_buffer_size;
|
||
|
volatile uint16_t rx_head, rx_tail;
|
||
|
};
|
||
|
|
||
|
static volatile uint8_t __server0_rx_buffer[TARGET_SERVER_RXBUF_SZ] __attribute__((section(".txbuf.server,\"aw\",%nobits@")));
|
||
|
static struct server server0;
|
||
|
|
||
|
static void rx_buffer_put(struct server *srv, uint8_t data)
|
||
|
{
|
||
|
srv->rx_buffer[srv->rx_tail % srv->rx_buffer_size] = data;
|
||
|
srv->rx_tail++;
|
||
|
}
|
||
|
|
||
|
static int rx_buffer_empty(struct server *srv)
|
||
|
{
|
||
|
return srv->rx_head == srv->rx_tail;
|
||
|
}
|
||
|
|
||
|
static uint8_t rx_buffer_get(struct server *srv)
|
||
|
{
|
||
|
uint8_t data = srv->rx_buffer[srv->rx_head % srv->rx_buffer_size];
|
||
|
srv->rx_head++;
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
static void __delay_us(void *param, unsigned int us)
|
||
|
{
|
||
|
dwt_wait_us(us);
|
||
|
}
|
||
|
|
||
|
static void __send_char(void *param, int _ch)
|
||
|
{
|
||
|
char ch = _ch;
|
||
|
struct server *srv = param;
|
||
|
|
||
|
if (srv->telnet)
|
||
|
telnet_send(srv->telnet, &ch, 1);
|
||
|
}
|
||
|
|
||
|
static int __get_char(void *param, char *ch)
|
||
|
{
|
||
|
struct server *srv = param;
|
||
|
if (!rx_buffer_empty(srv)) {
|
||
|
*ch = rx_buffer_get(srv);
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void tcp_output(struct server *srv, const void *buf, int len)
|
||
|
{
|
||
|
int n;
|
||
|
if (getSn_SR(srv->tcp) != SOCK_ESTABLISHED) { /* drop packets */
|
||
|
return;
|
||
|
}
|
||
|
n = send(srv->tcp, buf, len, 0);
|
||
|
if (n != len) {
|
||
|
printf("drop packet: %d -> %d\r\n", len, n);
|
||
|
}
|
||
|
//delay(5);
|
||
|
//fwrite(buf, 1, len, stdout);
|
||
|
}
|
||
|
|
||
|
static void event_handler(telnet_t *telnet, telnet_event_t *ev, void *user_data)
|
||
|
{
|
||
|
int i;
|
||
|
struct server *srv = user_data;
|
||
|
|
||
|
switch (ev->type) {
|
||
|
case TELNET_EV_DATA:
|
||
|
for (i = 0; i < ev->data.size; ++i) {
|
||
|
rx_buffer_put(srv, ev->data.buffer[i]);
|
||
|
}
|
||
|
break;
|
||
|
case TELNET_EV_SEND:
|
||
|
tcp_output(srv, ev->data.buffer, ev->data.size);
|
||
|
break;
|
||
|
case TELNET_EV_IAC:
|
||
|
if (ev->iac.cmd == TELNET_SUSP || ev->iac.cmd == TELNET_ABORT) {
|
||
|
rx_buffer_put(srv, 26); /* put CTRL-Z */
|
||
|
}
|
||
|
break;
|
||
|
case TELNET_EV_DO:
|
||
|
if (ev->neg.telopt == TELNET_TELOPT_ECHO) {
|
||
|
if (srv->console)
|
||
|
consoleSetEchoMode(srv->console, 1);
|
||
|
}
|
||
|
break;
|
||
|
case TELNET_EV_DONT:
|
||
|
if (ev->neg.telopt == TELNET_TELOPT_ECHO) {
|
||
|
if (srv->console)
|
||
|
consoleSetEchoMode(srv->console, 0);
|
||
|
}
|
||
|
break;
|
||
|
case TELNET_EV_WILL:
|
||
|
if (ev->neg.telopt == TELNET_TELOPT_ECHO) {
|
||
|
if (srv->console)
|
||
|
consoleSetEchoMode(srv->console, 0);
|
||
|
}
|
||
|
break;
|
||
|
case TELNET_EV_WONT:
|
||
|
if (ev->neg.telopt == TELNET_TELOPT_ECHO) {
|
||
|
if (srv->console)
|
||
|
consoleSetEchoMode(srv->console, 1);
|
||
|
}
|
||
|
break;
|
||
|
case TELNET_EV_SUBNEGOTIATION:
|
||
|
printf("opt: %d (%d)\r\n", ev->sub.telopt, ev->sub.size);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int telnet_proto_init(SOCKET socket, int port)
|
||
|
{
|
||
|
ConsoleCfg cfg;
|
||
|
static const telnet_telopt_t my_telopts[] = {
|
||
|
{ TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO }, /* I will, you don't */
|
||
|
{ TELNET_TELOPT_BINARY, TELNET_WILL, TELNET_DO }, /* I will, you do */
|
||
|
{ TELNET_TELOPT_SGA, TELNET_WILL, TELNET_DO }, /* I will, you do */
|
||
|
{ TELNET_TELOPT_LINEMODE, TELNET_WONT, TELNET_DONT }, /* I will, you do */
|
||
|
{ TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DO },
|
||
|
{ -1, 0, 0 }
|
||
|
};
|
||
|
memset(&server0, 0, sizeof server0);
|
||
|
|
||
|
server0.rx_buffer = __server0_rx_buffer;
|
||
|
server0.rx_buffer_size = TARGET_SERVER_RXBUF_SZ;
|
||
|
|
||
|
memset(&cfg, 0, sizeof cfg);
|
||
|
cfg.delayUs = __delay_us;
|
||
|
cfg.getc = __get_char;
|
||
|
cfg.putc = __send_char;
|
||
|
cfg.param = &server0;
|
||
|
cfg.prompt = "A10> ";
|
||
|
server0.console = consoleNew(&cfg);
|
||
|
if (server0.console)
|
||
|
consoleSetEchoMode(server0.console, 0);
|
||
|
server0.telnet = telnet_init(my_telopts, event_handler, TELNET_FLAG_TRANSMIT_BINARY | TELNET_FLAG_RECEIVE_BINARY, &server0);
|
||
|
if (server0.telnet == NULL) {
|
||
|
return -1;
|
||
|
}
|
||
|
server0.tcp = socket;
|
||
|
server0.port = port;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int tcp_input(struct server *srv, int tcp)
|
||
|
{
|
||
|
uint8 buf[64];
|
||
|
int len = getSn_RX_RSR(tcp);
|
||
|
|
||
|
if (len <= 0)
|
||
|
return 0;
|
||
|
|
||
|
if (len > sizeof buf)
|
||
|
len = sizeof buf;
|
||
|
len = recv(tcp, buf, len);
|
||
|
if (srv->telnet)
|
||
|
telnet_recv(srv->telnet, (const char *)buf, len);
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static void process_tcp(struct server *srv)
|
||
|
{
|
||
|
int s = srv->tcp;
|
||
|
int state = getSn_SR(s);
|
||
|
|
||
|
switch (state) {
|
||
|
case SOCK_CLOSED:
|
||
|
if(socket(s, (Sn_MR_ND | Sn_MR_TCP),srv->port, 0x00) == 0) {
|
||
|
printf("%d : Fail to create socket.\r\n", s);
|
||
|
}
|
||
|
break;
|
||
|
case SOCK_INIT: /* if a socket is initiated */
|
||
|
listen(s);
|
||
|
printf("%x :LISTEN socket %d\r\n",getSn_SR(s), s);
|
||
|
break;
|
||
|
case SOCK_ESTABLISHED:
|
||
|
tcp_input(srv, s);
|
||
|
break;
|
||
|
case SOCK_CLOSE_WAIT: /* If the client request to close */
|
||
|
disconnect(s);
|
||
|
printf("%d : CLOSE_WAIT\r\n", s);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
zcHandle telnet_get_console()
|
||
|
{
|
||
|
return server0.console;
|
||
|
}
|
||
|
|
||
|
void telnet_proto_loop()
|
||
|
{
|
||
|
if (server0.telnet) {
|
||
|
process_tcp(&server0);
|
||
|
}
|
||
|
if (server0.console)
|
||
|
consoleProcess(server0.console);
|
||
|
}
|