//
//  bt_avctp_target.c
//
//  Bluetooth Protocol Stack - AVDTP Target side server
//  Copyright (C) 2018 Toyohiko Togashi tog001@nifty.com
//
//
//  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/>
//
//
//  Reference:
//      Bluetooth SIG (www.bluetooth.com)
//          Adopted Specifications
//          Protocols
//              AVCTP A/V Control Transport 1.4
//
//  Update history
//  ---------- ----- -------------------------------------------
//  2018.03.07 v0.0  First cording
//

#include "bt_avctp_target.h"
#include "bt_spec_avctp.h"

#define MAX(a,b)    ((a) > (b) ? (a) : (b))
#define MIN(a,b)    ((a) < (b) ? (a) : (b))
//#define DEBUG

//
//  Debug
//
#ifdef DEBUG
#include <stdio.h>                      // Debug
#define DEBUGP(...)     printf(__VA_ARGS__)
#else
#define DEBUGP(...)
#endif

//
//  Global area
//
struct bt_avctp_ifa {	// Max 8bytes
	unsigned char	initFlag;
};


//
//  Internal subroutines
//
// User own code default routine
void _bt_avct_connect(struct bt_l2capChannel *ch) {
	DEBUGP("bt_avct_connect\n");
    return;
}
void _bt_avct_disconnect(struct bt_l2capChannel *ch) {
	DEBUGP("bt_avct_disconnect\n");
    return;
}
int _bt_avct_messageRec(struct bt_l2capChannel *ch, int *pid, int *transaction, int *type, unsigned char *data, size_t *length) {
	DEBUGP("bt_avct_messageRec: pid=0x%04x tran=%d type=%s len=%d\n", *pid, *transaction, *type == 1 ? "cmd" : "resp", *length);
    return(0);
}

void bt_avct_connect()    __attribute__ ((weak, alias ("_bt_avct_connect")));
void bt_avct_disconnect() __attribute__ ((weak, alias ("_bt_avct_disconnect")));
int  bt_avct_messageRec() __attribute__ ((weak, alias ("_bt_avct_messageRec")));

//
//  Server
//
size_t bt_avctpTarget(struct bt_l2capChannel *ch, unsigned char *inBuff, size_t inLen, unsigned char *outBuff, size_t outSize)
{
    size_t l;

	l = 0;
	if (ch) {
		struct bt_avctp_ifa	*ifa;

	    ifa = (struct bt_avctp_ifa *)(ch->dynamic.userArea);
	    if (ifa->initFlag == 0) {
	    	bt_avct_connect(ch);
	    	ifa->initFlag = 1;
	    }
		if (ifa->initFlag && (ch->link == NULL)) {
			bt_avct_disconnect(ch);
	    	ifa->initFlag = 0;
		}
		if (inLen > 0) {
			struct bt_avctp_PDU_Format *p;
			struct bt_avctp_PDU_Format *q;
			int		transaction;
			int		packetType;
			int		type;

			p = (struct bt_avctp_PDU_Format *)inBuff;
			q = (struct bt_avctp_PDU_Format *)outBuff;

			transaction = (p->header & AVCTP_HEADER_TransactionLabel_Mask) >> AVCTP_HEADER_TransactionLabel_Shift;
			packetType  = (p->header & AVCTP_HEADER_PacketType_Mask);
			type        = (p->header & AVCTP_HEADER_CR_Mask) == AVCTP_HEADER_CR_Command ? 1 : 2;

			if (packetType == AVCTP_HEADER_PacketType_SinglePacket) {
				int		pid;
				size_t	len;
				int		rc;

#define HEAD_SIZE	(sizeof(q->header) + sizeof(q->body.singlePacket))

				len = inLen - HEAD_SIZE;
				pid = AVCTP_UINT16(p->body.startPacket.ProfileIdentifier);

				rc = bt_avct_messageRec(ch, &pid, &transaction, &type, p->body.singlePacket.message, &len);
				if (rc > 0) {
					q->header = transaction << AVCTP_HEADER_TransactionLabel_Shift
							  | AVCTP_HEADER_PacketType_SinglePacket
							  | (type == 1 ? AVCTP_HEADER_CR_Command : AVCTP_HEADER_CR_Response)
							  | AVCTP_HEADER_IPID_Normal;
					AVCTP_STORE16(q->body.singlePacket.ProfileIdentifier, pid);
					memcpy(&(q->body.singlePacket.message), &(p->body.singlePacket.message), len);
					l = HEAD_SIZE + len;
				} else if (rc < 0) {
					q->header = (p->header & (~AVCTP_HEADER_IPID_Mask)) | AVCTP_HEADER_IPID_Invalid;
					l = sizeof(q->header);
				}
			} else {	// Reject message
				q->header = (p->header & (~AVCTP_HEADER_IPID_Mask)) | AVCTP_HEADER_IPID_Invalid;
				l = sizeof(q->header);
			}

		} else {
			struct bt_avctp_PDU_Format *q;
			int		transaction;
			int		type;
			int		pid;
			size_t	len;
			int		rc;

			q = (struct bt_avctp_PDU_Format *)outBuff;
			pid         = 0;
			transaction = 0;
			type        = 0;
			len         = 0;

			rc = bt_avct_messageRec(ch, &pid, &transaction, &type, q->body.singlePacket.message, &len);
			if (rc > 0) {
				q->header = transaction << AVCTP_HEADER_TransactionLabel_Shift
						  | AVCTP_HEADER_PacketType_SinglePacket
						  | (type == 1 ? AVCTP_HEADER_CR_Command : AVCTP_HEADER_CR_Response)
						  | AVCTP_HEADER_IPID_Normal;
				AVCTP_STORE16(q->body.singlePacket.ProfileIdentifier, pid);
				l = HEAD_SIZE + len;
			}
		}
	}

	return(l);
}
