You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/05/08 12:43:08 UTC

[GitHub] michal-narajowski closed pull request #1063: apps/blemesh_light: Add demo app that uses Light Lightness model

michal-narajowski closed pull request #1063: apps/blemesh_light: Add demo app that uses Light Lightness model
URL: https://github.com/apache/mynewt-core/pull/1063
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/apps/blemesh_light/pkg.yml b/apps/blemesh_light/pkg.yml
new file mode 100644
index 000000000..642cbba9f
--- /dev/null
+++ b/apps/blemesh_light/pkg.yml
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+pkg.name: apps/blemesh_light
+pkg.type: app
+pkg.description: Sample application for BLE Mesh node with Light model
+pkg.author: "MichaƂ Narajowski <mi...@codecoup.pl>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - kernel/os
+    - net/nimble/controller
+    - net/nimble/host
+    - net/nimble/host/services/gap
+    - net/nimble/host/services/gatt
+    - net/nimble/host/store/ram
+    - net/nimble/transport/ram
+    - sys/console/full
+    - sys/log/full
+    - sys/stats/full
+    - sys/shell
diff --git a/apps/blemesh_light/src/light_model.c b/apps/blemesh_light/src/light_model.c
new file mode 100644
index 000000000..7f12fbf02
--- /dev/null
+++ b/apps/blemesh_light/src/light_model.c
@@ -0,0 +1,246 @@
+
+#include "syscfg/syscfg.h"
+
+#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
+
+#include "mesh/mesh.h"
+#include "bsp.h"
+#include "pwm/pwm.h"
+#include "light_model.h"
+#include "ws2812.h"
+
+#if (!MYNEWT_VAL(USE_NEOPIXEL))
+#if MYNEWT_VAL(PWM_0)
+struct pwm_dev *pwm0;
+#endif
+#if MYNEWT_VAL(PWM_1)
+struct pwm_dev *pwm1;
+#endif
+#if MYNEWT_VAL(PWM_2)
+struct pwm_dev *pwm2;
+#endif
+#if MYNEWT_VAL(PWM_3)
+struct pwm_dev *pwm3;
+#endif
+
+static uint16_t top_val;
+#endif
+
+#if (MYNEWT_VAL(USE_NEOPIXEL))
+static uint32_t neopixel[WS2812_NUM_LED];
+#endif
+
+static u8_t gen_onoff_state;
+static s16_t gen_level_state;
+
+static void light_set_lightness(u8_t percentage)
+{
+#if (!MYNEWT_VAL(USE_NEOPIXEL))
+	int rc;
+
+	uint16_t pwm_val = (uint16_t) (percentage * top_val / 100);
+
+#if MYNEWT_VAL(PWM_0)
+	rc = pwm_enable_duty_cycle(pwm0, 0, pwm_val);
+	assert(rc == 0);
+#endif
+#if MYNEWT_VAL(PWM_1)
+	rc = pwm_enable_duty_cycle(pwm1, 0, pwm_val);
+	assert(rc == 0);
+#endif
+#if MYNEWT_VAL(PWM_2)
+	rc = pwm_enable_duty_cycle(pwm2, 0, pwm_val);
+	assert(rc == 0);
+#endif
+#if MYNEWT_VAL(PWM_3)
+	rc = pwm_enable_duty_cycle(pwm3, 0, pwm_val);
+	assert(rc == 0);
+#endif
+#else
+	int i;
+	u32_t lightness;
+	u8_t max_lightness = 0x1f;
+
+	lightness = (u8_t) (percentage * max_lightness / 100);
+
+	for (i = 0; i < WS2812_NUM_LED; i++) {
+		neopixel[i] = (lightness | lightness << 8 | lightness << 16);
+	}
+	ws2812_write(neopixel);
+#endif
+}
+
+static void update_light_state(void)
+{
+	u16_t level = (u16_t)gen_level_state;
+	int percent = 100 * level / 0xffff;
+
+	if (gen_onoff_state == 0) {
+		percent = 0;
+	}
+	light_set_lightness((uint8_t) percent);
+}
+
+int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state)
+{
+	*state = gen_onoff_state;
+	return 0;
+}
+
+int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state)
+{
+	gen_onoff_state = state;
+	update_light_state();
+	return 0;
+}
+
+int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level)
+{
+	*level = gen_level_state;
+	return 0;
+}
+
+int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level)
+{
+	gen_level_state = level;
+	if ((u16_t)gen_level_state > 0x0000) {
+		gen_onoff_state = 1;
+	}
+	if ((u16_t)gen_level_state == 0x0000) {
+		gen_onoff_state = 0;
+	}
+	update_light_state();
+	return 0;
+}
+
+int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness)
+{
+	return light_model_gen_level_get(model, lightness);
+}
+
+int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness)
+{
+	return light_model_gen_level_set(model, lightness);
+}
+
+#if (!MYNEWT_VAL(USE_NEOPIXEL))
+#if MYNEWT_VAL(PWM_0)
+static struct pwm_dev_interrupt_cfg led1_conf = {
+	.cfg = {
+		.pin = LED_1,
+		.inverted = true,
+		.n_cycles = 0,
+		.interrupts_cfg = true,
+	},
+	.int_prio = 3,
+};
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+static struct pwm_dev_interrupt_cfg led2_conf = {
+	.cfg = {
+		.pin = LED_2,
+		.inverted = true,
+		.n_cycles = 0,
+		.interrupts_cfg = true,
+	},
+	.int_prio = 3,
+};
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+static struct pwm_dev_interrupt_cfg led3_conf = {
+	.cfg = {
+		.pin = LED_3,
+		.inverted = true,
+		.n_cycles = 0,
+		.interrupts_cfg = true,
+	},
+	.int_prio = 3,
+};
+#endif
+#endif
+
+#if MYNEWT_VAL(PWM_3)
+static struct pwm_dev_interrupt_cfg led4_conf = {
+	.cfg = {
+		.pin = LED_4,
+		.inverted = true,
+		.n_cycles = 0,
+		.interrupts_cfg = true,
+	},
+	.int_prio = 3,
+};
+#endif
+
+#if (!MYNEWT_VAL(USE_NEOPIXEL))
+int pwm_init(void)
+{
+	int rc = 0;
+
+#if MYNEWT_VAL(PWM_0)
+	led1_conf.seq_end_data = &led1_conf;
+	pwm0 = (struct pwm_dev *) os_dev_open("pwm0", 0, NULL);
+	assert(pwm0);
+	pwm_set_frequency(pwm0, 1000);
+	rc = pwm_chan_config(pwm0, 0, (struct pwm_chan_cfg*) &led1_conf);
+	assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+	led2_conf.seq_end_data = &led2_conf;
+	pwm1 = (struct pwm_dev *) os_dev_open("pwm1", 0, NULL);
+	assert(pwm1);
+	pwm_set_frequency(pwm1, 1000);
+	rc = pwm_chan_config(pwm1, 0, (struct pwm_chan_cfg*) &led2_conf);
+	assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+	led3_conf.seq_end_data = &led3_conf;
+	pwm2 = (struct pwm_dev *) os_dev_open("pwm2", 0, NULL);
+	assert(pwm2);
+	pwm_set_frequency(pwm2, 1000);
+	rc = pwm_chan_config(pwm2, 0, (struct pwm_chan_cfg*) &led3_conf);
+	assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_3)
+	led4_conf.seq_end_data = &led4_conf;
+	pwm3 = (struct pwm_dev *) os_dev_open("pwm3", 0, NULL);
+	assert(pwm3);
+	pwm_set_frequency(pwm3, 1000);
+	rc = pwm_chan_config(pwm3, 0, (struct pwm_chan_cfg*) &led4_conf);
+	assert(rc == 0);
+#endif
+
+	if (!pwm0) {
+		return 0;
+	}
+
+	top_val = (uint16_t) pwm_get_top_value(pwm0);
+	update_light_state();
+
+	return rc;
+}
+#endif
+#endif
+
+int light_model_init(void)
+{
+#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
+	int rc;
+#if (!MYNEWT_VAL(USE_NEOPIXEL))
+	rc = pwm_init();
+	assert(rc == 0);
+#else
+	rc = ws2812_init();
+	assert(rc == 0);
+	update_light_state();
+#endif
+	return rc;
+#else
+	return 0;
+#endif
+}
+
diff --git a/apps/blemesh_light/src/light_model.h b/apps/blemesh_light/src/light_model.h
new file mode 100644
index 000000000..2c5cd460f
--- /dev/null
+++ b/apps/blemesh_light/src/light_model.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef __BT_MESH_LIGHT_MODEL_H
+#define __BT_MESH_LIGHT_MODEL_H
+
+#include "syscfg/syscfg.h"
+#include "mesh/mesh.h"
+
+int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state);
+int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state);
+int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level);
+int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level);
+int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness);
+int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness);
+int light_model_init(void);
+
+#endif
diff --git a/apps/blemesh_light/src/main.c b/apps/blemesh_light/src/main.c
new file mode 100755
index 000000000..63be77b0d
--- /dev/null
+++ b/apps/blemesh_light/src/main.c
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+#include "sysinit/sysinit.h"
+#include "os/os.h"
+#include "mesh/mesh.h"
+#include "console/console.h"
+#include "hal/hal_system.h"
+#include "hal/hal_gpio.h"
+#include "bsp/bsp.h"
+#include "shell/shell.h"
+
+/* BLE */
+#include "nimble/ble.h"
+#include "host/ble_hs.h"
+#include "services/gap/ble_svc_gap.h"
+#include "mesh/glue.h"
+#include "mesh/testing.h"
+#include "mesh/model_srv.h"
+#include "light_model.h"
+
+
+static void model_bound_cb(u16_t addr, struct bt_mesh_model *model,
+                           u16_t key_idx)
+{
+    int rc;
+
+    console_printf("Model bound: remote addr 0x%04x key_idx 0x%04x model %p\n",
+                   addr, key_idx, model);
+
+    if (model->id != BT_MESH_MODEL_ID_GEN_LEVEL_SRV) {
+        return;
+    }
+
+    /* Hack for demo purposes */
+    rc = bt_test_bind_app_key_to_model(model, key_idx,
+                                       BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV);
+
+    if (rc) {
+        console_printf("Failed to bind light lightness srv model to app_key");
+    } else {
+        console_printf("Successfuly bound light lightness srv model to app_key");
+    }
+}
+
+static struct bt_test_cb bt_test_cb = {
+    .mesh_model_bound = model_bound_cb,
+};
+
+static void
+blemesh_on_reset(int reason)
+{
+    BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
+}
+
+static struct bt_mesh_gen_onoff_srv_cb gen_onoff_srv_cb = {
+        .get = light_model_gen_onoff_get,
+        .set = light_model_gen_onoff_set,
+};
+static struct bt_mesh_gen_level_srv_cb gen_level_srv_cb = {
+        .get = light_model_gen_level_get,
+        .set = light_model_gen_level_set,
+};
+static struct bt_mesh_light_lightness_srv_cb light_lightness_srv_cb = {
+        .get = light_model_light_lightness_get,
+        .set = light_model_light_lightness_set,
+};
+
+static void
+blemesh_on_sync(void)
+{
+    console_printf("Bluetooth initialized\n");
+
+    shell_register_default_module("mesh");
+
+    bt_test_cb_register(&bt_test_cb);
+
+    light_model_init();
+    bt_mesh_set_gen_onoff_srv_cb(&gen_onoff_srv_cb);
+    bt_mesh_set_gen_level_srv_cb(&gen_level_srv_cb);
+    bt_mesh_set_light_lightness_srv_cb(&light_lightness_srv_cb);
+
+    console_printf("Mesh initialized\n");
+
+    /* Hack for demo purposes */
+    bt_test_shell_init();
+}
+
+int
+main(void)
+{
+    /* Initialize OS */
+    sysinit();
+
+    /* Initialize the NimBLE host configuration. */
+    log_register("ble_hs", &ble_hs_log, &log_console_handler, NULL,
+                 LOG_SYSLEVEL);
+    ble_hs_cfg.reset_cb = blemesh_on_reset;
+    ble_hs_cfg.sync_cb = blemesh_on_sync;
+    ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
+
+    bt_mesh_register_gatt();
+
+    while (1) {
+        os_eventq_run(os_eventq_dflt_get());
+    }
+    return 0;
+}
diff --git a/apps/blemesh_light/src/ws2812.c b/apps/blemesh_light/src/ws2812.c
new file mode 100755
index 000000000..ddc6ed397
--- /dev/null
+++ b/apps/blemesh_light/src/ws2812.c
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include "sysinit/sysinit.h"
+#include "os/os.h"
+#include "bsp/bsp.h"
+#include "pwm/pwm.h"
+#include "nrfx.h"
+#include "nrfx_pwm.h"
+#include "ws2812.h"
+
+#define BITS_PER_SEQ    (24)
+#define BIT0            (0x8000 | 6)
+#define BIT1            (0x8000 | 11)
+
+static const nrfx_pwm_t pwm = NRFX_PWM_INSTANCE(WS2812_PWM);
+
+static const nrfx_pwm_config_t pwm_config = {
+    .output_pins = { WS2812_GPIO, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED },
+    .irq_priority = 3,
+    .base_clock = NRF_PWM_CLK_16MHz,
+    .count_mode = NRF_PWM_MODE_UP,
+    .top_value = 20,
+    .load_mode = NRF_PWM_LOAD_COMMON,
+    .step_mode = NRF_PWM_STEP_AUTO,
+};
+
+static uint16_t pwm_seq_values[2][BITS_PER_SEQ];
+
+static const nrf_pwm_sequence_t pwm_seq[2] = {
+        {
+            .values.p_raw = pwm_seq_values[0],
+            .length = BITS_PER_SEQ,
+            .repeats = 0,
+            .end_delay = 0,
+        }, {
+            .values.p_raw = pwm_seq_values[1],
+            .length = BITS_PER_SEQ,
+            .repeats = 0,
+            .end_delay = 0,
+        },
+};
+
+static uint32_t led_color[WS2812_NUM_LED];
+static int led_idx;
+
+static void
+load_pixel(void)
+{
+    uint16_t *seq_values;
+    uint32_t grb;
+    int i;
+
+    seq_values = pwm_seq_values[led_idx & 1];
+    grb = led_color[led_idx];
+
+    for (i = 0; i < BITS_PER_SEQ; i++) {
+        *seq_values = grb & 0x800000 ? BIT1 : BIT0;
+        grb <<= 1;
+        seq_values++;
+    }
+
+    led_idx++;
+}
+
+static void
+pwm_handler_func(nrfx_pwm_evt_type_t event_type)
+{
+    switch (event_type) {
+    case NRFX_PWM_EVT_END_SEQ0:
+    case NRFX_PWM_EVT_END_SEQ1:
+        load_pixel();
+        break;
+    default:
+        break;
+    }
+}
+
+int
+ws2812_init(void)
+{
+    nrfx_err_t err;
+
+    err = nrfx_pwm_init(&pwm, &pwm_config, pwm_handler_func);
+
+    return err != NRFX_SUCCESS;
+}
+
+int
+ws2812_write(const uint32_t *rgb)
+{
+    uint32_t grb;
+    int i;
+
+    for (i = 0; i < WS2812_NUM_LED; i++) {
+        grb = 0;
+        grb |= (rgb[i] & 0x00FF00) << 8;
+        grb |= (rgb[i] & 0xFF0000) >> 8;
+        grb |= (rgb[i] & 0x0000FF);
+
+        led_color[i] = grb;
+    }
+
+    led_idx = 0;
+
+    load_pixel();
+    load_pixel();
+    nrfx_pwm_complex_playback(&pwm, &pwm_seq[0], &pwm_seq[1], WS2812_NUM_LED,
+                              NRFX_PWM_FLAG_SIGNAL_END_SEQ0 |
+                              NRFX_PWM_FLAG_SIGNAL_END_SEQ1 |
+                              NRFX_PWM_FLAG_STOP);
+
+    return 0;
+}
diff --git a/apps/blemesh_light/src/ws2812.h b/apps/blemesh_light/src/ws2812.h
new file mode 100755
index 000000000..6f7f68e94
--- /dev/null
+++ b/apps/blemesh_light/src/ws2812.h
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+#ifndef __WS2812_H__
+#define __WS2812_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WS2812_PWM          0
+#define WS2812_GPIO         30
+#define WS2812_NUM_LED      32
+
+int ws2812_init(void);
+
+int ws2812_write(const uint32_t *rgb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WS2812_H__ */
diff --git a/apps/blemesh_light/syscfg.yml b/apps/blemesh_light/syscfg.yml
new file mode 100644
index 000000000..e40f09930
--- /dev/null
+++ b/apps/blemesh_light/syscfg.yml
@@ -0,0 +1,60 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+# Package: apps/blemesh_light
+
+syscfg.defs:
+    USE_NEOPIXEL:
+        value: 0
+
+syscfg.vals:
+    # Enable the shell task.
+    SHELL_TASK: 1
+
+    # Set log level to info (disable debug logging).
+    LOG_LEVEL: 1
+
+    # Default task settings
+    OS_MAIN_STACK_SIZE: 768
+
+    # Newtmgr is not supported in this app, so disable newtmgr-over-shell.
+    SHELL_NEWTMGR: 0
+
+    MSYS_1_BLOCK_COUNT: 80
+
+    BLE_MESH: 1
+    BLE_MESH_SHELL: 1
+    BLE_MESH_PROV: 1
+    BLE_MESH_PB_ADV: 1
+    BLE_MESH_PB_GATT: 1
+    BLE_MESH_GATT_PROXY: 1
+    BLE_MESH_TESTING: 1
+    BLE_MESH_FRIEND: 0
+    BLE_MESH_CFG_CLI: 1
+    BLE_MESH_HEALTH_CLI: 0
+    BLE_MESH_SHELL_MODELS: 1
+    BLE_MESH_TESTING: 1
+    BLE_MESH_OOB_OUTPUT_ACTIONS: 0
+    USE_NEOPIXEL: 0
+
+syscfg.vals.BLE_MESH_SHELL_MODELS:
+    PWM_0: 1
+    PWM_1: 1
+    PWM_2: 1
+    PWM_3: 1
+


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services