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

RobotWebTools / rclnodejs / 16044464595

03 Jul 2025 07:38AM UTC coverage: 84.526% (-0.1%) from 84.625%
16044464595

Pull #1158

github

web-flow
Merge 90720ad95 into 82bbc82ff
Pull Request #1158: Enable npm test on Windows workflow

775 of 1009 branches covered (76.81%)

Branch coverage included in aggregate %.

1907 of 2164 relevant lines covered (88.12%)

3222.81 hits per line

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

57.39
/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('bindings')('rclnodejs');
208✔
18
const { Clock, ROSClock } = require('./clock.js');
208✔
19
const { ClockType } = Clock;
208✔
20
const { Parameter, ParameterType } = require('./parameter.js');
208✔
21
const Time = require('./time.js');
208✔
22

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

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

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

42
    if (this._node) {
4,686!
43
      this.attachNode(this._node);
4,686✔
44
    }
45
  }
46

47
  get isRosTimeActive() {
48
    return this._isRosTimeActive;
×
49
  }
50

51
  set isRosTimeActive(enabled) {
52
    if (this.isRosTimeActive === enabled) return;
×
53

54
    this._isRosTimeActive = enabled;
×
55
    for (const clock in this._associatedClocks) {
×
56
      clock.isRosTimeActive = enabled;
×
57
    }
58

59
    if (enabled) {
×
60
      this._subscribeToClockTopic();
×
61
    } else if (this._node && this._clockSubscription) {
×
62
      this._node.destroySubscription(this._clockSubscription);
×
63
      this._node._clockSubscription = null;
×
64
    }
65
  }
66

67
  /**
68
   * Return status that whether the ROS time is active.
69
   * @name TimeSource#get:isRosTimeActive
70
   * @function
71
   * @return {boolean} Return true if the time is active, otherwise return false.
72
   */
73

74
  get isRosTimeActive() {
75
    return this._isRosTimeActive;
4,710✔
76
  }
77

78
  /**
79
   * Set the status of time.
80
   * @param {boolean} enabled - Set the ROS time to be active if enabled is true.
81
   * @name TimeSource#set:isRosTimeActive
82
   * @function
83
   * @return {undefined}
84
   */
85

86
  set isRosTimeActive(enabled) {
87
    if (this._isRosTimeActive === enabled) return;
×
88

89
    this._isRosTimeActive = enabled;
×
90
    this._associatedClocks.forEach((clock) => {
×
91
      clock.isRosTimeActive = enabled;
×
92
    });
93
    if (enabled) {
×
94
      this._subscribeToClockTopic();
×
95
    }
96
  }
97

98
  /**
99
   * Attach the clock to a Node object.
100
   * @param {Node} node - The node to be attached.
101
   * @return {undefined}
102
   */
103
  attachNode(node) {
104
    if ((!node) instanceof rclnodejs.ShadowNode) {
4,694!
105
      throw new TypeError('Invalid argument, must be type of Node');
×
106
    }
107

108
    if (this._node) {
4,694✔
109
      this.detachNode();
4,686✔
110
    }
111

112
    this._node = node;
4,694✔
113

114
    if (!node.hasParameter(USE_SIM_TIME_PARAM)) {
4,694✔
115
      node.declareParameter(
4,622✔
116
        new Parameter(USE_SIM_TIME_PARAM, ParameterType.PARAMETER_BOOL, false)
117
      );
118
    }
119

120
    const useSimTimeParam = node.getParameter(USE_SIM_TIME_PARAM);
4,694✔
121
    if (useSimTimeParam.type !== ParameterType.PARAMETER_NOT_SET) {
4,694!
122
      if (useSimTimeParam.type === ParameterType.PARAMETER_BOOL) {
4,694!
123
        this._isRosTimeActive = useSimTimeParam.value;
4,694✔
124
      } else {
125
        node
×
126
          .getLogger()
127
          .error(
128
            `Invalid type for parameter ${USE_SIM_TIME_PARAM} ${useSimTimeParam.type} should be bool`
129
          );
130
      }
131
    } else {
132
      node
×
133
        .getLogger()
134
        .debug(
135
          `${USE_SIM_TIME_PARAM}' parameter not set, using wall time by default`
136
        );
137
    }
138

139
    if (this.isRosTimeActive) {
4,694✔
140
      this._subscribeToClockTopic();
32✔
141
    }
142

143
    node.addOnSetParametersCallback(this.onParameterEvent.bind(this));
4,694✔
144
  }
145

146
  /**
147
   * Detach the node which the clock have attached.
148
   * @return {undefined}
149
   */
150
  detachNode() {
151
    if (this._clockSubscription) {
4,694✔
152
      if (!this._node) {
8!
153
        throw new Error(
×
154
          'Unable to destroy previously created clock subscription'
155
        );
156
      }
157
      this._node.destroySubscription(this._clockSubscription);
8✔
158
    }
159
    this._clockSubscription = undefined;
4,694✔
160
    this._node = undefined;
4,694✔
161
  }
162

163
  /**
164
   * Attach the clock to a TimeSource object.
165
   * @param {Clock} clock - The node to be attached.
166
   * @return {undefined}
167
   */
168
  attachClock(clock) {
169
    if (!(clock instanceof ROSClock)) {
4,718✔
170
      throw new TypeError('Only clocks with type ROS_TIME can be attached.');
16✔
171
    }
172
    clock.rosTimeOverride = this._lastTimeSet;
4,702✔
173
    clock.isRosTimeActive = this._isRosTimeActive;
4,702✔
174
    this._associatedClocks.push(clock);
4,702✔
175
  }
176

177
  _clockCallback(msg) {
178
    this._lastTimeSet = Time.fromMsg(msg.clock);
32✔
179
    this._associatedClocks.forEach((clock) => {
32✔
180
      clock.rosTimeOverride = this._lastTimeSet;
32✔
181
    });
182
  }
183

184
  _subscribeToClockTopic() {
185
    if (!this._clockSubscription && this._node) {
32!
186
      this._clockSubscription = this._node.createSubscription(
32✔
187
        'rosgraph_msgs/msg/Clock',
188
        CLOCK_TOPIC,
189
        this._clockCallback.bind(this)
190
      );
191
    }
192
  }
193

194
  onParameterEvent(parameters = []) {
×
195
    for (const parameter of parameters) {
3,852✔
196
      if (parameter.name === USE_SIM_TIME_PARAM) {
3,852!
197
        if (parameter.type === ParameterType.PARAMETER_BOOL) {
×
198
          this.isRosTimeActive = parameter.value;
×
199
        } else if (this._node) {
×
200
          this._node
×
201
            .getLogger()
202
            .error(
203
              `${USE_SIM_TIME_PARAM} parameter set to something besides a bool`
204
            );
205
        }
206

207
        break;
×
208
      }
209
    }
210

211
    return {
3,852✔
212
      successful: true,
213
      reason: '',
214
    };
215
  }
216
}
217

218
module.exports = TimeSource;
208✔
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

© 2025 Coveralls, Inc