#include "server.h"
/*##################################################################################
EXTERNAL VARIABLES
##################################################################################*/
extern UART_HandleTypeDef huart6;
extern USART_prop_ptr usartProp;
//extern char dataPacket[64];
/*##################################################################################
INTERNAL GLOBAL VARIABLES
##################################################################################*/
struct tcp_pcb* server_pcb;
char tcpDataPacket[TCP_WND+1];
uint32_t tcpDataLen = 0;
uint8_t serverHasConnection = 0;
/*##################################################################################
STATIC FUNCTIONS DEFINITIONS
##################################################################################*/
static err_t tcpServerAccept(void *arg, struct tcp_pcb *newpcb, err_t err);
static err_t tcpServerRecvClbck(void *arg, struct tcp_pcb *tpcb, struct pbuf *p , err_t err);
static void tcpServerErrorClbck(void *arg, err_t err);
static err_t tcpServerPollClbck(void *arg, struct tcp_pcb *tpcb);
static err_t tcpServerSentClbck(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcpServerSendData(struct tcp_pcb *tpcb, struct ServerStruct *es);
static void tcpServerCloseConnection(struct tcp_pcb *tpcb, struct ServerStruct *es);
static void tcpStoreData(struct tcp_pcb *tpcb, struct ServerStruct *es);
/*##################################################################################
FUNCTIONS
##################################################################################*/
/*==============================================
tcp_recv(…) - Is used to initialize callback function
tcp_sent(…) - Specify a callback function
tcp_sndbuf(…) - Get the maximum amount of data that can be sent
tcp_write(…) - To enqueue the data
tcp_output(…) - To force the data to be sent
==============================================*/
/*==============================================
LWIP Client Incoming
* @param arg: not used
* @param newpcb: pointer on tcp_pcb struct for the newly created tcp connection
* @param err: not used
* @retval err_t: error status
==============================================*/
static err_t tcpServerAccept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
#ifdef __MDEBUG__
if(serverHasConnection < MEMP_NUM_TCP_PCB)
{
#endif
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
tcp_setprio(newpcb, TCP_PRIO_MIN);
struct ServerStruct *es; //allocate structure es to maintain tcp connection informations
es = (struct ServerStruct *)mem_malloc(sizeof(struct ServerStruct));
if (es != NULL)
{
es->state = ES_S_ACCEPTED;
es->server_pcb = newpcb;
es->p = NULL;
tcp_arg(newpcb, es);
tcp_recv(newpcb, tcpServerRecvClbck); //initialize tcp_recv callback function
tcp_err(newpcb, tcpServerErrorClbck); //initialize tcp_err callback function
tcp_sent(newpcb, tcpServerSentClbck); //initialize tcp_sent callback function
tcp_poll(newpcb, tcpServerPollClbck, 0); //initialize tcp_poll callback function
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV: GOT_CONNECTION\n\r", 24, 0x0F);
++serverHasConnection;
//#ifdef __MDEBUG__
if(serverHasConnection >= MEMP_NUM_TCP_PCB)
{
}
//#endif
ret_err = ERR_OK;
}
else
{
tcpServerCloseConnection(newpcb, es);
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_ACCEPT_ERR_MEM\n\r", 23, 0x0F);
ret_err = ERR_MEM;
}
#ifdef __MDEBUG__
}
else
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_NOFREESLOTS\n\r", 20, 0x0F);
ret_err = ERR_ABRT;
}
#endif
return ret_err;
}
/*==============================================
TCP Server Receive Callback
==============================================*/
static err_t tcpServerRecvClbck(void *arg, struct tcp_pcb *tpcb, struct pbuf *p , err_t err)
{
err_t ret_err;
struct ServerStruct *es;
LWIP_ASSERT("arg != NULL", arg != NULL);
es = (struct ServerStruct *)arg;
if(p == NULL) /* if we receive an empty tcp frame from client => close connection */
{
es->state = ES_S_CLOSING;
if(es->p == NULL)
{
//tcp_recved(tpcb, p->tot_len);
tcpServerCloseConnection(tpcb, es); /* we're done sending, close connection */
}
else
{
/* we're not done yet */
tcp_sent(tpcb, tcpServerSentClbck); //acknowledge received packet
tcpServerSendData(tpcb, es); //send remaining data
}
ret_err = ERR_OK;
}
/* a non empty frame was received from client but for some reason err != ERR_OK */
else if(err != ERR_OK)
{
if(p != NULL) //some data in buffer, free it
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRVDBG: recv_busy\n\r", 22, 0x0F);
es->p = NULL;
pbuf_free(p);
}
ret_err = err;
}
else if(es->state == ES_S_ACCEPTED) //accepted 1st part of packet
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRVDBG: s_accepted\n\r", 23, 0x0F);
es->state = ES_S_RECEIVED;
es->p = p;
tcp_sent(tpcb, tcpServerSentClbck);
/////////////////////=========================////////////////////////
//some action after receiving new part of data:
//tcpServerSendData(tpcb, es);
tcpStoreData(tpcb, es);
/////////////////////=========================////////////////////////
ret_err = ERR_OK;
}
else if(es->state == ES_S_RECEIVED) //receiving other parts of packet
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRVDBG: s_received ", 22, 0x0F);
if(es->p == NULL)
{
HAL_UART_Transmit(&huart6, (uint8_t*)"OK\n\r", 4, 0x0F);
es->p = p;
//tcpServerSendData(tpcb, es);
tcpStoreData(tpcb, es);
}
else
{
HAL_UART_Transmit(&huart6, (uint8_t*)"--\n\r", 4, 0x0F);
struct pbuf* ptr;
ptr = es->p;
pbuf_chain(ptr, p);
}
ret_err = ERR_OK;
}
else //free buffer
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRVDBG: recv_end\n\r", 22, 0x0F);
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
/*
if(tcpDataLen > 5)
{
strncpy(tcpDataPacket + tcpDataLen, "\r\n", 2);
tcpDataLen += 2;
tcp_write(tpcb, tcpDataPacket, tcpDataLen, 1);
tcpDataLen = 0;
}
*/
return ret_err;
}
/*==============================================
TCP Server Error Callback
==============================================*/
static void tcpServerErrorClbck(void *arg, err_t err)
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_ERR\n\r", 12, 0x0F);
}
/*==============================================
TCP Server Poll Callback
==============================================*/
static err_t tcpServerPollClbck(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct ServerStruct *es;
es = (struct ServerStruct*)arg;
//turn on LED
if(es != NULL)
{
if(es->p != NULL)
{
//some error?
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_POLL_BUFF\n\r", 18, 0x0F);
}
else
{
if(es->state == ES_S_CLOSING)
{
tcpServerCloseConnection(tpcb, es);
}
/////////////////////=========================////////////////////////
// if(usartProp.isText)
// {
// usartProp.isText = 0;
// }
/////////////////////=========================////////////////////////
}
ret_err = ERR_OK;
}
else
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_POLL_ABRT\n\r", 18, 0x0F);
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}
/*==============================================
TCP Server Sent Callback
==============================================*/
static err_t tcpServerSentClbck(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct ServerStruct *es;
LWIP_UNUSED_ARG(len);
es = (struct ServerStruct*)arg;
es->retries = 0;
if(es->p != NULL)
{
tcpServerSendData(tpcb, es);
}
else
{
if(es->state == ES_S_CLOSING)
{ tcpServerCloseConnection(tpcb, es); }
}
return ERR_OK;
}
/*==============================================
TCP Send Data from Server
==============================================*/
static void tcpServerSendData(struct tcp_pcb *tpcb, struct ServerStruct *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;
while((wr_err == ERR_OK) &&
(es->p != NULL) &&
(es->p->len <= tcp_sndbuf(tpcb)))
{
ptr = es->p;
wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
if(wr_err == ERR_OK)
{
u16_t plen;
plen = ptr->len;
es->p = ptr->next;
if(es->p != NULL)
{
pbuf_ref(es->p);
}
pbuf_free(ptr);
tcp_recved(tpcb, plen);
}
else if(wr_err == ERR_MEM)
{
es->p = ptr;
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_SND_ERR_MEM\n\r", 22, 0x0F);
}
else
{
//other problem
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_SND_OTHER\n\r", 18, 0x0F);
}
}
}
/*==============================================
TCP Close Connection
==============================================*/
static void tcpServerCloseConnection(struct tcp_pcb *tpcb, struct ServerStruct *es)
{
HAL_UART_Transmit(&huart6, (uint8_t*)"close\n\r", 7, 0x0F);
if(serverHasConnection)
{
--serverHasConnection;
}
//remove all callbacks
tcp_arg(es->server_pcb, NULL);
tcp_sent(es->server_pcb, NULL);
tcp_recv(es->server_pcb, NULL);
tcp_err(es->server_pcb, NULL);
tcp_poll(es->server_pcb, NULL, 0);
if(es != NULL)
{
mem_free(es);
}
tcp_close(tpcb);
}
/*==============================================
LWIP Server Initialization
==============================================*/
void tcpServerInit(void)
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_INIT\n\r", 14, 0x0F);
server_pcb = tcp_new(); //create new tcp pcb structure
if(server_pcb != NULL)
{
err_t err;
err = tcp_bind(server_pcb, IP_ADDR_ANY, SERVER_LISTEN_PORT); //bind tcp port
if(err == ERR_OK)
{
//HAL_UART_Transmit(&huart6, (uint8_t*)"srvini\n\r", 8, 0x0F);
server_pcb = tcp_listen(server_pcb); //start tcp listening
tcp_accept(server_pcb, tcpServerAccept); //callback function tcpServerAccept when connection occurs
}
else
{
HAL_UART_Transmit(&huart6, (uint8_t*)"TCPSRV_INIT_ERR_MEM\n\r", 22, 0x0F);
memp_free(MEMP_TCP_PCB, server_pcb); //deallocate pcb
}
}
}
/*==============================================
Send String to Server (NOT!!! to connected Host)
==============================================*/
void tcpServerSendString(char* bufStr) //send string to server
{
/*
if(serverHasConnection)
{
usartProp.isText = 1;
tcp_sent(ss->server_pcb, tcpServerSentClbck);
tcp_write(ss->server_pcb, (void*)bufStr, strlen(bufStr), 1);
tcp_recved(ss->server_pcb, strlen(bufStr));
}
else
{
}
usartProp.usartBufCnt = 0;
*/
}
/*==============================================
Save Data from Buffer
==============================================*/
static void tcpStoreData(struct tcp_pcb *tpcb, struct ServerStruct *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;
while((wr_err == ERR_OK) &&
(es->p != NULL) &&
(es->p->len <= tcp_sndbuf(tpcb)))
{
ptr = es->p;
strncpy(tcpDataPacket+tcpDataLen, ptr->payload, ptr->len);
tcpDataLen += ptr->len;
u16_t plen;
plen = ptr->len;
es->p = ptr->next;
if(es->p != NULL)
{
pbuf_ref(es->p);
}
pbuf_free(ptr);
tcp_recved(tpcb, plen);
}
}