/*
  xdrv_52_3_berry_zigbee.ino - Berry scripting language, native fucnctions

  Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry

  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/>.
*/

// Mappgin from internal light and a generic `light_state` Berry class

#ifdef USE_BERRY
#ifdef USE_ZIGBEE

#include "berry.h"
#include "be_func.h"

extern "C" {
  extern const bclass be_class_zb_device;

  // Zigbee Device `zd`
  const void* zd_init(const class Z_Device* device) {
    return device;
  }

  int32_t zd_shortaddr(const class Z_Device* d) {
    return d->shortaddr;
  }
  const void* zd_longaddr(const class Z_Device* d, size_t *size, void* p2) {
    *size = 8;    // 64 bits
    return &d->longaddr;
  }

  const char* zd_manufacturer(const class Z_Device* d) {
    return d->manufacturerId ? d->manufacturerId : "";
  }
  extern const char* zd_model(const class Z_Device* d) {
    return d->modelId ? d->modelId : "";
  }
  extern const char* zd_name(const class Z_Device* d) {
    return d->friendlyName ? d->friendlyName : "";
  }
  bool zd_router(const class Z_Device* d) {
    return d->is_router;
  }
  bool zd_hidden(const class Z_Device* d) {
    return d->hidden;
  }
  bool zd_reachable(const class Z_Device* d) {
    return d->reachable;
  }
  int32_t zd_lastseen(const class Z_Device* d) {
    return d->last_seen;
  }
  int32_t zd_lqi(const class Z_Device* d) {
    return d->lqi == 255 ? -1 : d->lqi;
  }
  int32_t zd_battery(const class Z_Device* d) {
    return d->batt_percent == 255 ? -1 : d->batt_percent;
  }
  int32_t zd_battery_lastseen(const class Z_Device* d) {
    return d->batt_last_seen;   // TODO not yet known
  }
}

extern "C" {
  // Zigbee Coordinator `zc`
  int zc_info(struct bvm *vm);
  int zc_info(struct bvm *vm) {
    int32_t top = be_top(vm); // Get the number of arguments
    if (top == 1) {  // no argument (instance only)
      be_newobject(vm, "map");
      be_map_insert_int(vm, "channel", Settings->zb_channel);
      be_map_insert_int(vm, "tx_radio", Settings->zb_txradio_dbm);
      char tmp[24];
      ext_snprintf_P(tmp, sizeof(tmp), "0x%04X", Settings->zb_pan_id);
      be_map_insert_str(vm, "pan_id_hex", tmp);
      be_map_insert_int(vm, "pan_id", Settings->zb_pan_id);
      ext_snprintf_P(tmp, sizeof(tmp), "0x%_X", &Settings->zb_ext_panid);
      be_map_insert_str(vm, "ext_pan_id", tmp);
      ext_snprintf_P(tmp, sizeof(tmp), "0x%04X", localShortAddr);
      be_map_insert_str(vm, "shortaddr_hex", tmp);
      be_map_insert_int(vm, "shortaddr", localShortAddr);
      ext_snprintf_P(tmp, sizeof(tmp), "0x%_X", &localIEEEAddr);
      be_map_insert_str(vm, "longaddr", tmp);
      be_pop(vm, 1);
      be_return(vm);
    }
    be_raise(vm, kTypeError, nullptr);
  }

  int zc_item(struct bvm *vm);
  int zc_item(struct bvm *vm) {
    int32_t top = be_top(vm); // Get the number of arguments
    if (zigbee.init_phase) {
      be_raise(vm, "internal_error", "zigbee not started");
    }
    if (top >= 2 && (be_isint(vm, 2) || be_isstring(vm, 2))) {
      const Z_Device & device = be_isint(vm, 2) ? zigbee_devices.findShortAddr(be_toint(vm, 2))
                                                : zigbee_devices.parseDeviceFromName(be_tostring(vm, 2));
      if (!device.valid()) {
        be_raise(vm, "value_error", "unknown device");
      }

      be_pushntvclass(vm, &be_class_zb_device);
      be_pushcomptr(vm, (void*) &device);
      be_call(vm, 1);
      be_pop(vm, 1);
      be_return(vm);
    }
    be_raise(vm, kTypeError, nullptr);
  }

  int32_t zc_size(void*) {
    return zigbee_devices.devicesSize();
  }

  // stop zigbee, abort
  // The abort state corresponds to state machine stopped but init not finished
  void zc_abort(void) {
    zigbee.active = false;
    zigbee.state_machine = false;    // not ready
    zigbee.init_phase = false;
  }

  // iterator for devices in the coordinator's list of devices
  // upval 0: index from 0 to size-1
  static int zc_iter_closure(bvm *vm)
  {
      /* for better performance, we operate the upvalues
      * directly without using by the stack. */
      bntvclos *func = (bntvclos*) var_toobj(vm->cf->func);
      bvalue *uv0 = be_ntvclos_upval(func, 0)->value;
      bint idx = var_toint(uv0); /* upvalue[0] => lower */
      if (idx >= zigbee_devices.devicesSize()) {
          be_stop_iteration(vm);
      }
      var_toint(uv0) = idx + 1; /* set upvale[0] */
      be_pushntvclass(vm, &be_class_zb_device);
      const Z_Device & device = zigbee_devices.isKnownIndexDevice(idx);
      be_pushcomptr(vm, (void*) &device);
      be_call(vm, 1);
      be_pop(vm, 1);
      be_return(vm);
  }

  int zc_iter(bvm *vm);
  int zc_iter(bvm *vm) {
    if (zigbee.init_phase) {
      be_raise(vm, "internal_error", "zigbee not started");
    }
    be_pushntvclosure(vm, zc_iter_closure, 1);
    be_pushint(vm, 0);
    be_setupval(vm, -2, 0);
    be_pop(vm, 1);
    be_return(vm);
  }

  int32_t callBerryZigbeeDispatcher(const char* event, const class ZCLFrame* zcl_frame, const class Z_attribute_list* attr_list, int32_t idx);
  int32_t callBerryZigbeeDispatcher(const char* event, const class ZCLFrame* zcl_frame, const class Z_attribute_list* attr_list, int32_t idx) {
    int32_t ret = 0;
    bvm *vm = berry.vm;

    if (nullptr == vm) { return ret; }
    checkBeTop();
    be_getglobal(vm, PSTR("zigbee"));   // global object of type zb_coord()
    if (!be_isnil(vm, -1)) {
      be_getmethod(vm, -1, PSTR("dispatch"));   // method dispatch
      if (!be_isnil(vm, -1)) {
        be_pushvalue(vm, -2); // add instance as first arg
        be_pushstring(vm, event != nullptr ? event : "");
        be_pushcomptr(vm, (void*) zcl_frame);
        be_pushcomptr(vm, (void*) attr_list);
        be_pushint(vm, idx);
        BrTimeoutStart();
        ret = be_pcall(vm, 5);   // 5 arguments
        BrTimeoutReset();
        if (ret != 0) {
          be_error_pop_all(berry.vm);             // clear Berry stack
          return ret;
        }
        be_pop(vm, 5);
        if (be_isint(vm, -1) || be_isbool(vm, -1)) {
          if (be_isint(vm, -1)) { ret = be_toint(vm, -1); }
          if (be_isbool(vm, -1)) { ret = be_tobool(vm, -1); }
        }
      }
      be_pop(vm, 1);  // remove method
    }
    be_pop(vm, 1);  // remove instance object
    checkBeTop();
    return ret;
  }

}

/*********************************************************************************************\
 * Mapping for zcl_frame_ntv
 *
\*********************************************************************************************/
extern "C" {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"   // avoid warnings since we're using offsetof() in a risky way

  extern const be_ctypes_structure_t be_zigbee_zcl_frame_struct = {
    sizeof(ZCLFrame),  /* size in bytes */
    13,  /* number of elements */
    nullptr,
    (const be_ctypes_structure_item_t[13]) {
      { "cluster", offsetof(ZCLFrame, cluster), 0, 0, ctypes_u16, 0 },
      { "cluster_specific", offsetof(ZCLFrame, clusterSpecific), 0, 0, ctypes_u8, 0 },
      { "cmd", offsetof(ZCLFrame, cmd), 0, 0, ctypes_u8, 0 },
      { "direct", offsetof(ZCLFrame, direct), 0, 0, ctypes_u8, 0 },
      { "dstendpoint", offsetof(ZCLFrame, dstendpoint), 0, 0, ctypes_u8, 0 },
      { "groupaddr", offsetof(ZCLFrame, groupaddr), 0, 0, ctypes_u16, 0 },
      { "manuf", offsetof(ZCLFrame, manuf), 0, 0, ctypes_u16, 0 },
      { "need_response", offsetof(ZCLFrame, needResponse), 0, 0, ctypes_u8, 0 },
      { "payload_ptr", offsetof(ZCLFrame, payload), 0, 0, ctypes_ptr32, 0 },
      { "shortaddr", offsetof(ZCLFrame, shortaddr), 0, 0, ctypes_u16, 0 },
      { "srcendpoint", offsetof(ZCLFrame, srcendpoint), 0, 0, ctypes_u8, 0 },
      { "transactseq", offsetof(ZCLFrame, transactseq), 0, 0, ctypes_u8, 0 },
      { "transactseq_set", offsetof(ZCLFrame, transacSet), 0, 0, ctypes_u8, 0 },
  }};

#pragma GCC diagnostic pop
}

/*********************************************************************************************\
 * Mapping for zcl_attribute_ntv
 *
\*********************************************************************************************/
extern "C" {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"   // avoid warnings since we're using offsetof() in a risky way

  extern const be_ctypes_structure_t be_zigbee_zcl_attribute_list_struct = {
    sizeof(Z_attribute_list),  /* size in bytes */
    3,  /* number of elements */
    nullptr,
    (const be_ctypes_structure_item_t[3]) {
      { "_groupaddr", offsetof(Z_attribute_list, group_id), 0, 0, ctypes_u16, 0 },
      { "_lqi", offsetof(Z_attribute_list, lqi), 0, 0, ctypes_u8, 0 },
      { "_src_ep", offsetof(Z_attribute_list, src_ep), 0, 0, ctypes_u8, 0 },
  }};

  extern const be_ctypes_structure_t be_zigbee_zcl_attribute_struct = {
    sizeof(Z_attribute),  /* size in bytes */
    11,  /* number of elements */
    nullptr,
    (const be_ctypes_structure_item_t[12]) {
      { "_attr_id", offsetof(Z_attribute, attr_id), 0, 0, ctypes_u16, 0 },
      { "_cluster", offsetof(Z_attribute, cluster), 0, 0, ctypes_u16, 0 },
      { "_cmd", offsetof(Z_attribute, attr_id), 0, 0, ctypes_u8, 0 },       // low 8 bits of attr_id
      { "_cmd_general", offsetof(Z_attribute, attr_id) + 1, 1, 1, ctypes_u8, 0 },       // bit #1 of byte+1
      { "_direction", offsetof(Z_attribute, attr_id) + 1, 0, 1, ctypes_u8, 0 },         // bit #0 of byte+1
      { "_iscmd", offsetof(Z_attribute, key_is_cmd), 0, 0, ctypes_u8, 0 },
      { "attr_base", offsetof(Z_attribute, attr_base), 0, 0, ctypes_u32, 0 },
      { "attr_divider", offsetof(Z_attribute, attr_divider), 0, 0, ctypes_u32, 0 },
      { "attr_multiplier", offsetof(Z_attribute, attr_multiplier), 0, 0, ctypes_u32, 0 },
      { "attr_type", offsetof(Z_attribute, attr_type), 0, 0, ctypes_u8, 0 },
      // { "key", offsetof(Z_attribute, key), 0, 0, ctypes_ptr32, 0 },
      // { "key_is_pmem", offsetof(Z_attribute, key_is_pmem), 0, 0, ctypes_u8, 0 },
      // { "key_is_str", offsetof(Z_attribute, key_is_str), 0, 0, ctypes_u8, 0 },
      { "key_suffix", offsetof(Z_attribute, key_suffix), 0, 0, ctypes_u8, 0 },
      { "manuf", offsetof(Z_attribute, manuf), 0, 0, ctypes_u16, 0 },
      // { "type", offsetof(Z_attribute, type), 0, 0, ctypes_u8, 0 },
      // { "val_float", offsetof(Z_attribute, val), 0, 0, ctypes_float, 0 },
      // { "val_i32", offsetof(Z_attribute, val), 0, 0, ctypes_i32, 0 },
      // { "val_str_raw", offsetof(Z_attribute, val_str_raw), 0, 0, ctypes_u8, 0 },
      // { "val_ptr", offsetof(Z_attribute, val), 0, 0, ctypes_ptr32, 0 },
      // { "val_u32", offsetof(Z_attribute, val), 0, 0, ctypes_u32, 0 },
  }};

#pragma GCC diagnostic pop
}

/*********************************************************************************************\
 * Functions for zcl_frame
 *
\*********************************************************************************************/
extern "C" {
  void* zfn_get_bytes(void* sbuf_ptr, size_t *len_bytes) {
    if (sbuf_ptr == NULL || len_bytes == NULL) { return NULL; }
    const SBuffer &sbuf = (const SBuffer&) sbuf_ptr;

    *len_bytes = sbuf.getLen();
    return sbuf.getBuffer();
  }

  void zfn_set_bytes(void* sbuf_ptr, const uint8_t* bytes, size_t len_bytes) {
    if (sbuf_ptr == NULL || bytes == NULL) { return; }

    SBuffer &sbuf = (SBuffer&) sbuf_ptr;

    sbuf.reserve(len_bytes);  // make sure it's large enough
    sbuf.setLen(0);           // clear content
    sbuf.addBuffer(bytes, len_bytes); // add content of bytes() buffer
  }
}

/*********************************************************************************************\
 * Functions for zcl_attribute
 *
\*********************************************************************************************/
extern "C" {
  extern const bclass be_class_zcl_attribute_list;
  extern const bclass be_class_zcl_attribute;
  extern const bclass be_class_zcl_attribute_ntv;

  void zat_zcl_attribute(struct bvm *vm, const Z_attribute *attr);

  // Pushes the Z_attribute_list on the stack as a simple list
  // Adds the output on top of stack and does not change rest of stack (stack size incremented by 1)
  void zat_zcl_attribute_list_inner(struct bvm *vm, const Z_attribute_list* attrlist) {
    be_newobject(vm, "list");

    for (const auto & attr : *attrlist) {
      zat_zcl_attribute(vm, &attr);
      be_data_push(vm, -2);
      be_pop(vm, 1);
    }
    be_pop(vm, 1);
  }

  // Pushes the Z_attribute on the stack as `zcl_attribute_ntv`
  void zat_zcl_attribute(struct bvm *vm, const Z_attribute *attr) {
    be_pushntvclass(vm, &be_class_zcl_attribute);
    be_pushcomptr(vm, (void*) attr);

    // instantiate
    be_call(vm, 1);     // 1 parameter
    be_pop(vm, 1);
  }

  // Get typed value from zcl_attributes
  int be_zigbee_zcl_attribute_ntv_get_val(struct bvm *vm) {
    const Z_attribute *attr = (const Z_attribute*) be_tobytes(vm, 1, NULL);
    // value
    switch (attr->type) {
      case Za_type::Za_bool:
        be_pushbool(vm, attr->val.uval32 ? btrue : bfalse);
        break;
      case Za_type::Za_uint:
      case Za_type::Za_int:
        be_pushint(vm, attr->val.ival32);
        break;
      case Za_type::Za_float:
        be_pushreal(vm, (breal)attr->val.fval);
        break;
      case Za_type::Za_raw:
        be_pushbytes(vm, attr->val.bval->getBuffer(), attr->val.bval->len());
        break;
      case Za_type::Za_str:
        be_pushstring(vm, attr->val.sval);
        break;
        
      case Za_type::Za_obj:
        zat_zcl_attribute_list_inner(vm, attr->val.objval);
        break;

      case Za_type::Za_arr:
        // json_format = true;
        if (attr->val.arrval) {
          String arrval = attr->val.arrval->toString();
          be_module_load(vm, be_newstr(vm, "json"));
          be_getmember(vm, -1, "load");
          be_remove(vm, -2);      // remove module 'json'
          be_pushstring(vm, arrval.c_str());
          be_call(vm, 1);
          be_pop(vm, 1);
        } else {
          // push empty list
          be_newobject(vm, "list");
          be_pop(vm, 1);
        }
        break;

      case Za_type::Za_none:
      default:
        be_pushnil(vm);
        break;
    }

    be_return(vm);
  }

  // Initialize the Z_attribute_list memory zone with provided address
  int be_zigbee_zcl_attribute_list_ntv_init(struct bvm *vm) {
    size_t len;
    Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, &len);
    attr_list = new(attr_list) Z_attribute_list();   // "placement new" to provide a fixed address https://isocpp.org/wiki/faq/dtors#placement-new
    be_return_nil(vm);
  }

  // Deinitialize the Z_attribute_list memory zone with provided address
  int be_zigbee_zcl_attribute_list_ntv_deinit(struct bvm *vm) {
    size_t len;
    Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, &len);
    if (attr_list) {
      attr_list->~Z_attribute_list();
    }
    be_return_nil(vm);
  }

  // Size
  int be_zigbee_zcl_attribute_list_ntv_size(struct bvm *vm) {
    Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, nullptr);
    be_pushint(vm, attr_list->length());
    be_return(vm);
  }

  // Item
  int be_zigbee_zcl_attribute_list_ntv_item(struct bvm *vm) {
    int32_t argc = be_top(vm);
    if (argc >= 2) {
      int32_t idx = be_toint(vm, 2);
      Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, nullptr);
      const Z_attribute* attr = attr_list->at(idx);
      if (attr) {
        zat_zcl_attribute(vm, attr);
        be_return(vm);
      }
    }
    be_return_nil(vm);
  }

  // new_head
  int be_zigbee_zcl_attribute_list_ntv_new_head(struct bvm *vm) {
    Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, nullptr);
    Z_attribute &attr = attr_list->addHead();
    zat_zcl_attribute(vm, &attr);
    be_return(vm);
  }

  // new_tail
  int be_zigbee_zcl_attribute_list_ntv_new_tail(struct bvm *vm) {
    Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, nullptr);
    Z_attribute &attr = attr_list->addToLast();
    zat_zcl_attribute(vm, &attr);
    be_return(vm);
  }

  // Remove
  int be_zigbee_zcl_attribute_list_ntv_remove(struct bvm *vm) {
    int32_t argc = be_top(vm);
    if (argc >= 2) {
      int32_t idx = be_toint(vm, 2);
      Z_attribute_list *attr_list = (Z_attribute_list*) be_tobytes(vm, 1, nullptr);
      const Z_attribute* attr = attr_list->at(idx);
      if (attr) {
        attr_list->remove(attr);
      }
    }
    be_return_nil(vm);
  }

  // Initialize the Z_attribute memory zone with provided address
  int be_zigbee_zcl_attribute_ntv_init(struct bvm *vm) {
    size_t len;
    Z_attribute *attr = (Z_attribute*) be_tobytes(vm, 1, &len);
    attr = new(attr) Z_attribute();   // "placement new" to provide a fixed address https://isocpp.org/wiki/faq/dtors#placement-new
    be_return_nil(vm);
  }

  // Deinitialize the Z_attribute memory zone with provided address
  int be_zigbee_zcl_attribute_ntv_deinit(struct bvm *vm) {
    size_t len;
    Z_attribute *attr = (Z_attribute*) be_tobytes(vm, 1, &len);
    if (attr) {
      attr->~Z_attribute();
    }
    be_return_nil(vm);
  }

  // Set typed value from zcl_attributes
  int be_zigbee_zcl_attribute_ntv_set_val(struct bvm *vm) {
    int32_t argc = be_top(vm);
    if (argc >= 2) {
      Z_attribute *attr = (Z_attribute*) be_tobytes(vm, 1, NULL);

      if (be_isnil(vm, 2)) {
        attr->setNone();
      } else if (be_isbool(vm, 2)) {
        attr->setBool(be_tobool(vm, 2));
      } else if (be_isint(vm, 2)) {
        attr->setInt(be_toint(vm, 2));
      } else if (be_isreal(vm, 2)) {
        attr->setFloat(be_toreal(vm, 2));
      } else if (be_isstring(vm, 2)) {
        attr->setStr(be_tostring(vm, 2));
      } else if (be_isbytes(vm, 2)) {
        size_t len;
        const void* buf = be_tobytes(vm, 2, &len);
        attr->setRaw(buf, len);
      }
    }

    be_return(vm);
  }

  // returns the key as string or `nil` if no string key. Suffix is not appended
  int be_zigbee_zcl_attribute_ntv_get_key(struct bvm *vm) {
    const Z_attribute *attr = (const Z_attribute*) be_tobytes(vm, 1, NULL);
    if (attr->key_is_str)  {
      be_pushstring(vm, attr->key);
    } else {
      be_pushnil(vm);
    }
    be_return(vm);
  }

  // set string key, or remove if `nil` or no parameter
  int be_zigbee_zcl_attribute_ntv_set_key(struct bvm *vm) {
    Z_attribute *attr = (Z_attribute*) be_tobytes(vm, 1, NULL);
    int32_t argc = be_top(vm);
    if (argc >= 2 && be_isstring(vm, 2)) {
      const char* key = be_tostring(vm, 2);
      attr->setKeyName(key, false);
    } else {
      attr->setKeyId(attr->cluster, attr->attr_id);
    }
    be_return_nil(vm);
  }
}

extern "C" {
  int zigbee_test_attr(struct bvm *vm) {
    int32_t mode = be_toint(vm, 2);
    if (mode < 10) {
      //
    } else {
      Z_attribute *a = new Z_attribute();
      if (mode == 10) {
        a->setKeyId(1111, 2222);
        a->setUInt(1337);
      } else if (mode == 11) {
        a->setKeyName("super_attribute");
        a->key_suffix = 2;
        a->setFloat(3.14);
      } else if (mode == 12) {
        a->setKeyName("array");
        a->newJsonArray();
        a->val.arrval->add((int32_t)-1);
        a->val.arrval->addStr("foo");
        a->val.arrval->addStr("bar");
        a->val.arrval->addStr("bar\"baz\'toto");
      } else if (mode == 13) {
        a->setKeyName("list");
        a->newAttrList();
        Z_attribute &subattr1 = a->val.objval->addAttribute(10,20);
        subattr1.setStr("sub1");
        Z_attribute &subattr2 = a->val.objval->addAttribute(11,21);
        subattr2.setStr("sub2");
      }
      zat_zcl_attribute(vm, a);
    }
    be_return(vm);
  }


  // Creates a zcl_attributes from Z_attribute_list
  // Adds the output on top of stack and does not change rest of stack (stack size incremented by 1)
  void zat_zcl_attribute_list(struct bvm *vm, uint16_t shortaddr, const Z_attribute_list* attr_list) {
    be_pushntvclass(vm, &be_class_zcl_attribute_list);
    be_pushcomptr(vm, (void*) attr_list);
    // // instantiate
    be_call(vm, 1);     // 1 parameter
    be_pop(vm, 1);

    if (shortaddr != BAD_SHORTADDR) {
      be_pushint(vm, shortaddr);
      be_setmember(vm, -2, "shortaddr");
      be_pop(vm, 1);
    }
  }

  int zigbee_test_msg(struct bvm *vm) {
    Z_attribute_list attr_list;

    attr_list.lqi = 250;
    Z_attribute &subattr1 = attr_list.addAttribute(10,20);
    subattr1.setStr("sub1");
    Z_attribute &subattr2 = attr_list.addAttribute(11,21);
    subattr2.setStr("sub2");

    zat_zcl_attribute_list(vm, 100, &attr_list);
    be_return(vm);
  }
}

#endif // USE_ZIGBEE
#endif  // USE_BERRY
