//
//  bt_spec_att.h
//
//  Bluetooth Protocol Stack - ATT(Attribute Protocol) Specification definition
//  Copyright (C) 2013-2019 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)
//          BLUETOOTH SPECIFICATION Version 4.0
//          [Vol 3] Core System Package [Host volume]
//           Part F: ATTRIBUTE PROTOCOL (ATT)
//
//  Update history
//  ---------- ----- -------------------------------------------
//  2013.01.21 v0.0  First cording
//  2013.04.21 v0.1  Commit
//  2013.11.03 v0.1a Add macro ATT_INITUUID128()
//  2015.02.20 v0.3b Change of data initialize macro
//  2017.02.06 v0.3g Bug fix
//  2019.02.09 v0.4c Add macro ATT_INT16/24/32()
//
#ifndef BT_SPEC_ATT_H_
#define BT_SPEC_ATT_H_

#include <stdint.h>

struct bt_att_PDU_Format {
    uint8_t Attribute_Opcode;
    union {
        struct {
            uint8_t Request_Opcode_In_Error;
            uint8_t Attribute_Handle_In_Error[2];
            uint8_t Error_Code;
        }       Error_Response;

        struct {
            uint8_t Client_Rx_MTU[2];
        }       Exchange_MTU_Request;

        struct {
            uint8_t Server_Rx_MTU[2];
        }       Exchange_MTU_Response;

        struct {
            uint8_t Starting_Handle[2];
            uint8_t Ending_Handle[2];
        }       Find_Information_Request;

        struct {
            uint8_t Format;
#ifdef DEL                              // DEL START 2017.02.06
            union Information_Data {
                uint8_t Format0[18];
                struct {
                    uint8_t Handle[2];
                    uint8_t UUID16[2];
                }       Format1;
                struct {
                    uint8_t Handle[2];
                    uint8_t UUID128[16];
                }       Format2;
            }       Information_Data[];
#else                                   // DEL END - ADD START 2017.02.06
            union {
                struct {
                    uint8_t Handle[2];
                    uint8_t UUID16[2];
                }       Format1[0];
                struct {
                    uint8_t Handle[2];
                    uint8_t UUID128[16];
                }       Format2[0];
            };
#endif                                  // ADD END 2017.02.06
        }       Find_Information_Response;

        struct {
            uint8_t Starting_Handle[2];
            uint8_t Ending_Handle[2];
            uint8_t Attribute_Type[2];
            uint8_t Attribute_Value[];
        }       Find_By_Type_Value_Request;

        struct {
            struct {
                uint8_t Found_Attribute_Handle[2];
                uint8_t Group_End_Handle[2];
            }       Handles_Information_List[1]; // 1..
        }       Find_By_Type_Value_Response;

        struct {
            uint8_t Starting_Handle[2];
            uint8_t Ending_Handle[2];
            uint8_t Attribute_Type[16];         // 2 or 16 UUID
        }       Read_By_Type_Request;

        struct {
            uint8_t    Length;
            struct {
                uint8_t Attribute_Handle[2];
                uint8_t Attribute_Value[];      // Length - 2
            }       Attribute_Data_List;
        }       Read_By_Type_Response;

        struct {
            uint8_t Attribute_Handle[2];
        }       Read_Request;

        struct {
            uint8_t Attribute_Value[0];
        }       Read_Response;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Value_Offset[2];
        }       Read_Blob_Request;

        struct {
            uint8_t Part_Attribute_Value[0];
        }       Read_Blob_Response;

        struct {
            uint8_t Set_Of_Handles[2][1];       // 2..
        }       Read_Multiple_Request;

        struct {
            uint8_t Set_Of_Values[1];
        }       Read_Multiple_Response;

        struct {
            uint8_t Starting_Handle[2];
            uint8_t Ending_Handle[2];
            uint8_t Attribute_Group_Type[16];   // 2 or 16
        }       Read_by_Group_Type_Request;

        struct {
            uint8_t Length;
            struct {
                uint8_t Attribute_Handle[2];
                uint8_t End_Group_Handle[2];
                uint8_t Attribute_Value[];
            }       Attribute_Data_List;
        }       Read_by_Group_Type_Response;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Attribute_Value[];
        }       Write_Request;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Attribute_Value[];
        }       Write_Command;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Value_Offset[2];
            uint8_t Part_Attribute_Value[];
        }       Prepare_Write_Request;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Value_Offset[2];
            uint8_t Part_Attribute_Value[];
        }       Prepare_Write_Response;

        struct {
            uint8_t Flags;
        }       Execute_Write_Request;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Attribute_Value[];
        }       Handle_Value_Notification;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Attribute_Value[];
        }       Handle_Value_Indication;

        struct {
            uint8_t Attribute_Handle[2];
            uint8_t Attribute_Value[];
//          uint8_t Authentication_Signature[12];
        }       Signed_Write_Command;

    }       Attribute_Parameters;
//    uint8_t    Authentication_Signature[];
}  __attribute__ ((packed)) ;

#define ATT_PDU_Format_HeadSize                    1        // Opcode

#define ATT_Opcode_Error_Response               0x01    // Request_Opcode_In_Error,Attribute_Handle_In_Error,Error_Code
#define ATT_Opcode_Exchange_MTU_Request         0x02    // Client_Rx_MTU
#define ATT_Opcode_Exchange_MTU_Response        0x03    // Server_Rx_MTU
#define ATT_Opcode_Find_Information_Request     0x04    // Starting_Handle,Ending_Handle,UUID
#define ATT_Opcode_Find_Information_Response    0x05    // Format,Information_Data
#define ATT_Opcode_Find_By_Type_Value_Request   0x06    // Starting_Handle,Ending_Handle,Attribute_Type,Attribute_Value
#define ATT_Opcode_Find_By_Type_Value_Response  0x07    // Handles_Information_List
#define ATT_Opcode_Read_By_Type_Request         0x08    // Starting_Handle,Ending_Handle,UUID
#define ATT_Opcode_Read_By_Type_Response        0x09    // Length,Attribute_Data_List
#define ATT_Opcode_Read_Request                 0x0A    // Attribute_Handle
#define ATT_Opcode_Read_Response                0x0B    // Attribute_Value
#define ATT_Opcode_Read_Blob_Request            0x0C    // Attribute_Handle,Value_Offset
#define ATT_Opcode_Read_Blob_Response           0x0D    // Part_Attribute_Value
#define ATT_Opcode_Read_Multiple_Request        0x0E    // Handle_Set
#define ATT_Opcode_Read_Multiple_Response       0x0F    // Value_Set
#define ATT_Opcode_Read_by_Group_Type_Request   0x10    // Start_Handle,Ending_Handle,UUID
#define ATT_Opcode_Read_by_Group_Type_Response  0x11    // Length,Attribute_Data_List
#define ATT_Opcode_Write_Request                0x12    // Attribute_Handle,Attribute_Value
#define ATT_Opcode_Write_Response               0x13    //
#define ATT_Opcode_Write_Command                0x52    // Attribute_Handle,Attribute_Value
#define ATT_Opcode_Prepare_Write_Request        0x16    // Attribute_Handle,Value_Offset,Part_Attribute_Value
#define ATT_Opcode_Prepare_Write_Response       0x17    // Attribute_Handle,Value_Offset,Part_Attribute_Value
#define ATT_Opcode_Execute_Write_Request        0x18    // Flags
#define ATT_Opcode_Execute_Write_Response       0x19    //
#define ATT_Opcode_Handle_Value_Notification    0x1B    // Attribute_Handle,Attribute_Value
#define ATT_Opcode_Handle_Value_Indication      0x1D    // Attribute_Handle,Attribute_Value
#define ATT_Opcode_Handle_Value_Confirmation    0x1E    //
#define ATT_Opcode_Signed_Write_Command         0xD2    // Attribute_Handle,Attribute_Value,Authentication_Signature

#define ATT_Error_Code_Invalid_Handle                   0x01    // The_attribute_handle_given_was_not_valid_on_this_server.
#define ATT_Error_Code_Read_Not_Permitted               0x02    // The_attribute_cannot_be_read.
#define ATT_Error_Code_Write_Not_Permitted              0x03    // The_attribute_cannot_be_written.
#define ATT_Error_Code_Invalid_PDU                      0x04    // The_attribute_PDU_was_invalid.
#define ATT_Error_Code_Insufficient_Authentication      0x05    // The_attribute_requires_authentication_before_it_can_be_read_or_written.
#define ATT_Error_Code_Request_Not_Supported            0x06    // Attribute_server_does_not_support_the_request_received_from_the_client.
#define ATT_Error_Code_Invalid_Offset                   0x07    // Offset_specified_was_past_the_end_of_the_attribute.
#define ATT_Error_Code_Insufficient_Authorization       0x08    // The_attribute_requires_authorization_before_it_can_be_read_or_written.
#define ATT_Error_Code_Prepare_Queue_Full               0x09    // Too_many_prepare_writes_have_been_queued.
#define ATT_Error_Code_Attribute_Not_Found              0x0A    // No_attribute_found_within_the_given_attri-_bute_handle_range.
#define ATT_Error_Code_Attribute_Not_Long               0x0B    // The_attribute_cannot_be_read_or_written_using_the_Read_Blob_Request
#define ATT_Error_Code_Insufficient_Encryption_Key_Size 0x0C    // The_Encryption_Key_Size_used_for_encrypting_this_link_is_insufficient.
#define ATT_Error_Code_Invalid_Attribute_Value_Length   0x0D    // The_attribute_value_length_is_invalid_for_the_operation.
#define ATT_Error_Code_Unlikely_Error                   0x0E    // The_attribute_request_that_was_requested_has_encountered_an_error_that_was_unlikely,_and_therefore_could_not_be_completed_as_requested.
#define ATT_Error_Code_Insufficient_Encryption          0x0F    // The_attribute_requires_encryption_before_it_can_be_read_or_written.
#define ATT_Error_Code_Unsupported_Group_Type           0x10    // The_attribute_type_is_not_a_supported_grouping_attribute_as_defined_by_a_higher_layer_specification.
#define ATT_Error_Code_Insufficient_Resources           0x11    // Insufficient_Resources_to_complete_the_request

#define ATT_Format_Handles_and_16bit_Bluetooth_UUIDs    0x01    // 2+2bytes
#define ATT_Format_Handles_and_128bit_UUIDs             0x02    // 2+16bytes

#define ATT_Flags_Cancel_all_prepared_writes                    0x00
#define ATT_Flags_Immediately_write_all_pending_prepared_values 0x01

//
//  Implement tool
//
// Byte order normalize
#define ATT_UINT16(a)               (uint16_t)((a)[0] | ((a)[1] << 8))
#define ATT_UINT24(a)               (uint32_t)((a)[0] | ((a)[1] << 8) | ((a)[2] << 16))
#define ATT_UINT32(a)               (uint32_t)((a)[0] | ((a)[1] << 8) | ((a)[2] << 16) | ((a)[3] << 24))
#define ATT_INT16(a)                (int16_t)((a)[0] | ((a)[1] << 8))									// ADD 2019.02.09
#define ATT_INT24(a)                (int32_t)((a)[0] | ((a)[1] << 8) | ((a)[2] << 16))					// ADD 2019.02.09
#define ATT_INT32(a)                (int32_t)((a)[0] | ((a)[1] << 8) | ((a)[2] << 16) | ((a)[3] << 24))	// ADD 2019.02.09
#define ATT_STORE16(d,s)            ((d)[0] = (uint8_t)(s), (d)[1] = (uint8_t)((s) >> 8))
#define ATT_STORE24(d,s)            ((d)[0] = (uint8_t)(s), (d)[1] = (uint8_t)((s) >> 8), (d)[2] = (uint8_t)((s) >> 16))
#define ATT_STORE32(d,s)            ((d)[0] = (uint8_t)(s), (d)[1] = (uint8_t)((s) >> 8), (d)[2] = (uint8_t)((s) >> 16), (d)[3] = (uint8_t)((s) >> 24))

#define ATT_STOREUUID16TO128(d,s)   (d)[0]=0xFB,(d)[1]=0x34,(d)[2]=0x9b,(d)[3]=0x5f,(d)[4]=0x80,(d)[5]=0x00,(d)[6]=0x00,(d)[7]=0x80,(d)[8]=0x00,(d)[9]=0x10,(d)[10]=0x00,(d)[11]=0x00,(d)[12]=(s)[0],(d)[13]=(s)[1],(d)[14]=0x00,(d)[15]=0x00
#define ATT_STOREUUID128TO16(d,s)   (d)[0]=(s)[12],(d)[1]=(s)[13]

#ifdef DELETE                           // DEL START 2015.02.20
#define ATT_INIT16(s)               (uint8_t)(s), (uint8_t)((s) >> 8)
#define ATT_INIT24(s)               (uint8_t)(s), (uint8_t)((s) >> 8), (uint8_t)((s) >> 16)
#define ATT_INIT32(s)               (uint8_t)(s), (uint8_t)((s) >> 8), (uint8_t)((s) >> 16), (uint8_t)((s) >> 24)
#define ATT_INITUUID16TO128(a)      0xFB,0x34,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,((uint8_t)(a)),((uint8_t)((a)>>8)),0x00,0x00
//#define ATT_INITUUID128(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)    (p),(o),(n),(m),(l),(k),(j),(i),(h),(g),(f),(e),(d),(c),(b),(a)      // ADD 2013.11.03, DEL 2015.02.20
#endif                                  // DEL END/ADD START 2015.02.20
#define ATT_UINT16_DATA(s)           (uint8_t)(s), (uint8_t)((s) >> 8)
#define ATT_UINT24_DATA(s)           (uint8_t)(s), (uint8_t)((s) >> 8), (uint8_t)((s) >> 16)
#define ATT_UINT32_DATA(s)           (uint8_t)(s), (uint8_t)((s) >> 8), (uint8_t)((s) >> 16), (uint8_t)((s) >> 24)
#define ATT_INT16_DATA(s)            (int8_t)(s), (int8_t)((s) >> 8)											// ADD 2019.02.09
#define ATT_INT24_DATA(s)            (int8_t)(s), (int8_t)((s) >> 8), (int8_t)((s) >> 16)						// ADD 2019.02.09
#define ATT_INT32_DATA(s)            (int8_t)(s), (int8_t)((s) >> 8), (int8_t)((s) >> 16), (int8_t)((s) >> 24)	// ADD 2019.02.09
#define ATT_UUID16TO128_DATA(a)      0xFB,0x34,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,((uint8_t)(a)),((uint8_t)((a)>>8)),0x00,0x00
#define ATT_UUID128_DATA(aaaaaaaa,bbbb,cccc,dddd,eeeeeeeeeeee) \
    (uint8_t)(eeeeeeeeeeee),\
    (uint8_t)((eeeeeeeeeeee)>>8),\
    (uint8_t)((eeeeeeeeeeee)>>16),\
    (uint8_t)((eeeeeeeeeeee)>>24),\
    (uint8_t)((eeeeeeeeeeee)>>32),\
    (uint8_t)((eeeeeeeeeeee)>>40),\
    (uint8_t)(dddd),\
    (uint8_t)((dddd)>>8),\
    (uint8_t)(cccc),\
    (uint8_t)((cccc)>>8),\
    (uint8_t)(bbbb),\
    (uint8_t)((bbbb)>>8),\
    (uint8_t)(aaaaaaaa),\
    (uint8_t)((aaaaaaaa)>>8),\
    (uint8_t)((aaaaaaaa)>>16),\
    (uint8_t)((aaaaaaaa)>>24)
                                        // ADD END 2015.02.20
#endif /* BT_SPEC_ATT_H_ */
