Skip to content

Commit d2ab696

Browse files
committed
Merge branch 'release/1.7.0'
2 parents f938e1e + dcce487 commit d2ab696

File tree

8 files changed

+818
-2
lines changed

8 files changed

+818
-2
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,23 @@ All notable changes to this project will be documented in this file. Dates are d
44

55
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
66

7+
#### [1.7.0](https://github.com/rdkcentral/python_raft/compare/1.6.0...1.7.0)
8+
9+
- Update #175: Create avSyncController [`#185`](https://github.com/rdkcentral/python_raft/pull/185)
10+
- Fix #175: Corrected typos found in review [`#175`](https://github.com/rdkcentral/python_raft/issues/175)
11+
- Merge tag '1.6.0' into develop [`f5a0113`](https://github.com/rdkcentral/python_raft/commit/f5a0113a8c3f296ac2627a776840386993dd5886)
12+
713
#### [1.6.0](https://github.com/rdkcentral/python_raft/compare/1.5.0...1.6.0)
814

15+
> 5 September 2025
16+
917
- Deploy cla action [`#171`](https://github.com/rdkcentral/python_raft/pull/171)
1018
- GH174 - Incorrect handling of elapsed time in pingTest when logPingTime is False [`#179`](https://github.com/rdkcentral/python_raft/pull/179)
1119
- GH173 - Missing result validation before JSON parsing in getPowerLevel [`#178`](https://github.com/rdkcentral/python_raft/pull/178)
1220
- Bugfix #169: Changed send_message method to capture full responses [`#169`](https://github.com/rdkcentral/python_raft/issues/169)
1321
- Update #169: Created RedRat remote type [`76d31fe`](https://github.com/rdkcentral/python_raft/commit/76d31fe8d86edf9e0a95ee2265dfbc0175dd8037)
1422
- Update #169: added keymaps to support known redrat platforms [`bbccbfb`](https://github.com/rdkcentral/python_raft/commit/bbccbfbdb32e90312906193cb5d6c4ae00196cca)
15-
- Update #169: Updated RedRat Hub class to add socketverification [`b2e8bf2`](https://github.com/rdkcentral/python_raft/commit/b2e8bf2d1e12498f7bc7b079be6a27d2cd4a8cca)
23+
- Bumped changelog [`5d61917`](https://github.com/rdkcentral/python_raft/commit/5d6191754bebc0b9615e399415f24e7b4ace8009)
1624

1725
#### [1.5.0](https://github.com/rdkcentral/python_raft/compare/1.4.2...1.5.0)
1826

examples/configs/example_rack_config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ rackConfig:
9999
# supported types:
100100
# [type: "cec-client", adaptor: "/dev/ttycec"]
101101
# [type: "remote-cec-client", adaptor: "/dev/ttycec", address: "192.168.99.1", username(optional): "testuser", password(optional): "testpswd", port(optional): "22"]
102+
103+
# [ avSyncController: optional] - Specifiec AVSyncController for the slot
104+
# supported types:
105+
# [type: "SyncOne2", port: "/dev/ttyACM0", extended_mode (optional): true|false, audio_input (optional): "AUTO|EXTERNAL|INTERNAL", speaker_distance (optional): "1.5"]
102106
- pi2:
103107
ip: "192.168.99.1"
104108
description: "local pi4"

framework/core/avSyncController.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
#!/usr/bin/env python3
2+
#** *****************************************************************************
3+
# *
4+
# * If not stated otherwise in this file or this component's LICENSE file the
5+
# * following copyright and licenses apply:
6+
# *
7+
# * Copyright 2023 RDK Management
8+
# *
9+
# * Licensed under the Apache License, Version 2.0 (the "License");
10+
# * you may not use this file except in compliance with the License.
11+
# * You may obtain a copy of the License at
12+
# *
13+
# *
14+
# http://www.apache.org/licenses/LICENSE-2.0
15+
# *
16+
# * Unless required by applicable law or agreed to in writing, software
17+
# * distributed under the License is distributed on an "AS IS" BASIS,
18+
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
# * See the License for the specific language governing permissions and
20+
# * limitations under the License.
21+
# *
22+
#* ******************************************************************************
23+
#*
24+
#* ** Project : RAFT
25+
#* ** @addtogroup : core
26+
#* ** @date : 28/08/2025
27+
#* **
28+
#* ** @brief : AV Sync controller
29+
#* **
30+
#* ******************************************************************************
31+
import json
32+
from os import path
33+
34+
import sys
35+
MY_PATH = path.realpath(__file__)
36+
MY_DIR = path.dirname(MY_PATH)
37+
sys.path.append(path.join(MY_DIR,'../../'))
38+
from framework.core.logModule import logModule
39+
from framework.core.avSyncModules import SyncOne2
40+
41+
class AVSyncController():
42+
43+
def __init__(self, log: logModule, config: dict):
44+
self._log = log
45+
self.controllerType = config.get('type')
46+
if self.controllerType.lower() == 'syncone2':
47+
port = config.get('port')
48+
input = config.get('audio_input','AUTO')
49+
extended_mode = config.get('extended_mode',False)
50+
speaker_distance = config.get('speaker_distance', None)
51+
if port is None:
52+
raise AttributeError('Cannot initialise SyncOne2 without port set in the rackConfig.')
53+
self.controller = SyncOne2(port,
54+
audio_input=input,
55+
extended_mode=extended_mode,
56+
speaker_dist=speaker_distance)
57+
@property
58+
def audio_trigger_level(self) -> int:
59+
"""Audio Sensor Sensitivity Level.
60+
61+
The higher the level the easier the sensor will trigger.
62+
"""
63+
return self.controller.get_audio_trigger_level()
64+
65+
@audio_trigger_level.setter
66+
def audio_trigger_level(self, audio_trigger_level: int):
67+
self.controller.set_audio_trigger_level(audio_trigger_level)
68+
69+
@property
70+
def frame_rate(self) -> int:
71+
"""Frame rate used in statistics calculations.
72+
"""
73+
return self.controller.get_frame_rate()
74+
75+
@frame_rate.setter
76+
def frame_rate(self, frame_rate: int):
77+
self.controller.set_frame_rate(frame_rate)
78+
79+
@property
80+
def mask_length(self) -> int:
81+
"""Mask time length in milliseconds.
82+
83+
The time AVSync controller will wait after taking a measurement
84+
before re-arming to take the next measurement.
85+
"""
86+
return self.controller.get_mask_len()
87+
88+
@mask_length.setter
89+
def mask_length(self, mask_length: int):
90+
self.controller.set_mask_len(mask_length)
91+
92+
@property
93+
def offset(self) -> int:
94+
"""Manual offset in milliseconds.
95+
96+
This manual offset can be used where equipment delays are known.
97+
"""
98+
return self.controller.get_offset()
99+
100+
@offset.setter
101+
def offset(self, offset: int):
102+
self.controller.set_offset(offset)
103+
104+
@property
105+
def video_trigger_level(self) -> int:
106+
"""Video Sensor Sensitivity Level.
107+
108+
The higher the level the easier the sensor will trigger.
109+
"""
110+
return self.controller.get_audio_trigger_level()
111+
112+
@video_trigger_level.setter
113+
def video_trigger_level(self, video_trigger_level: int):
114+
self.controller.set_audio_trigger_level(video_trigger_level)
115+
116+
def calibrate(self):
117+
"""Calibrate the AVSync controller.
118+
"""
119+
self._log.info('Calibrating AVSync controller.')
120+
self.controller.calibrate()
121+
122+
def start_measurements(self):
123+
"""Start recording measurements.
124+
125+
The current measurement held in the buffer of the AVSync controller will
126+
be cleared before more measurements start being captured.
127+
"""
128+
self._log.info('Starting measurement collection from AVSync controller.')
129+
# Clear the measurements before we start taking more measurements.
130+
self.controller.clear_results()
131+
self.controller.start_measuring()
132+
133+
def stop_measurements(self):
134+
"""Stop recording measurements
135+
"""
136+
self._log.info('Stopping measurement collection from AVSync controller.')
137+
self.controller.stop_measuring()
138+
139+
def clear_results(self):
140+
"""Clear store results.
141+
"""
142+
self._log.info('Clearing stored results from AVSync controller.')
143+
self.controller.clear_results()
144+
145+
def get_results(self) -> list[dict]:
146+
"""Return the results of the most recent measurements.
147+
148+
Returns:
149+
results (list[dict]): list containing dictionary of each measurement recorded,
150+
with the following keys:
151+
{'milliseconds',
152+
'frames',
153+
'avg_milliseconds',
154+
'avg_frames',
155+
'span_milliseconds',
156+
'span_frames'}
157+
"""
158+
self._log.debug('Retrieving results from AVSync controller.')
159+
results = self.controller.get_results()
160+
self._log.debug(json.dumps(results))
161+
return results
162+
163+
### MAIN ###
164+
if __name__ == '__main__':
165+
import time
166+
CONFIG = {
167+
'type': 'SyncONE2',
168+
'port': '/dev/ttyACM0',
169+
'extended_mode': False,
170+
'audio_input': 'EXTERNAL'
171+
}
172+
LOG = logModule('AVSync Logger')
173+
CONTROLLER = AVSyncController(LOG, CONFIG)
174+
175+
# Test Audio Trigger Level
176+
CONTROLLER.audio_trigger_level = 2
177+
res = CONTROLLER.audio_trigger_level
178+
print(res)
179+
180+
# Test Frame Rate
181+
CONTROLLER.frame_rate = 30
182+
print(CONTROLLER.frame_rate)
183+
184+
# Test Mask Length
185+
CONTROLLER.mask_length = 300
186+
print(CONTROLLER.mask_length)
187+
188+
# Test offset
189+
CONTROLLER.offset = -10
190+
print(CONTROLLER.offset)
191+
192+
# Test Video Trigger Level
193+
CONTROLLER.video_trigger_level = 3
194+
print(CONTROLLER.video_trigger_level)
195+
196+
# Test capturing measurements
197+
# CONTROLLER.start_measurements()
198+
# time.sleep(5)
199+
# CONTROLLER.stop_measurements()
200+
print(json.dumps(CONTROLLER.get_results()))
201+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python3
2+
#** *****************************************************************************
3+
# *
4+
# * If not stated otherwise in this file or this component's LICENSE file the
5+
# * following copyright and licenses apply:
6+
# *
7+
# * Copyright 2023 RDK Management
8+
# *
9+
# * Licensed under the Apache License, Version 2.0 (the "License");
10+
# * you may not use this file except in compliance with the License.
11+
# * You may obtain a copy of the License at
12+
# *
13+
# *
14+
# http://www.apache.org/licenses/LICENSE-2.0
15+
# *
16+
# * Unless required by applicable law or agreed to in writing, software
17+
# * distributed under the License is distributed on an "AS IS" BASIS,
18+
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
# * See the License for the specific language governing permissions and
20+
# * limitations under the License.
21+
# *
22+
#* ******************************************************************************
23+
#*
24+
#* ** Project : RAFT
25+
#* ** @addtogroup : core
26+
#* ** @date : 28/08/2025
27+
#* **
28+
#* ** @brief : AV Sync controller
29+
#* **
30+
#* ******************************************************************************
31+
32+
from .syncOne2 import SyncOne2

0 commit comments

Comments
 (0)