//
//  bt_att_db.c
//
//  Bluetooth Protocol Stack - Attribute Database manager
//  Copyright (C) 2013-2016 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/>
//
//
//  Update history
//  ---------- ----- -------------------------------------------
//  2013.04.25 v0.0  First cording
//  2014.02.23 v0.1a Sample database template
//  2014.03.07 v0.2  Change API, argument "value" is void*
//  2015.02.20 v0.3b The new "bt_att_data.c" is independent of the ATT database user data
//  2016.01.24 v0.3c Bug fix, value area an align error
//  2017.02.11 v0.3h The new "bt_config.h"
//
#include <stddef.h>
#include <string.h>
#include "bt_att_db.h"
#include "bt_spec_gatt.h"
#include "bt_spec_att.h"        // ADD 2017.02.11


//
//  ATT DB access subroutines
//

// Sequential read
struct bt_attDbEntry    *bt_attDbGetNext(   // OUT: Result data
        int     *id)                        // IN,OUT: Access pointer (Start: *id = 0)
{
    struct bt_attDbEntry *p;

    if (bt_attDb.entryNum == 0) {
        p = NULL;
    } else {
        if (*id >= bt_attDb.entryNum) {
            p = NULL;
            *id = 0;
        } else {
            p = &bt_attDb.entry[*id];
            (*id)++;
        }
    }
    return(p);
}

                                        // Direct read
struct bt_attDbEntry    *bt_attDbFind(  // OUT: Result data
        unsigned short  startHandle,    // IN: Search key
        unsigned short  endHandle,      // IN: Search key
        unsigned char   *types,         // IN: Search key (UUID, NULL=All match)
//      unsigned char   *value,         // IN: Search key (NULL=All match)  CHG 2014.03.07
        void            *value,         // IN: Search key (NULL=All match)  CHG 2014.03.07
        size_t          valueLen)       // IN: "value" bytes
{
    struct bt_attDbEntry    *p;
    int                     i;

    i = 0;
    while((p = bt_attDbGetNext(&i)) != NULL) {
        if (p->handle < startHandle) {
            continue;
        }
        if (p->handle > endHandle) {
            p = NULL;
            break;
        }
        if ((types != NULL) && memcmp(p->types, types, sizeof(p->types))) {
            continue;
        }
        if ((value != NULL) && memcmp(p->value, value, valueLen)) {
            continue;
        }
        break;
    }

    return(p);
}

                                        // Direct update
int bt_attDbUpdate(                     // OUT: Return code (Negative value is error)
        unsigned short  handle,         // IN: Target
//      unsigned char   *value,         // IN: Update data  CHG 2014.03.07
        void            *value,         // IN: Update data  CHG 2014.03.07
        size_t          valueLen)       // IN: "value" bytes
{
//  const unsigned char     clientConfig[] = {INIT_UUID16TO128(GATT_Characteristic_Descriptors_Client_Characteristic_Configuration)};       // DEL 2015.02.20
    const unsigned char     clientConfig[] = {ATT_UUID16TO128_DATA(GATT_Characteristic_Descriptors_Client_Characteristic_Configuration)};   // ADD 2015.02.20
    struct bt_attDbEntry    *p;

    if ((p = bt_attDbFind(handle, handle, NULL, NULL, 0)) != NULL) {
        if (valueLen > sizeof(p->value)) {
            valueLen = sizeof(p->value);
        }
        memcpy(p->value, value, valueLen);
        p->valueLen = valueLen;

        // User callback
//      bt_attDbNotification(handle, value, valueLen);      // DEL 2016.1.24
        bt_attDbNotification(handle, p->value, valueLen);   // ADD 2016.1.24

        // Special DB record relation
        if (memcmp(clientConfig, p->types, sizeof(clientConfig)) == 0) {
            union bt_gatt_Attribute_Value   *v;
            int                             c;
            unsigned short                  h;

            v = (union bt_gatt_Attribute_Value  *)p->value;
            c = ATT_UINT16(v->Client_Characteristic_Configuration.Characteristic_Configuration_Bits);
            h = handle - 2;             // !! DB structure rule is this
            if ((p = bt_attDbFind(h, h, NULL, NULL, 0)) != NULL) {
                if (c & GATT_Client_Characteristic_Configuration_Notification) {
                    p->properties |= ATT_DB_PROPERTIES_NOTIFY;
                } else {
                    p->properties &= ~ATT_DB_PROPERTIES_NOTIFY;
                }
                if (c & GATT_Client_Characteristic_Configuration_Indication) {
                    p->properties |= ATT_DB_PROPERTIES_INDICATE;
                } else {
                    p->properties &= ~ATT_DB_PROPERTIES_INDICATE;
                }
            }
        }
    }
    return((p != NULL) ? 0 : -1);
}
