Skip to content

Commit

Permalink
[Tizen] [lighting-app] Add GPIO control and dbus UI (#29958)
Browse files Browse the repository at this point in the history
* Add simple gpio implementation

* dbus - add xml and integrate in gn

* Integrate dbus controller into app

* Use property instead of method call

* Use gdbus_library GN template for generating iface

* Expose Matter clusters via Tizen App D-Bus

* Update for color cluster

* Fix color temperature set

* Expose Identify cluster via example app D-Bus API

* Alight D-Bus API property names with Matter

* Add led manager

* Add license

* clean unused callback

* Preserve the state of the color temperature

* Set color temperature mode as default

* Remove unused static variable

* Update signals name

* Add else to define to remove warning

* Remove unused value

* Add [-with-ui] to tinze in all_targets_linux_x64.txt

* Verify by CI that -with-ui works

* Restyled by gn

---------

Co-authored-by: Arkadiusz Bokowy <[email protected]>
Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
3 people authored and pull[bot] committed Feb 3, 2024
1 parent 36c8ca0 commit 2571257
Show file tree
Hide file tree
Showing 14 changed files with 572 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/examples-tizen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
--enable-flashbundle \
--target tizen-arm-all-clusters \
--target tizen-arm-chip-tool-ubsan \
--target tizen-arm-light \
--target tizen-arm-light-with-ui \
build \
--copy-artifacts-to out/artifacts \
"
5 changes: 5 additions & 0 deletions config/tizen/chip-gn/platform/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import("${chip_root}/config/tizen/chip-gn/args.gni")
import("${build_root}/config/linux/pkg_config.gni")
import("${chip_root}/src/platform/device.gni")

pkg_config("capi-system-peripheral-io") {
packages = [ "capi-system-peripheral-io" ]
}

pkg_config("dlog") {
packages = [ "dlog" ]
}
Expand Down Expand Up @@ -69,6 +73,7 @@ source_set("tizen") {
":glib",
":capi-appfw-preference",
":capi-system-info",
":capi-system-peripheral-io",
]

if (chip_mdns == "platform") {
Expand Down
24 changes: 24 additions & 0 deletions examples/lighting-app/tizen/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,31 @@
import("//build_overrides/chip.gni")
import("//build_overrides/tizen.gni")

import("${chip_root}/build/chip/linux/gdbus_library.gni")
import("${chip_root}/build/chip/tools.gni")
import("${chip_root}/src/app/common_flags.gni")
import("${tizen_sdk_build_root}/tizen_sdk.gni")

assert(chip_build_tools)

declare_args() {
# Enable D-Bus based UI functionality for example app
chip_examples_enable_ui = false
}

gdbus_library("chip-lighting-app-manager") {
sources = [ "xml/DBusLightApp.xml" ]
interface_prefix = "org.tizen.matter.example.lighting"
c_namespace = "LightApp"
c_generate_object_manager = true
dbus_out_dir = "dbus"
}

executable("chip-lighting-app") {
sources = [
"include/CHIPProjectAppConfig.h",
"include/LedManager.h",
"src/LedManager.cpp",
"src/main.cpp",
]

Expand All @@ -34,6 +50,14 @@ executable("chip-lighting-app") {
"${chip_root}/src/lib",
]

if (chip_examples_enable_ui) {
sources += [ "src/DBusInterface.cpp" ]
deps += [ ":chip-lighting-app-manager" ]
defines = [ "ENABLE_DBUS_UI=1" ]
} else {
defines = [ "ENABLE_DBUS_UI=0" ]
}

include_dirs = [ "include" ]

output_dir = root_out_dir
Expand Down
45 changes: 45 additions & 0 deletions examples/lighting-app/tizen/include/LedManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>

#include <peripheral_io.h>

namespace example {
class LedManager
{
public:
explicit LedManager(chip::EndpointId endpointId);
void SetOnOff(bool on);
CHIP_ERROR Init();

private:
void InitOnOff();

// Numbers of GPIO used to control LED in order: RED, GREEN, BLUE
static constexpr int number_of_pins = 3;
static constexpr int pins[number_of_pins] = { 20, 19, 18 };
peripheral_gpio_h gpio[number_of_pins] = {};

const chip::EndpointId mEndpointId;
};

} // namespace example
230 changes: 230 additions & 0 deletions examples/lighting-app/tizen/src/DBusInterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "DBusInterface.h"

#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-enums.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/ConcreteAttributePath.h>
#include <app/clusters/color-control-server/color-control-server.h>
#include <app/clusters/level-control/level-control.h>
#include <app/clusters/on-off-server/on-off-server.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/CHIPDeviceLayer.h>

#include "dbus/DBusLightApp.h"

using namespace chip;
using namespace chip::app;

namespace example {

// Dummy class to satisfy the CommandHandler::Callback interface.
class CommandHandlerCallback : public CommandHandler::Callback
{
public:
using Status = Protocols::InteractionModel::Status;
void OnDone(CommandHandler & apCommandObj) {}
void DispatchCommand(CommandHandler & apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & apPayload) {}
Status CommandExists(const ConcreteCommandPath & aCommandPath) { return Status::Success; }
};

DBusInterface::DBusInterface(chip::EndpointId endpointId) : mEndpointId(endpointId)
{
mManager = g_dbus_object_manager_server_new("/");
mIfaceIdentify = light_app_identify_skeleton_new();
mIfaceOnOff = light_app_on_off_skeleton_new();
mIfaceLevelControl = light_app_level_control_skeleton_new();
mIfaceColorControl = light_app_color_control_skeleton_new();
}

DBusInterface::~DBusInterface()
{
g_object_unref(mIfaceIdentify);
g_object_unref(mIfaceOnOff);
g_object_unref(mIfaceLevelControl);
g_object_unref(mIfaceColorControl);
g_object_unref(mManager);
}

CHIP_ERROR DBusInterface::Init()
{
// During the initialization we are going to connect glib signals, so we need to be
// on the GLib Matter context. Otherwise, signals will be emitted on the glib default
// main context.
return chip::DeviceLayer::PlatformMgrImpl().GLibMatterContextInvokeSync(InitOnGLibMatterContext, this);
}

void DBusInterface::Identify(uint16_t time)
{
light_app_identify_emit_identify(mIfaceIdentify, time);
}

void DBusInterface::SetOnOff(bool on)
{
InternalSetGuard guard(this);
if (light_app_on_off_get_on_off(mIfaceOnOff) != on)
light_app_on_off_set_on_off(mIfaceOnOff, on);
}

void DBusInterface::SetCurrentLevel(uint8_t value)
{
InternalSetGuard guard(this);
if (light_app_level_control_get_current_level(mIfaceLevelControl) != value)
light_app_level_control_set_current_level(mIfaceLevelControl, value);
}

void DBusInterface::SetColorMode(chip::app::Clusters::ColorControl::ColorMode colorMode)
{
InternalSetGuard guard(this);
if (light_app_color_control_get_color_mode(mIfaceColorControl) != colorMode)
light_app_color_control_set_color_mode(mIfaceColorControl, colorMode);
}

void DBusInterface::SetColorTemperature(uint16_t value)
{
InternalSetGuard guard(this);
if (light_app_color_control_get_color_temperature_mireds(mIfaceColorControl) != value)
light_app_color_control_set_color_temperature_mireds(mIfaceColorControl, value);
}

CHIP_ERROR DBusInterface::InitOnGLibMatterContext(DBusInterface * self)
{
g_autoptr(GDBusConnection) bus = nullptr;
g_autoptr(GError) error = nullptr;

if ((bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error)) == nullptr)
{
ChipLogError(NotSpecified, "Couldn't get D-Bus bus: %s", error->message);
return CHIP_ERROR_NOT_CONNECTED;
}

LightAppObjectSkeleton * object = light_app_object_skeleton_new("/app");
g_dbus_object_manager_server_export(self->mManager, G_DBUS_OBJECT_SKELETON(object));

light_app_object_skeleton_set_identify(object, self->mIfaceIdentify);
light_app_object_skeleton_set_on_off(object, self->mIfaceOnOff);
light_app_object_skeleton_set_level_control(object, self->mIfaceLevelControl);
light_app_object_skeleton_set_color_control(object, self->mIfaceColorControl);

self->InitOnOff();
self->InitColor();

g_dbus_object_manager_server_set_connection(self->mManager, bus);
g_object_unref(object);

g_signal_connect(self->mIfaceOnOff, "notify::on-off", G_CALLBACK(OnOnOffChanged), self);
g_signal_connect(self->mIfaceLevelControl, "notify::current-level", G_CALLBACK(OnCurrentLevelChanged), self);
g_signal_connect(self->mIfaceColorControl, "notify::color-temperature-mireds", G_CALLBACK(OnColorTemperatureChanged), self);

g_bus_own_name_on_connection(bus, "org.tizen.matter.example.lighting", G_BUS_NAME_OWNER_FLAGS_NONE,
reinterpret_cast<GBusAcquiredCallback>(OnBusAcquired),
reinterpret_cast<GBusNameLostCallback>(OnBusLost), self, nullptr);

return CHIP_NO_ERROR;
}

void DBusInterface::OnBusAcquired(GDBusConnection *, const char *, DBusInterface * self)
{
self->mNameAcquired = true;
}

void DBusInterface::OnBusLost(GDBusConnection *, const char * name, DBusInterface * self)
{
VerifyOrReturn(self->mNameAcquired, /* connection was lost after name was acquired, so it's not an error */);
ChipLogError(NotSpecified, "Couldn't acquire D-Bus name. Please check D-Bus configuration. Requested name: %s", name);
}

gboolean DBusInterface::OnOnOffChanged(LightAppOnOff * onOff, GDBusMethodInvocation * invocation, DBusInterface * self)
{
// Do not handle on-change event if it was triggered by internal set
VerifyOrReturnValue(!self->mInternalSet, G_DBUS_METHOD_INVOCATION_HANDLED);

chip::DeviceLayer::StackLock lock;
OnOffServer::Instance().setOnOffValue(self->mEndpointId,
light_app_on_off_get_on_off(onOff) ? Clusters::OnOff::Commands::On::Id
: Clusters::OnOff::Commands::Off::Id,
false /* initiatedByLevelChange */);
return G_DBUS_METHOD_INVOCATION_HANDLED;
}

gboolean DBusInterface::OnCurrentLevelChanged(LightAppLevelControl * levelControl, GDBusMethodInvocation * invocation,
DBusInterface * self)
{
// Do not handle on-change event if it was triggered by internal set
VerifyOrReturnValue(!self->mInternalSet, G_DBUS_METHOD_INVOCATION_HANDLED);

Clusters::LevelControl::Commands::MoveToLevel::DecodableType data;
data.level = light_app_level_control_get_current_level(levelControl);
data.optionsMask.Set(Clusters::LevelControl::LevelControlOptions::kExecuteIfOff);
data.optionsOverride.Set(Clusters::LevelControl::LevelControlOptions::kExecuteIfOff);

chip::DeviceLayer::StackLock lock;
LevelControlServer::MoveToLevel(self->mEndpointId, data);

return G_DBUS_METHOD_INVOCATION_HANDLED;
}

gboolean DBusInterface::OnColorTemperatureChanged(LightAppColorControl * colorControl, GDBusMethodInvocation * invocation,
DBusInterface * self)
{
// Do not handle on-change event if it was triggered by internal set
VerifyOrReturnValue(!self->mInternalSet, G_DBUS_METHOD_INVOCATION_HANDLED);

CommandHandlerCallback callback;
CommandHandler handler(&callback);

ConcreteCommandPath path{ self->mEndpointId, Clusters::ColorControl::Id, 0 };

Clusters::ColorControl::Commands::MoveToColorTemperature::DecodableType data;
data.colorTemperatureMireds = light_app_color_control_get_color_temperature_mireds(colorControl);

chip::DeviceLayer::StackLock lock;
ColorControlServer::Instance().moveToColorTempCommand(&handler, path, data);

return G_DBUS_METHOD_INVOCATION_HANDLED;
}

void DBusInterface::InitOnOff()
{
bool isOn = false;
auto status = Clusters::OnOff::Attributes::OnOff::Get(mEndpointId, &isOn);
VerifyOrReturn(status == EMBER_ZCL_STATUS_SUCCESS, ChipLogError(NotSpecified, "Error getting OnOff: 0x%x", status));
light_app_on_off_set_on_off(mIfaceOnOff, isOn);
}

void DBusInterface::InitColor()
{
{
uint8_t value = 0;
auto status = Clusters::ColorControl::Attributes::ColorMode::Get(mEndpointId, &value);
VerifyOrReturn(status == EMBER_ZCL_STATUS_SUCCESS, ChipLogError(NotSpecified, "Error getting ColorMode: 0x%x", status));
light_app_color_control_set_color_mode(mIfaceColorControl, value);
}
{
uint16_t value = 0;
auto status = Clusters::ColorControl::Attributes::ColorTemperatureMireds::Get(mEndpointId, &value);
VerifyOrReturn(status == EMBER_ZCL_STATUS_SUCCESS,
ChipLogError(NotSpecified, "Error getting ColorTemperatureMireds: 0x%x", status));
light_app_color_control_set_color_temperature_mireds(mIfaceColorControl, value);
}
}

}; // namespace example
Loading

0 comments on commit 2571257

Please sign in to comment.