Skip to content

Commit

Permalink
Merge pull request #673 from sassy-asjp/feature/667-msg-array-types
Browse files Browse the repository at this point in the history
Feature/667 Message payload C array types
  • Loading branch information
schaubh authored May 14, 2024
2 parents 490e6b7 + 6344944 commit c19f00e
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 80 deletions.
2 changes: 2 additions & 0 deletions docs/source/Support/bskReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Version |release|
and :ref:`spinningBodyTwoDOFStateEffector` to any number of degrees of freedom.
- Update the Windows build to automatically include the Math library defines. This avoids having
to include them in BSK source code files individually.
- Added support for arrays and 2D arrays of 16 and 64 bit integers in message definitions
- Fixed bug where 2D arrays of 32 bit integers would have elements of type ``float`` in python.


Version 2.3.0 (April 5, 2024)
Expand Down
129 changes: 50 additions & 79 deletions src/architecture/_GeneralModuleFiles/swig_conly_data.i
Original file line number Diff line number Diff line change
Expand Up @@ -20,71 +20,8 @@
%module swig_conly_data

%include "stdint.i"
%define ARRAYASLIST(type)
%typemap(in) type [ANY] (type temp[$1_dim0]) {
int i;
void *blankPtr = 0 ;
int resOut = 0 ;
if (!PySequence_Check($input)) {
PyErr_SetString(PyExc_ValueError,"Expected a sequence");
return NULL;
}
if (PySequence_Length($input) > $1_dim0) {
printf("Value: %d\n", $1_dim0);
PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
return NULL;
}
memset(temp, 0x0, $1_dim0*sizeof(type));
for (i = 0; i < PySequence_Length($input); i++) {
PyObject *o = PySequence_GetItem($input,i);
if (PyNumber_Check(o)) {
temp[i] = (type)PyFloat_AsDouble(o);
} else {
resOut = SWIG_ConvertPtr(o, &blankPtr,$1_descriptor, 0 | 0 );
if (!SWIG_IsOK(resOut)) {
SWIG_exception_fail(SWIG_ArgError(resOut), "Could not convert that type into a pointer for some reason. This is an ugly SWIG failure. Good luck.\n");
return NULL;
}
memcpy(&(temp[i]), blankPtr, sizeof(type));
}
}
$1 = temp;
}

%typemap(memberin) type [ANY] {
int i;
for (i = 0; i < $1_dim0; i++) {
memcpy(&($1[i]), &($input[i]), sizeof(type));
}
}

%typemap(out) type [ANY] {
int i;
$result = PyList_New(0);
PyObject *locOutObj = 0;
for (i = 0; i < $1_dim0; i++) {
locOutObj = SWIG_NewPointerObj(SWIG_as_voidptr(&($1[i])), $1_descriptor, 0 | 0 );

if(PyNumber_Check(locOutObj)){
PyObject *outObject = PyFloat_FromDouble((double) $1[i]);
PyList_Append($result,outObject);
Py_DECREF(outObject);
Py_DECREF(locOutObj);
}
else
{
PyList_SetItem($result, i, locOutObj);
}
}
}

%enddef
ARRAYASLIST(double)
ARRAYASLIST(int)
ARRAYASLIST(float)
ARRAYASLIST(unsigned int)

%define ARRAYINTASLIST(type)
%define ARRAYASLIST(type, fromfunc, asfunc)
%typemap(in) type [ANY] (type temp[$1_dim0]) {
int i;
void *blankPtr = 0 ;
Expand All @@ -102,15 +39,17 @@ ARRAYASLIST(unsigned int)
for (i = 0; i < PySequence_Length($input); i++) {
PyObject *o = PySequence_GetItem($input,i);
if (PyNumber_Check(o)) {
temp[i] = (type)PyInt_AsLong(o);
temp[i] = (type)asfunc(o);
} else {
resOut = SWIG_ConvertPtr(o, &blankPtr,$1_descriptor, 0 | 0 );
if (!SWIG_IsOK(resOut)) {
SWIG_exception_fail(SWIG_ArgError(resOut), "Could not convert that type into a pointer for some reason. This is an ugly SWIG failure. Good luck.\n");
Py_DECREF(o);
return NULL;
}
memcpy(&(temp[i]), blankPtr, sizeof(type));
}
Py_DECREF(o);
}
$1 = temp;
}
Expand All @@ -128,25 +67,40 @@ ARRAYASLIST(unsigned int)
PyObject *locOutObj = 0;
for (i = 0; i < $1_dim0; i++) {
locOutObj = SWIG_NewPointerObj(SWIG_as_voidptr(&($1[i])), $1_descriptor, 0 | 0 );

if(PyNumber_Check(locOutObj)){
PyObject *outObject = PyInt_FromLong((long) $1[i]);
PyObject *outObject = fromfunc($1[i]);
PyList_Append($result,outObject);
Py_DECREF(outObject);
Py_DECREF(locOutObj);
}
else
{
PyList_SetItem($result, i, locOutObj);
// NOTE: SetItem steals the reference, so Py_DECREF is unnecessary
}
}
}

%enddef
ARRAYINTASLIST(int)
ARRAYINTASLIST(unsigned int)
ARRAYASLIST(int, PyLong_FromLong, PyLong_AsLong)
ARRAYASLIST(unsigned int, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAYASLIST(int32_t, PyLong_FromLong, PyLong_AsLong)
ARRAYASLIST(uint32_t, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAYASLIST(long long, PyLong_FromLongLong, PyLong_AsLongLong)
ARRAYASLIST(unsigned long long, PyLong_FromUnsignedLongLong, PyLong_AsUnsignedLongLong)
ARRAYASLIST(int64_t, PyLong_FromLongLong, PyLong_AsLongLong)
ARRAYASLIST(uint64_t, PyLong_FromUnsignedLongLong, PyLong_AsUnsignedLongLong)
ARRAYASLIST(short, PyLong_FromLong, PyLong_AsLong)
ARRAYASLIST(unsigned short, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAYASLIST(int16_t, PyLong_FromLong, PyLong_AsLong)
ARRAYASLIST(uint16_t, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAYASLIST(size_t, PyLong_FromSize_t, PyLong_AsSize_t)
ARRAYASLIST(ssize_t, PyLong_FromSsize_t, PyLong_AsSsize_t)
ARRAYASLIST(double, PyFloat_FromDouble, PyFloat_AsDouble)
ARRAYASLIST(float, PyFloat_FromDouble, PyFloat_AsDouble)

%define ARRAY2ASLIST(type)
%define ARRAY2ASLIST(type, fromfunc, asfunc)

%typemap(in) type [ANY][ANY] (type temp[$1_dim0][$1_dim1]) {
Py_ssize_t i;
Expand All @@ -157,7 +111,7 @@ ARRAYINTASLIST(unsigned int)
Py_ssize_t rowLength = 0;
for(i=0; i<PySequence_Length($input); i++){
PyObject *obj = PySequence_GetItem($input, i);
if(!PySequence_Check($input)) {
if(!PySequence_Check(obj)) {
printf("Row bad in matrix: %zd\n", i);
PyErr_SetString(PyExc_ValueError,"Need a list for each row");
}
Expand All @@ -173,8 +127,11 @@ ARRAYINTASLIST(unsigned int)
int j;
for(j=0; j<rowLength; j++)
{
temp[i][j] = PyFloat_AsDouble(PySequence_GetItem(obj, j));
PyObject *o = PySequence_GetItem(obj, j);
temp[i][j] = (type)asfunc(o);
Py_DECREF(o);
}
Py_DECREF(obj);
}
$1 = temp;
}
Expand All @@ -196,20 +153,32 @@ ARRAYINTASLIST(unsigned int)
PyObject *locRow = PyList_New(0);
for(j=0; j<$1_dim1; j++)
{
PyObject *outObject = PyFloat_FromDouble($1[i][j]);
PyObject *outObject = fromfunc($1[i][j]);
PyList_Append(locRow, outObject);
Py_DECREF(outObject);
}
PyList_Append($result, locRow);
Py_DECREF(locRow);
}
}

%enddef

ARRAY2ASLIST(double)
ARRAY2ASLIST(int)
ARRAY2ASLIST(float)
ARRAY2ASLIST(unsigned int)
ARRAY2ASLIST(int, PyLong_FromLong, PyLong_AsLong)
ARRAY2ASLIST(unsigned int, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAY2ASLIST(int32_t, PyLong_FromLong, PyLong_AsLong)
ARRAY2ASLIST(uint32_t, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAY2ASLIST(long long, PyLong_FromLongLong, PyLong_AsLongLong)
ARRAY2ASLIST(unsigned long long, PyLong_FromUnsignedLongLong, PyLong_AsUnsignedLongLong)
ARRAY2ASLIST(int64_t, PyLong_FromLongLong, PyLong_AsLongLong)
ARRAY2ASLIST(uint64_t, PyLong_FromUnsignedLongLong, PyLong_AsUnsignedLongLong)
ARRAY2ASLIST(short, PyLong_FromLong, PyLong_AsLong)
ARRAY2ASLIST(unsigned short, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAY2ASLIST(int16_t, PyLong_FromLong, PyLong_AsLong)
ARRAY2ASLIST(uint16_t, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong)
ARRAY2ASLIST(size_t, PyLong_FromSize_t, PyLong_AsSize_t)
ARRAY2ASLIST(ssize_t, PyLong_FromSsize_t, PyLong_AsSsize_t)
ARRAY2ASLIST(double, PyFloat_FromDouble, PyFloat_AsDouble)
ARRAY2ASLIST(float, PyFloat_FromDouble, PyFloat_AsDouble)

%define STRUCTASLIST(type)
%typemap(in) type [ANY] (type temp[$1_dim0]) {
Expand All @@ -231,10 +200,11 @@ ARRAY2ASLIST(unsigned int)
resOut = SWIG_ConvertPtr(o, &blankPtr,$1_descriptor, 0 | 0 );
if (!SWIG_IsOK(resOut)) {
SWIG_exception_fail(SWIG_ArgError(resOut), "Could not convert that type into a pointer for some reason. This is an ugly SWIG failur Good luck.\n");
Py_DECREF(o);
return NULL;
}
memcpy(&(temp[i]), blankPtr, sizeof(type));

Py_DECREF(o);
}
$1 = temp;
}
Expand All @@ -252,6 +222,7 @@ ARRAY2ASLIST(unsigned int)
for (i = 0; i < $1_dim0; i++) {
PyObject *locOutObj = SWIG_NewPointerObj(SWIG_as_voidptr(&($1[i])), $1_descriptor, 0 | 0 );
PyList_SetItem($result, i, locOutObj);
// NOTE: SetItem steals the reference, so Py_DECREF is unnecessary
}
}
%enddef
Expand Down
88 changes: 88 additions & 0 deletions src/architecture/messaging/_UnitTest/test_CMsgTypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#
# ISC License
#
# Copyright (c) 2024, Astroscale Japan
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

#
# Purpose: Test the handling of built in types for a C message payload
# Author: Sasawat Prankprakma (Astroscale Japan)
# Creation Date: 2024-04-17
#


from Basilisk.architecture import bskLogging
from Basilisk.architecture import messaging


def test_cMsgTypes():
"""
Test the Python-side types of various message payload C types
"""

bskLogging.setDefaultLogLevel(bskLogging.BSK_WARNING)

test = messaging.TypesTestMsgPayload()

assert type(test.i8Test) is int
assert type(test.ui8Test) is int
assert type(test.i16Test) is int
assert type(test.ui16Test) is int
assert type(test.i32Test) is int
assert type(test.ui32Test) is int
assert type(test.i64Test) is int
assert type(test.ui64Test) is int
assert type(test.f32Test) is float
assert type(test.f64Test) is float

assert type(test.i16TestArray[0]) is int
assert type(test.ui16TestArray[0]) is int
assert type(test.i32TestArray[0]) is int
assert type(test.ui32TestArray[0]) is int
assert type(test.i64TestArray[0]) is int
assert type(test.ui64TestArray[0]) is int
assert type(test.f32TestArray[0]) is float
assert type(test.f64TestArray[0]) is float

assert type(test.i16TestArray2[0][0]) is int
assert type(test.ui16TestArray2[0][0]) is int
assert type(test.i32TestArray2[0][0]) is int
assert type(test.ui32TestArray2[0][0]) is int
assert type(test.i64TestArray2[0][0]) is int
assert type(test.ui64TestArray2[0][0]) is int
assert type(test.f32TestArray2[0][0]) is float
assert type(test.f64TestArray2[0][0]) is float

assert len(test.i16TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.ui16TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.i32TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.ui32TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.i64TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.ui64TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.f32TestArray) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.f64TestArray) == messaging.TYPES_TEST_ARRAY_SIZE

assert len(test.i16TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.ui16TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.i32TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.ui32TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.i64TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.ui64TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.f32TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE
assert len(test.f64TestArray2[0]) == messaging.TYPES_TEST_ARRAY_SIZE


if __name__ == "__main__":
test_cMsgTypes()
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
%include "architecture/utilities/macroDefinitions.h"
%include "fswAlgorithms/fswUtilities/fswDefinitions.h"
%include "simulation/dynamics/reactionWheels/reactionWheelSupport.h"
ARRAYINTASLIST(FSWdeviceAvailability)
ARRAYASLIST(FSWdeviceAvailability, PyLong_FromLong, PyLong_AsLong)
STRUCTASLIST(CSSUnitConfigMsgPayload)
STRUCTASLIST(AccPktDataMsgPayload)
STRUCTASLIST(RWConfigElementMsgPayload)
Expand Down
66 changes: 66 additions & 0 deletions src/architecture/msgPayloadDefC/TypesTestMsgPayload.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
ISC License
Copyright (c) 2024, Astroscale Japan
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef TYPES_TEST_MESSAGE_H
#define TYPES_TEST_MESSAGE_H

#include <stdint.h>

#define TYPES_TEST_ARRAY_SIZE 3

/*! @brief Structure used to test the handling of various built-in types in message payloads across SWIG C/Python bridge */
typedef struct {
// Scalars
int8_t i8Test; //!< Test variable of int8_t
uint8_t ui8Test; //!< Test variable of uint8_t
int16_t i16Test; //!< Test variable of int16_t
uint16_t ui16Test; //!< Test variable of uint16_t
int32_t i32Test; //!< Test variable of int32_t
uint32_t ui32Test; //!< Test variable of uint32_t
int64_t i64Test; //!< Test variable of int64_t
uint64_t ui64Test; //!< Test variable of uint64_t
float f32Test; //!< Test variable of float
double f64Test; //!< Test variable of double

// 1D Arrays, integer
int16_t i16TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of int16_t
uint16_t ui16TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of uint16_t
int32_t i32TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of int32_t
uint32_t ui32TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of uint32_t
int64_t i64TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of int64_t
uint64_t ui64TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of uint64_t

// 2D Arrays, integer
int16_t i16TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of int16_t
uint16_t ui16TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of uint16_t
int32_t i32TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of int32_t
uint32_t ui32TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of uint32_t
int64_t i64TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of int64_t
uint64_t ui64TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of uint64_t

// 1D Arrays, floating point
float f32TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of float
double f64TestArray[TYPES_TEST_ARRAY_SIZE]; //!< Test variable of array of double

// 2D Arrays, floating point
float f32TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of float
double f64TestArray2[TYPES_TEST_ARRAY_SIZE][TYPES_TEST_ARRAY_SIZE]; //!< Test variable of 2D array of double
} TypesTestMsgPayload;

#endif

0 comments on commit c19f00e

Please sign in to comment.