• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RobotWebTools / rclnodejs / 22705446100

05 Mar 2026 06:29AM UTC coverage: 85.838% (+0.4%) from 85.481%
22705446100

Pull #1414

github

web-flow
Merge d9ce4ee00 into d709c3082
Pull Request #1414: Fix bugs in examples and electron demos

1387 of 1754 branches covered (79.08%)

Branch coverage included in aggregate %.

2868 of 3203 relevant lines covered (89.54%)

450.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/lib/time_source.js
1
// Copyright (c) 2018 Intel Corporation. All rights reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
'use strict';
16

17
const rclnodejs = require('./native_loader.js');
26✔
18
const { Clock, ROSClock } = require('./clock.js');
26✔
19
const { ClockType } = Clock;
26✔
20
const { Parameter, ParameterType } = require('./parameter.js');
26✔
21
const Time = require('./time.js');
26✔
22
const { TypeValidationError, OperationError } = require('./errors.js');
26✔
23

24
const USE_SIM_TIME_PARAM = 'use_sim_time';
26✔
25
const CLOCK_TOPIC = '/clock';
26✔
26

27
/**
28
 * @class - Class representing a TimeSource in ROS
29
 */
30

31
class TimeSource {
32
  /**
33
   * Create a TimeSource.
34
   * @param {Node} node - The node to be attached.
35
   */
36
  constructor(node) {
37
    this._node = node;
819✔
38
    this._associatedClocks = [];
819✔
39
    this._clockSubscription = undefined;
819✔
40
    this._lastTimeSet = new Time(0n, 0n, ClockType.ROS_TIME);
819✔
41
    this._isRosTimeActive = false;
819✔
42

43
    if (this._node) {
819✔
44
      this.attachNode(this._node);
817✔
45
    }
46
  }
47

48
  /**
49
   * Return status that whether the ROS time is active.
50
   * @name TimeSource#get:isRosTimeActive
51
   * @function
52
   * @return {boolean} Return true if the time is active, otherwise return false.
53
   */
54

55
  get isRosTimeActive() {
56
    return this._isRosTimeActive;
831✔
57
  }
58

59
  /**
60
   * Set the status of time.
61
   * @param {boolean} enabled - Set the ROS time to be active if enabled is true.
62
   * @name TimeSource#set:isRosTimeActive
63
   * @function
64
   * @return {undefined}
65
   */
66

67
  set isRosTimeActive(enabled) {
68
    if (this._isRosTimeActive === enabled) return;
6✔
69

70
    this._isRosTimeActive = enabled;
5✔
71
    this._associatedClocks.forEach((clock) => {
5✔
72
      clock.isRosTimeActive = enabled;
×
73
    });
74
    if (enabled) {
5✔
75
      this._subscribeToClockTopic();
4✔
76
    } else if (this._node && this._clockSubscription) {
1!
77
      this._node.destroySubscription(this._clockSubscription);
1✔
78
      this._clockSubscription = undefined;
1✔
79
    }
80
  }
81

82
  /**
83
   * Attach the clock to a Node object.
84
   * @param {Node} node - The node to be attached.
85
   * @return {undefined}
86
   */
87
  attachNode(node) {
88
    if (!(node instanceof rclnodejs.ShadowNode)) {
822✔
89
      throw new TypeValidationError('node', node, 'Node', {
1✔
90
        entityType: 'time source',
91
      });
92
    }
93

94
    if (this._node) {
821✔
95
      this.detachNode();
818✔
96
    }
97

98
    this._node = node;
821✔
99

100
    if (!node.hasParameter(USE_SIM_TIME_PARAM)) {
821✔
101
      node.declareParameter(
802✔
102
        new Parameter(USE_SIM_TIME_PARAM, ParameterType.PARAMETER_BOOL, false)
103
      );
104
    }
105

106
    const useSimTimeParam = node.getParameter(USE_SIM_TIME_PARAM);
821✔
107
    if (useSimTimeParam.type !== ParameterType.PARAMETER_NOT_SET) {
821!
108
      if (useSimTimeParam.type === ParameterType.PARAMETER_BOOL) {
821✔
109
        this._isRosTimeActive = useSimTimeParam.value;
819✔
110
      } else {
111
        node
2✔
112
          .getLogger()
113
          .error(
114
            `Invalid type for parameter ${USE_SIM_TIME_PARAM} ${useSimTimeParam.type} should be bool`
115
          );
116
      }
117
    } else {
118
      node
×
119
        .getLogger()
120
        .debug(
121
          `${USE_SIM_TIME_PARAM}' parameter not set, using wall time by default`
122
        );
123
    }
124

125
    if (this.isRosTimeActive) {
821✔
126
      this._subscribeToClockTopic();
6✔
127
    }
128

129
    node.addOnSetParametersCallback(this.onParameterEvent.bind(this));
821✔
130
  }
131

132
  /**
133
   * Detach the node which the clock have attached.
134
   * @return {undefined}
135
   */
136
  detachNode() {
137
    if (this._clockSubscription) {
821✔
138
      if (!this._node) {
3✔
139
        throw new OperationError(
1✔
140
          'Unable to destroy previously created clock subscription',
141
          {
142
            code: 'NO_NODE_ATTACHED',
143
            entityType: 'time source',
144
          }
145
        );
146
      }
147
      this._node.destroySubscription(this._clockSubscription);
2✔
148
    }
149
    this._clockSubscription = undefined;
820✔
150
    this._node = undefined;
820✔
151
  }
152

153
  /**
154
   * Attach the clock to a TimeSource object.
155
   * @param {Clock} clock - The node to be attached.
156
   * @return {undefined}
157
   */
158
  attachClock(clock) {
159
    if (!(clock instanceof ROSClock)) {
815✔
160
      throw new TypeValidationError('clock', clock, 'ROSClock', {
2✔
161
        entityType: 'time source',
162
      });
163
    }
164
    clock.rosTimeOverride = this._lastTimeSet;
813✔
165
    clock.isRosTimeActive = this._isRosTimeActive;
813✔
166
    this._associatedClocks.push(clock);
813✔
167
  }
168

169
  _clockCallback(msg) {
170
    this._lastTimeSet = Time.fromMsg(msg.clock);
10✔
171
    this._associatedClocks.forEach((clock) => {
10✔
172
      clock.rosTimeOverride = this._lastTimeSet;
10✔
173
    });
174
  }
175

176
  _subscribeToClockTopic() {
177
    if (!this._clockSubscription && this._node) {
10!
178
      this._clockSubscription = this._node.createSubscription(
10✔
179
        'rosgraph_msgs/msg/Clock',
180
        CLOCK_TOPIC,
181
        this._clockCallback.bind(this)
182
      );
183
    }
184
  }
185

186
  onParameterEvent(parameters = []) {
×
187
    for (const parameter of parameters) {
1,422✔
188
      if (parameter.name === USE_SIM_TIME_PARAM) {
1,422✔
189
        if (parameter.type === ParameterType.PARAMETER_BOOL) {
2✔
190
          this.isRosTimeActive = parameter.value;
1✔
191
        } else if (this._node) {
1!
192
          this._node
1✔
193
            .getLogger()
194
            .error(
195
              `${USE_SIM_TIME_PARAM} parameter set to something besides a bool`
196
            );
197
        }
198

199
        break;
2✔
200
      }
201
    }
202

203
    return {
1,422✔
204
      successful: true,
205
      reason: '',
206
    };
207
  }
208
}
209

210
module.exports = TimeSource;
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc