Skip to content

Commit 5d69215

Browse files
authored
Merge pull request #652 from AVSLab/feature/466-running-non-swig-v2
Feature/466 running non swig v2
2 parents 23f542e + 02806a3 commit 5d69215

File tree

7 files changed

+227
-1
lines changed

7 files changed

+227
-1
lines changed

docs/source/Support/bskReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ Version 2.3.0 (April 5, 2024)
133133
``coastOptionBangDuration``. The setter and getter methods for this variable are renamed to reflect this change as
134134
``setCoastOptionBangDuration()`` and ``getCoastOptionBangDuration()``, respectively. See the module documentation
135135
for the current usage of this parameter and these associated methods.
136+
- Updated messaging files so that non-swig messages can be subscribed to, and data read out from. Supports pybind-based messages notably.
136137

137138

138139
Version 2.2.1 (Dec. 22, 2023)
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#
2+
# Copyright (c) 2023, Autonomous Vehicle Systems Lab, University of Colorado at Boulder
3+
#
4+
# Permission to use, copy, modify, and/or distribute this software for any
5+
# purpose with or without fee is hereby granted, provided that the above
6+
# copyright notice and this permission notice appear in all copies.
7+
#
8+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15+
#
16+
17+
#
18+
# Purpose: Test if a C-wrapped input message can be logged with a recorder module and that a C++ module can access its data using non-swig modules
19+
# Author: Scott Piggott
20+
# Creation Date: Aug. 17 2024
21+
#
22+
23+
24+
from Basilisk.architecture import bskLogging
25+
from Basilisk.architecture import messaging
26+
from Basilisk.architecture import sim_model
27+
from Basilisk.moduleTemplates import cModuleTemplate
28+
from Basilisk.moduleTemplates import cppModuleTemplate
29+
from Basilisk.utilities import SimulationBaseClass
30+
from Basilisk.utilities import macros
31+
from Basilisk.utilities import unitTestSupport as uts
32+
33+
34+
def test_RecordingInputMessages():
35+
"""
36+
testing recording a C-wrapped input message with the recorder module
37+
"""
38+
39+
bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING)
40+
testFailCount = 0 # zero unit test result counter
41+
testMessages = [] # create empty array to store test log messages
42+
43+
# Create a sim module as an empty container
44+
scSim = SimulationBaseClass.SimBaseClass()
45+
46+
# create the simulation process
47+
dynProcess = scSim.CreateNewProcess("dynamicsProcess")
48+
49+
# create the dynamics task and specify the integration update time
50+
dynProcess.addTask(scSim.CreateNewTask("dynamicsTask", macros.sec2nano(1.)))
51+
52+
# create modules
53+
mod1 = cModuleTemplate.cModuleTemplate()
54+
mod1.ModelTag = "cModule1"
55+
scSim.AddModelToTask("dynamicsTask", mod1)
56+
57+
# Write input data
58+
inputData = messaging.CModuleTemplateMsgPayload()
59+
inputData.dataVector = [1, 2, 3]
60+
inputDataMsg = messaging.CModuleTemplateMsg().write(inputData)
61+
62+
# Subscribe input message to stand alone message
63+
inputAddr = sim_model.getObjectAddress(inputDataMsg)
64+
mod1.dataInMsg.subscribeTo(inputAddr)
65+
66+
# Create recorders tied to IO messages
67+
dataInRec = mod1.dataInMsg.recorder()
68+
scSim.AddModelToTask("dynamicsTask", dataInRec)
69+
dataOutRec = mod1.dataOutMsg.recorder()
70+
scSim.AddModelToTask("dynamicsTask", dataOutRec)
71+
72+
attGuidMsg = messaging.CModuleTemplateMsg_C()
73+
attGuidMsgPayload = messaging.CModuleTemplateMsgPayload()
74+
attGuidMsg.write(attGuidMsgPayload)
75+
messaging.CModuleTemplateMsg_C_addAuthor(mod1.dataOutMsg, attGuidMsg)
76+
dataOut2Rec = attGuidMsg.recorder()
77+
scSim.AddModelToTask("dynamicsTask", dataOut2Rec)
78+
79+
# create modules
80+
mod1CPP = cppModuleTemplate.CppModuleTemplate()
81+
mod1CPP.ModelTag = "cppModule1"
82+
scSim.AddModelToTask("dynamicsTask", mod1CPP)
83+
84+
# Subscribe input message to C-module output message address
85+
cOutAddr = sim_model.getObjectAddress(mod1.dataOutMsg)
86+
mod1CPP.dataInMsg.subscribeToCAddr(cOutAddr)
87+
88+
# Create recorders tied to IO messages
89+
dataInRecCPP = mod1CPP.dataInMsg.recorder()
90+
scSim.AddModelToTask("dynamicsTask", dataInRecCPP)
91+
dataOutRecCPP = mod1CPP.dataOutMsg.recorder()
92+
scSim.AddModelToTask("dynamicsTask", dataOutRecCPP)
93+
94+
# initialize Simulation:
95+
scSim.InitializeSimulation()
96+
97+
# configure a simulation stop time and execute the simulation run
98+
scSim.ConfigureStopTime(macros.sec2nano(1.0))
99+
scSim.ExecuteSimulation()
100+
101+
# reading the module output message show not change the earlier redirection
102+
# further, we are testing that the read() command copies the payload from
103+
# the stand alone msg to the module output module
104+
tempSet = mod1.dataOutMsg.read().dataVector
105+
scSim.ConfigureStopTime(macros.sec2nano(2.0))
106+
scSim.ExecuteSimulation()
107+
108+
# print(dataInRec.dataVector)
109+
# print(dataOutRec.dataVector)
110+
# print(dataOut2Rec.dataVector)
111+
112+
testFailCount, testMessages = uts.compareArray([inputData.dataVector]*3
113+
, dataInRec.dataVector
114+
, 0.01
115+
, "recorded input message was not correct."
116+
, testFailCount
117+
, testMessages)
118+
119+
testFailCount, testMessages = uts.compareArray([[0, 0, 0], [0, 0, 0], [3, 2, 3]]
120+
, dataOutRec.dataVector
121+
, 0.01
122+
, "recorded module output message was not correct."
123+
, testFailCount
124+
, testMessages)
125+
126+
testFailCount, testMessages = uts.compareArray([[2, 2, 3], [3, 2, 3], [4, 2, 3]]
127+
, dataOut2Rec.dataVector
128+
, 0.01
129+
, "recorded redirected module output message was not correct."
130+
, testFailCount
131+
, testMessages)
132+
133+
testFailCount, testMessages = uts.compareArray([[4., 2., 3.]]
134+
, [mod1.dataOutMsg.read().dataVector]
135+
, 0.01
136+
, "read of module output message was not correct."
137+
, testFailCount
138+
, testMessages)
139+
140+
testFailCount, testMessages = uts.compareArray([[4, 2, 3]]
141+
, [attGuidMsg.read().dataVector]
142+
, 0.01
143+
, "read of module redirected output message was not correct."
144+
, testFailCount
145+
, testMessages)
146+
#Check that the input message subscribed with address reflects data right
147+
testFailCount, testMessages = uts.compareArray(dataOutRec.dataVector
148+
, dataInRecCPP.dataVector
149+
, 0.01
150+
, "recorded input message from addr was not correct."
151+
, testFailCount
152+
, testMessages)
153+
dataRecExpectation = dataInRecCPP.dataVector
154+
dummyVal = 1
155+
for i in range(dataRecExpectation.shape[0]):
156+
dataRecExpectation[i, 0] += dummyVal
157+
dummyVal += 1
158+
159+
#Check that the output message using input subscribed with address is right
160+
testFailCount, testMessages = uts.compareArray(dataRecExpectation
161+
, dataOutRecCPP.dataVector
162+
, 0.01
163+
, "recorded output message from addr was not correct."
164+
, testFailCount
165+
, testMessages)
166+
167+
if testFailCount:
168+
print(testMessages)
169+
170+
# each test method requires a single assert method to be called
171+
# this check below just makes sure no sub-test failures were found
172+
assert testFailCount < 1, testMessages
173+
174+
175+
if __name__ == "__main__":
176+
test_RecordingInputMessages()

src/architecture/messaging/cMsgCInterface/msg_C.cpp.in

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ void @MSG_AUTOSOURCE_TYPE@_cpp_subscribe(@MSG_AUTOSOURCE_TYPE@_C *subscriber, vo
114114
subscriber->headerPointer->isLinked = 1; // set output message as linked
115115
};
116116

117+
//! This method takes an address location as an integer, reinterprets it to be an object, and calls the CPP subscribe method from there
118+
void @MSG_AUTOSOURCE_TYPE@_addr_subscribe(@MSG_AUTOSOURCE_TYPE@_C *subscriber, uint64_t sourceAddr){
119+
void *source = reinterpret_cast<void *> (sourceAddr);
120+
@MSG_AUTOSOURCE_TYPE@_cpp_subscribe(subscriber, source);
121+
};
117122

118123
//! Cpp interface to check if subscriber is indeed subscribed to a message (1: subscribed, 0: not subscribed)
119124
int8_t @MSG_AUTOSOURCE_TYPE@_cpp_isSubscribedTo(@MSG_AUTOSOURCE_TYPE@_C *subscriber, void* source) {
@@ -126,3 +131,11 @@ int8_t @MSG_AUTOSOURCE_TYPE@_cpp_isSubscribedTo(@MSG_AUTOSOURCE_TYPE@_C *subscri
126131
return (firstCheck && secondCheck);
127132

128133
};
134+
135+
//! Cpp interface to check if subscriber is indeed subscribed to a message-address (1: subscribed, 0: not subscribed)
136+
int8_t @MSG_AUTOSOURCE_TYPE@_cpp_isSubscribedToAddr(@MSG_AUTOSOURCE_TYPE@_C *subscriber, uint64_t sourceAddr) {
137+
138+
void *source = reinterpret_cast<void*> (sourceAddr);
139+
return (@MSG_AUTOSOURCE_TYPE@_cpp_isSubscribedTo(subscriber, source));
140+
141+
};

src/architecture/messaging/cMsgCInterface/msg_C.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ void @MSG_AUTOSOURCE_TYPE@_cpp_subscribe(@MSG_AUTOSOURCE_TYPE@_C *subscriber, vo
2828

2929
void @MSG_AUTOSOURCE_TYPE@_C_subscribe(@MSG_AUTOSOURCE_TYPE@_C *subscriber, @MSG_AUTOSOURCE_TYPE@_C *source);
3030

31+
void @MSG_AUTOSOURCE_TYPE@_addr_subscribe(@MSG_AUTOSOURCE_TYPE@_C *subscriber, uint64_t sourceAddr);
32+
3133
int8_t @MSG_AUTOSOURCE_TYPE@_C_isSubscribedTo(@MSG_AUTOSOURCE_TYPE@_C *subscriber, @MSG_AUTOSOURCE_TYPE@_C *source);
3234
int8_t @MSG_AUTOSOURCE_TYPE@_cpp_isSubscribedTo(@MSG_AUTOSOURCE_TYPE@_C *subscriber, void* source);
35+
int8_t @MSG_AUTOSOURCE_TYPE@_cpp_isSubscribedToAddr(@MSG_AUTOSOURCE_TYPE@_C *subscriber, uint64_t sourceAddr);
3336

3437
void @MSG_AUTOSOURCE_TYPE@_C_addAuthor(@MSG_AUTOSOURCE_TYPE@_C *coowner, @MSG_AUTOSOURCE_TYPE@_C *data);
3538

src/architecture/messaging/messaging.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,21 @@ class ReadFunctor{
115115
this->initialized = true; // set input message as linked
116116
this->headerPointer->isLinked = 1; // set source output message as linked
117117
};
118-
118+
//! Subscribe to the message located at the sourceAddr in memory
119+
void subscribeToAddr(uint64_t sourceAddr)
120+
{
121+
//!Cast a pointer at the sourceAddr and call the regular subscribe
122+
Message<messageType> *source =
123+
reinterpret_cast<Message<messageType> *> (sourceAddr);
124+
subscribeTo(source);
125+
}
126+
//! Subscribe to the C message located at the sourceAddr in memory
127+
void subscribeToCAddr(uint64_t sourceAddr)
128+
{
129+
//! Cast a void* pointer and call the regular C-subscribe method
130+
void *source = reinterpret_cast<void *> (sourceAddr);
131+
subscribeToC(source);
132+
}
119133
//! Subscribe to a C++ message
120134
void subscribeTo(Message<messageType> *source){
121135
*this = source->addSubscriber();
@@ -143,6 +157,20 @@ class ReadFunctor{
143157
return (this->initialized && firstCheck && secondCheck );
144158

145159
};
160+
//! Check if self has been subscribed to the message at sourceAddr
161+
uint8_t isSubscribedToAddr(uint64_t sourceAddr)
162+
{
163+
//!Cast a pointer at the sourceAddr and call the regular is-subscribe
164+
Message<messageType> *source = reinterpret_cast<Message<messageType> *> (sourceAddr);
165+
return(isSubscribedTo(source));
166+
}
167+
//! Check if self has been subscribed to the message at sourceAddr
168+
uint8_t isSubscribedToCAddr(uint64_t sourceAddr)
169+
{
170+
//!Cast a void* pointer at the sourceAddr and call the regular is-subscribe
171+
void *source = reinterpret_cast<void *> (sourceAddr);
172+
return(isSubscribedToC(source));
173+
}
146174

147175
//! Recorder method description
148176
Recorder<messageType> recorder(uint64_t timeDiff = 0){return Recorder<messageType>(this, timeDiff);}

src/architecture/messaging/msgAutoSource/cMsgCInterfacePy.i.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ typedef struct {type};
1414
{type}_C_subscribe(self, source)
1515
elif type(source) == {type}:
1616
{type}_cpp_subscribe(self, source)
17+
elif type(source) == int: #Note that is assumes it is a uint64_t address in memory
18+
{type}_addr_subscribe(self, source)
1719
else:
1820
raise Exception('tried to subscribe {type} to another message type')
1921

@@ -26,6 +28,8 @@ typedef struct {type};
2628
return ({type}_C_isSubscribedTo(self, source))
2729
elif type(source) == {type}:
2830
return ({type}_cpp_isSubscribedTo(self, source))
31+
elif type(source) == int: #Note that this assumes it is a uint64_t address location in memory
32+
return ({type}_cpp_isSubscribedToAddr(self, source))
2933
else:
3034
return 0
3135

src/architecture/utilities/bskLogging.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ void BSKLogger::bskLog(logLevel_t targetLevel, const char* info, ...)
104104
va_start (args, info);
105105
vsnprintf(formatMessage, sizeof(formatMessage), info, args);
106106
printf("%s: %s\n", targetLevelStr, formatMessage);
107+
va_end(args);
107108
}
108109
}
109110

0 commit comments

Comments
 (0)