mirror of
https://github.com/EranMorkon/AMTS.git
synced 2023-12-28 16:48:38 +00:00
392 lines
9.4 KiB
C
392 lines
9.4 KiB
C
/*
|
|
Ethernet shield test program
|
|
Copyright (C) 2018 Andreas Mieke
|
|
Copyright (C) 2010 Arduino LLC
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "socket.h"
|
|
|
|
// Check if address is a net addres 0.0.0.0
|
|
#define is_net_addr(addr) ((addr[0] == 0x00) && \
|
|
(addr[1] == 0x00) && \
|
|
(addr[2] == 0x00) && \
|
|
(addr[3] == 0x00))
|
|
|
|
// Check if address is broadcast address 255.255.255.255
|
|
#define is_broadcast_addr(addr) ((addr[0] == 0xFF) && \
|
|
(addr[1] == 0xFF) && \
|
|
(addr[2] == 0xFF) && \
|
|
(addr[3] == 0xFF))
|
|
|
|
// Check if port is valid (not 0)
|
|
#define is_valid_port(port) (port != 0x00)
|
|
|
|
static uint16_t local_port;
|
|
|
|
uint8_t ETH_socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
|
|
{
|
|
// Check if protocol is supported
|
|
if ((protocol == ETH_SMR_TCP) || (protocol == ETH_SMR_UDP) || (protocol == ETH_SMR_IPRAW) || (protocol == ETH_SMR_MACRAW) || (protocol == ETH_SMR_PPPoE))
|
|
{
|
|
// Close socket, if open
|
|
ETH_close(s);
|
|
// Set the mode register to the protocol, plus eventual flags
|
|
ETH_writeSnMR(s, protocol | flag);
|
|
if (port != 0) {
|
|
// If port is not 0 (0 on client mode) write port to the port register
|
|
ETH_writeSnPORT(s, port);
|
|
}
|
|
else {
|
|
// Write a random port to the port register (for client mode)
|
|
local_port++;
|
|
ETH_writeSnPORT(s, local_port);
|
|
}
|
|
|
|
// Execute the open socket command
|
|
ETH_exec_socket_cmd(s, ETH_SCR_OPEN);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t ETH_socket_status(SOCKET s)
|
|
{
|
|
// Read the status register and return it
|
|
uint8_t tmp = ETH_readSnSR(s);
|
|
return tmp;
|
|
}
|
|
|
|
void ETH_close(SOCKET s)
|
|
{
|
|
// Execute close socket and disable interrupts
|
|
ETH_exec_socket_cmd(s, ETH_SCR_CLOSE);
|
|
ETH_writeSnIR(s, 0xFF);
|
|
}
|
|
|
|
uint8_t ETH_connect(SOCKET s, uint8_t * addr, uint16_t port)
|
|
{
|
|
// Check if port and address is valid
|
|
if (is_net_addr(addr) || is_broadcast_addr(addr) || !is_valid_port(port))
|
|
return 0;
|
|
|
|
// Write IP to destination register
|
|
ETH_writeSnDIPR(s, addr);
|
|
// Write port to destination register
|
|
ETH_writeSnDPORT(s, port);
|
|
// Execute connect
|
|
ETH_exec_socket_cmd(s, ETH_SCR_CONNECT);
|
|
return 1;
|
|
}
|
|
|
|
void ETH_disconnect(SOCKET s)
|
|
{
|
|
// Execute disconnect
|
|
ETH_exec_socket_cmd(s, ETH_SCR_DISCON);
|
|
}
|
|
|
|
uint8_t ETH_listen(SOCKET s)
|
|
{
|
|
// If state is not initzialized, return
|
|
if (ETH_readSnSR(s) != ETH_SSR_INIT) {
|
|
return 0;
|
|
}
|
|
// Execute the listen command
|
|
ETH_exec_socket_cmd(s, ETH_SCR_LISTEN);
|
|
return 1;
|
|
}
|
|
|
|
uint16_t ETH_send(SOCKET s, const uint8_t * buf, uint16_t len)
|
|
{
|
|
uint8_t status=0;
|
|
uint16_t ret=0;
|
|
uint16_t freesize=0;
|
|
|
|
// If data is bigger then Tx memory, split it
|
|
if (len > ETH_SSIZE)
|
|
ret = ETH_SSIZE;
|
|
else
|
|
ret = len;
|
|
|
|
do
|
|
{
|
|
// Write data to Tx memory
|
|
freesize = ETH_get_TX_free_size(s);
|
|
status = ETH_readSnSR(s);
|
|
if ((status != ETH_SSR_ESTABLISHED) && (status != ETH_SSR_CLOSE_WAIT))
|
|
{
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
while (freesize < ret);
|
|
|
|
// Start data processing and execute send command
|
|
ETH_send_data_processing(s, (uint8_t *)buf, ret);
|
|
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
|
|
|
|
// Check interrupt if everything is okay
|
|
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK )
|
|
{
|
|
// If socket is closed set the state locally right
|
|
if (ETH_readSnSR(s) == ETH_SSR_CLOSED )
|
|
{
|
|
ETH_close(s);
|
|
return 0;
|
|
}
|
|
}
|
|
// Mark interrupt as handled
|
|
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
|
|
return ret;
|
|
}
|
|
|
|
int16_t ETH_recv(SOCKET s, uint8_t * buf, int16_t len)
|
|
{
|
|
// Check remaining size
|
|
int16_t ret = ETH_get_RX_received_size(s);
|
|
if (ret == 0)
|
|
{
|
|
// Read status
|
|
uint8_t status = ETH_readSnSR(s);
|
|
// If status is wrong, return 0 read bytes
|
|
if (status == ETH_SSR_LISTEN || status == ETH_SSR_CLOSED || status == ETH_SSR_CLOSE_WAIT)
|
|
{
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
// Return -1 if there is nothing to read
|
|
ret = -1;
|
|
}
|
|
}
|
|
// If there is more to read then we have space, just read to the supplied limit
|
|
else if (ret > len)
|
|
{
|
|
ret = len;
|
|
}
|
|
|
|
// If there is data to read and we have space, beginn processing and reading
|
|
if (ret > 0)
|
|
{
|
|
ETH_recv_data_processing(s, buf, ret, 0x00);
|
|
ETH_exec_socket_cmd(s, ETH_SCR_RECV);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int16_t ETH_recv_available(SOCKET s)
|
|
{
|
|
// Check if data is available to read
|
|
return ETH_get_RX_received_size(s);
|
|
}
|
|
|
|
uint16_t ETH_peek(SOCKET s, uint8_t *buf)
|
|
{
|
|
// Receive one byte
|
|
ETH_recv_data_processing(s, buf, 1, 1);
|
|
return 1;
|
|
}
|
|
|
|
uint16_t ETH_sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
|
|
{
|
|
uint16_t ret=0;
|
|
|
|
// If write size is bigger then memory, limit to memory
|
|
if (len > ETH_SSIZE) ret = ETH_SSIZE;
|
|
else ret = len;
|
|
|
|
// Check if address and port is right
|
|
if (is_net_addr(addr) || !is_valid_port(port) || ret == 0) {
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
// Set address and port to send to
|
|
ETH_writeSnDIPR(s, addr);
|
|
ETH_writeSnDPORT(s, port);
|
|
|
|
// Process data and send it
|
|
ETH_send_data_processing(s, (uint8_t *)buf, ret);
|
|
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
|
|
|
|
// Wait for the data to be sent
|
|
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK)
|
|
{
|
|
// If time out reset send and timout interrupts
|
|
if (ETH_readSnIR(s) & ETH_SIR_TIMEOUT)
|
|
{
|
|
ETH_writeSnIR(s, (ETH_SIR_SEND_OK | ETH_SIR_TIMEOUT));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Reset send ok interrupt
|
|
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
uint16_t ETH_recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port)
|
|
{
|
|
uint8_t head[8];
|
|
uint16_t data_len=0;
|
|
uint16_t ptr=0;
|
|
|
|
// Check if there is something to receive
|
|
if (len > 0)
|
|
{
|
|
// Get the receive pointer
|
|
ptr = ETH_readSnRX_RD(s);
|
|
// Handle receiving according to socket type
|
|
switch (ETH_readSnMR(s) & 0x07)
|
|
{
|
|
case ETH_SMR_UDP :
|
|
ETH_read_data(s, ptr, head, 0x08);
|
|
ptr += 8;
|
|
addr[0] = head[0];
|
|
addr[1] = head[1];
|
|
addr[2] = head[2];
|
|
addr[3] = head[3];
|
|
*port = head[4];
|
|
*port = (*port << 8) + head[5];
|
|
data_len = head[6];
|
|
data_len = (data_len << 8) + head[7];
|
|
|
|
ETH_read_data(s, ptr, buf, data_len);
|
|
ptr += data_len;
|
|
|
|
ETH_writeSnRX_RD(s, ptr);
|
|
break;
|
|
|
|
case ETH_SMR_IPRAW :
|
|
ETH_read_data(s, ptr, head, 0x06);
|
|
ptr += 6;
|
|
|
|
addr[0] = head[0];
|
|
addr[1] = head[1];
|
|
addr[2] = head[2];
|
|
addr[3] = head[3];
|
|
data_len = head[4];
|
|
data_len = (data_len << 8) + head[5];
|
|
|
|
ETH_read_data(s, ptr, buf, data_len);
|
|
ptr += data_len;
|
|
|
|
ETH_writeSnRX_RD(s, ptr);
|
|
break;
|
|
|
|
case ETH_SMR_MACRAW:
|
|
ETH_read_data(s, ptr, head, 2);
|
|
ptr+=2;
|
|
data_len = head[0];
|
|
data_len = (data_len<<8) + head[1] - 2;
|
|
|
|
ETH_read_data(s, ptr, buf, data_len);
|
|
ptr += data_len;
|
|
ETH_writeSnRX_RD(s, ptr);
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
ETH_exec_socket_cmd(s, ETH_SCR_RECV);
|
|
}
|
|
return data_len;
|
|
}
|
|
|
|
void ETH_flush(SOCKET s)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
uint16_t ETH_igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
|
|
{
|
|
uint16_t ret=0;
|
|
|
|
if (len > ETH_SSIZE)
|
|
ret = ETH_SSIZE;
|
|
else
|
|
ret = len;
|
|
|
|
if (ret == 0)
|
|
return 0;
|
|
|
|
// Process and send IGMP data
|
|
ETH_send_data_processing(s, (uint8_t *)buf, ret);
|
|
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
|
|
|
|
// Wairt for data to be sent or timeout
|
|
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK)
|
|
{
|
|
if (ETH_readSnIR(s) & ETH_SIR_TIMEOUT)
|
|
{
|
|
ETH_close(s);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Reset interrupt
|
|
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
|
|
return ret;
|
|
}
|
|
|
|
int ETH_start_UDP(SOCKET s, uint8_t* addr, uint16_t port)
|
|
{
|
|
// Check if address and port are valid
|
|
if (is_net_addr(addr) || !is_valid_port(port))
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
// Write IP and port
|
|
ETH_writeSnDIPR(s, addr);
|
|
ETH_writeSnDPORT(s, port);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
uint16_t ETH_buffer_data(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len)
|
|
{
|
|
uint16_t ret = 0;
|
|
if (len > ETH_get_TX_free_size(s))
|
|
{
|
|
ret = ETH_get_TX_free_size(s);
|
|
}
|
|
else
|
|
{
|
|
ret = len;
|
|
}
|
|
ETH_send_data_processing_offset(s, offset, buf, ret);
|
|
return ret;
|
|
}
|
|
|
|
int ETH_send_UDP(SOCKET s)
|
|
{
|
|
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
|
|
|
|
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK)
|
|
{
|
|
if (ETH_readSnIR(s) & ETH_SIR_TIMEOUT)
|
|
{
|
|
ETH_writeSnIR(s, (ETH_SIR_SEND_OK | ETH_SIR_TIMEOUT));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
|
|
return 1;
|
|
}
|