///////////////////////////////////////////////////////////////////////////////
//
//                          IMPORTANT NOTICE
//
// The following open source license statement does not apply to any
// entity in the Exception List published by FMSoft.
//
// For more information, please visit:
//
// https://www.fmsoft.cn/exception-list
//
//////////////////////////////////////////////////////////////////////////////
/*
 *   This file is part of MiniGUI, a mature cross-platform windowing 
 *   and Graphics User Interface (GUI) support system for embedded systems
 *   and smart IoT devices.
 * 
 *   Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
 *   Copyright (C) 1998~2002, WEI Yongming
 * 
 *   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 <http://www.gnu.org/licenses/>.
 * 
 *   Or,
 * 
 *   As this program is a library, any link to this program must follow
 *   GNU General Public License version 3 (GPLv3). If you cannot accept
 *   GPLv3, you need to be licensed from FMSoft.
 * 
 *   If you have got a commercial license of this program, please use it
 *   under the terms and conditions of the commercial license.
 * 
 *   For more information about the commercial license, please refer to
 *   <http://www.minigui.com/en/about/licensing-policy/>.
 */
/*
** abs_signal_driver.c: this is the process file of abs signal driver module
**
** Author:	zangguangtong
*/

#include <stdio.h>
#include <sys/fcntl.h>

#ifdef SIGNAL_SOCKET_TEST
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <asm/dsp.h>
#include "abs_signal_driver.h"


int ABSSIG_translate_msg_from_driver_to_app (void *pmsg, ABS_SIG_INFO *asi);
int ABSSIG_translate_msg_from_app_to_driver(void *pmsg, ABS_SIG_INFO *asi);

int __mg_g_abssig_debug_mode = 0;
int __mg_g_abssig_fd = ABSSIG_INVALID_FD;

int ABSSIG_open_tel_device (ABS_SIG_INFO *asi)
{	
#ifndef SIGNAL_SOCKET_TEST
	
	if (NULL == asi)
	{
		return ABSSIG_FAIL;
	}
	
	asi->dev_fd = ABSSIG_INVALID_FD;

	switch(asi->dev_type)
	{
		case UD_DSP_1:
		{
			int socket_val;
			char name[20];
				
			sprintf(name, "/dev/tel");
			socket_val = open(name,O_RDWR);
			if(socket_val == ABSSIG_INVALID_FD)
			{
				DBGABSSIG_ERR(("Can't open tel device in ABSSIG_open_tel_device!\n"));
				asi->dev_fd = ABSSIG_INVALID_FD;
				return ABSSIG_INVALID_FD;
			}
	
			__mg_g_abssig_fd = asi->dev_fd = socket_val;			
            fprintf(stderr, "opened dev_fd %d\n", socket_val);
			return ABSSIG_SUCCESS;
		}
		default:
			return ABSSIG_FAIL;
	}
#else
	int test_socket;
	struct sockaddr_in sin;
	int tos;
	int opt;
	int len;

	int socket_val;
	char name[20];
	sprintf(name, "/dev/tel");
	socket_val = open(name,O_RDWR);
	if(socket_val == ABSSIG_INVALID_FD)
	{
		DBGABSSIG_ERR(("Can't open tel device in ABSSIG_open_tel_device!\n"));
		return ABSSIG_INVALID_FD;
	}

  	test_socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (test_socket == -1)
	{
		DBGABSSIG_ERR(("UDP socket open failed!"));
		return -1;
	}

	bzero(&sin, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	sin.sin_port = htons(1556);
	if (bind(test_socket, (struct sockaddr *)&sin, sizeof(sin)) == -1)
	{
		DBGABSSIG_ERR(("UDP(%d) socket bind failed!\n"));
		close(test_socket);
		return -1;
	}
	/*
	opt = 1; 
	len = sizeof(opt);   
   	setsockopt(test_socket,SOL_SOCKET,SO_REUSEADDR,&opt,&len); 
	if (fcntl(test_socket, F_SETFL, O_NONBLOCK) == -1) 
	{
		DBGABSSIG_ERR(("fcntl fail!\n"));
		close(test_socket);
		return -1;
	}
	*/
	
	__mg_g_abssig_fd = test_socket;
	return test_socket;
#endif
}


int ABSSIG_close_tel_device (ABS_SIG_INFO *asi)
{
	if (NULL == asi)
	{
		return ABSSIG_FAIL;
	}
	
	switch(asi->dev_type)
	{
		case UD_DSP_1:
			{
				close(asi->dev_fd);
				__mg_g_abssig_fd = ABSSIG_INVALID_FD;
				asi->dev_fd = ABSSIG_INVALID_FD;
			}
			break;
		default:
			return ABSSIG_FAIL;
	}
	/*
	if(fd != __mg_g_abssig_fd)
	{
		DBGABSSIG_ERR(("Input fd is wrong in ABSSIG_close_tel_device!Input fd is %d and fd of tel device is %d \n",fd,__mg_g_abssig_fd));
		return ABSSIG_FAIL;
	}
	close(fd); 
	__mg_g_abssig_fd = ABSSIG_INVALID_FD;
	*/
	return ABSSIG_SUCCESS;
}


int ABSSIG_receive_msg_from_driver(ABS_SIG_INFO *asi)
{
#ifndef SIGNAL_SOCKET_TEST
	int translate_result = ABSSIG_FAIL;
	if (NULL == asi)
	{
		return ABSSIG_FAIL;
	}
	
	switch(asi->dev_type)
	{
		case UD_DSP_1:
			{
			telesignal_msg tel_msg;

			if(asi->dev_fd == ABSSIG_INVALID_FD)
			{
				DBGABSSIG_ERR(("FD of tel device is invalid in ABSSIG_receive_msg_from_driver!\n"));
				return ABSSIG_FAIL;
			}

			read(__mg_g_abssig_fd,&tel_msg,sizeof(tel_msg));			
			translate_result = ABSSIG_translate_msg_from_driver_to_app(&tel_msg, asi);
			}
			break;
		default:
			break;
	}
	return translate_result;
#else	
	struct sockaddr from;
	socklen_t len;
	telesignal_msg tel_msg;
	int translate_result;	
	
	recvfrom(__mg_g_abssig_fd, &tel_msg, sizeof(telesignal_msg), 0, &from, &len);
	tel_msg.type = ntohl(tel_msg.type);
	translate_result = ABSSIG_translate_msg_from_driver_to_app(&tel_msg);
	return translate_result;
#endif

}


int ABSSIG_send_msg_to_driver (ABS_SIG_INFO *asi)
{
#ifndef SIGNAL_SOCKET_TEST

	if (NULL == asi)
	{
		return ABSSIG_FAIL;
	}

	switch(asi->dev_type)
	{
		case UD_DSP_1:
		{
			telesignal_msg tel_msg;
			int translate_result;

			if(asi->dev_fd == ABSSIG_INVALID_FD)
			{
				DBGABSSIG_ERR(("FD of tel device is invalid in ABSSIG_send_msg_to_driver!\n"));
				return ABSSIG_FAIL;
			}

			translate_result = ABSSIG_translate_msg_from_app_to_driver(&tel_msg, asi);
			if(translate_result == ABSSIG_FAIL)
			{
				DBGABSSIG_ERR(("Fails when translate the message from application,so can't send message to driver in ABSSIG_send_msg_to_driver! \n"));
				return ABSSIG_FAIL;
			}			
			write(asi->dev_fd, &tel_msg, sizeof(tel_msg));
		}
			break;
		default:
			return ABSSIG_FAIL;
	}
	return ABSSIG_SUCCESS;
#else
	char message_type[256];

	switch(abssig_signal_msg->msg_type)
	{
		case SIGNAL_SIG2DRV_SWITCH_PSTN:
			strcpy(message_type,"switch to PSTN");
			break;
		case SIGNAL_SIG2DRV_SWITCH_VOIP:
			strcpy(message_type,"switch to VOIP");
			break;
		case SIGNAL_SIG2DRV_DIAL_TONE:
			strcpy(message_type,"play dial tone");
			break;
		case SIGNAL_SIG2DRV_DIAL_TONE_STOP:
			strcpy(message_type,"stop dial tone");
			break;
		case SIGNAL_SIG2DRV_CALLBACK_TONE:
			strcpy(message_type,"play callback tone");
			break;
		case SIGNAL_SIG2DRV_CALLBACK_TONE_STOP:
			strcpy(message_type,"stop callback tone");
			break;
		case SIGNAL_SIG2DRV_BUSY_TONE:
			strcpy(message_type,"play busy tone");
			break;
		case SIGNAL_SIG2DRV_BUSY_TONE_STOP:
			strcpy(message_type,"stop busy tone");
			break;
		case SIGNAL_SIG2DRV_BLARE_TONE:
			strcpy(message_type,"play blare tone");
			break;
		case SIGNAL_SIG2DRV_BLARE_TONE_STOP:
			strcpy(message_type,"stop blare tone");
			break;
		case SIGNAL_SIG2DRV_START_RING:
			strcpy(message_type,"start ring");
			break;
		case SIGNAL_SIG2DRV_STOP_RING:
			strcpy(message_type,"stop ring");
			break;
		case SIGNAL_SIG2DRV_PSTN_OFFHOOK:
			strcpy(message_type,"notify PSTN OFFHOOK");
			break;
		case SIGNAL_SIG2DRV_PSTN_DTMF:
			strcpy(message_type,"notify PSTN DTMF");
			break;
		default:
			strcpy(message_type,"wrong message type");
			break;
	}
	DBGABSSIG_INFO(("\nReceived message is %s in ABSSIG_send_msg_to_driver!",message_type));
	DBGABSSIG_INFO(("\nLine number is %d in ABSSIG_send_msg_to_driver! \n",abssig_signal_msg->line_num));
	return ABSSIG_SUCCESS;
#endif
}


int ABSSIG_translate_msg_from_driver_to_app(void *pmsg, ABS_SIG_INFO *asi)
{
	if (NULL == asi)
	{
		return ABSSIG_FAIL;
	}
	if(NULL == pmsg)
	{
		DBGABSSIG_ERR(("tel message is NULL in ABSSIG_translate_msg_from_driver_to_app!\n"));
		return ABSSIG_FAIL;
	}
	
	switch(asi->dev_type)
	{
		case UD_DSP_1:
		{
			telesignal_msg *tel_msg = (telesignal_msg *)pmsg;
			switch(tel_msg->type)
			{
				case TELE_SIGNAL_DRV2TSK_OFFHOOK:
					asi->dev_msg = TEL_RMSG_OFFHOOK;
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;
					
				case TELE_SIGNAL_DRV2TSK_ONHOOK:
					asi->dev_msg = TEL_RMSG_ONHOOK;
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;
					
				case TELE_SIGNAL_DRV2TSK_DTMF:
					asi->dev_msg = tel_msg->message.dtmf_data.phonenum[0];
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;
					
				case TELE_SIGNAL_DRV2TSK_PSTN_DIAL_TONE:
					asi->dev_msg = TEL_RMSG_INVALID;
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;
					
				case TELE_SIGNAL_DRV2TSK_PSTN_RING_START:
					asi->dev_msg = TEL_RMSG_INVALID;
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;
					
				case TELE_SIGNAL_DRV2TSK_PSTN_RING_STOP:
					asi->dev_msg = TEL_RMSG_INVALID;
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;

				case TELE_SIGNAL_DRV2TSK_RINGBACK:				
					asi->dev_msg = TEL_RMSG_INVALID;
					asi->dev_id = tel_msg->message.control_data.linenum;
					break;
				
				case TELE_SIGNAL_DRV2TSK_VOICE_DATA:			
					asi->dev_msg = TEL_RMSG_INVALID;
					asi->dev_id = tel_msg->message.control_data.linenum;
					return ABSSIG_FAIL;
				
				default:
					return ABSSIG_FAIL;
			}
		}
			break;
		default:
			return ABSSIG_FAIL;
	}
	return ABSSIG_SUCCESS;
}

int ABSSIG_translate_msg_from_app_to_driver(void *pmsg, ABS_SIG_INFO *asi)
{
	if (NULL == asi)
	{
		return ABSSIG_FAIL;
	}
	if (NULL == pmsg)
	{
		DBGABSSIG_ERR(("tel message is NULL in ABSSIG_translate_msg_from_app_to_driver!\n"));
		return ABSSIG_FAIL;
	}

	switch (asi->dev_type)
	{
		case UD_DSP_1:
		{
			telesignal_msg *tel_msg = (telesignal_msg *)pmsg;
			
			switch(asi->dev_msg)
			{
				case TEL_SMSG_SWITCH_PSTN:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_SWITCH_PSTN;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_SWITCH_VOIP:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_SWITCH_VOIP;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_DIAL_TONE:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_DIAL_TONE;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
				case TEL_SMSG_DIAL_TONE_STOP:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_DIAL_TONE_STOP;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_CALLBACK_TONE:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_OTHERRING_TONE;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_CALLBACK_TONE_STOP:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_OTHERRING_TONE_STOP;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_BUSY_TONE:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_BUSY_TONE;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_BUSY_TONE_STOP:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_BUSY_TONE_STOP;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_BLARE_TONE:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_BLARE_TONE;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
				case TEL_SMSG_BLARE_TONE_STOP:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_BLARE_TONE_STOP;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_START_RING:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_RING_TONE;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_STOP_RING:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_RING_TONE_STOP;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_PSTN_OFFHOOK:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_PSTN_OFFHOOK;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_PSTN_DTMF:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_PSTN_DTMF;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				case TEL_SMSG_PSTN_ENDCALL:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_PSTN_ENDCALL;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

#if 0
				case TEL_SMSG_PSTN_TALK:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_PSTN_TALK;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
#endif

				case TEL_SMSG_SWITCH_HANDSET:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_SWITCH_HANDSET;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
				case TEL_SMSG_SWITCH_SPEAKER:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_SWITCH_SPEAKER;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
				case TEL_SMSG_KEY_TONE:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_KEY_TONE;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
				case TEL_SMSG_KEY_VOLINC:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_VOL_INC;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;
				case TEL_SMSG_KEY_VOLDEC:
					tel_msg->type = TELE_SIGNAL_TSK2DRV_VOL_DEC;
					tel_msg->message.control_data.linenum = asi->dev_id;
					break;

				default:
					DBGABSSIG_ERR(("The type of message from signal module is wrong in ABSSIG_translate_msg_from_app_to_driver!message type is %d \n",asi->dev_msg));
					return ABSSIG_FAIL;

			}
		}
			break;
		
		default :
			return ABSSIG_FAIL;
	}
	return ABSSIG_SUCCESS;
}


