#include <assert.h>
#include <string.h>
+#include <pthread.h>
+
// SDK
#include "scssdk_telemetry.h"
#define UNUSED(x)
-/**
- * @brief Combined telemetry data and shared memory management.
- */
-
-#include "telemetry.h"
-#include "shmget.h"
-
-static struct telemetry_state_t *telemetry = NULL;
-
-static bool init_shm(void)
-{
- if ( NULL == telemetry ) {
- void *p;
- p = init_shmput( TELE_SHM_KEY, sizeof *telemetry );
- telemetry = static_cast<struct telemetry_state_t *>(p);
- }
- if ( NULL != telemetry ) {
- telemetry->version = TELE_VERSION;
- telemetry->flags |= TELE_FLAG_ALIVE;
- }
- return NULL != telemetry;
-}
-
-static void drop_shm(void)
-{
- if ( NULL != telemetry ) {
- telemetry->flags &= ~TELE_FLAG_ALIVE;
- release_shm( TELE_SHM_KEY, telemetry );
- telemetry = NULL;
- }
-}
-
-/**
- * @brief Last timestamp we received.
- */
-scs_timestamp_t last_timestamp = static_cast<scs_timestamp_t>(-1);
-
-
/**
* @brief Logging to external file.
*/
#endif // def LOGGING
+/**
+ * @brief Combined telemetry data and shared memory management.
+ */
+
+#include "telemetry.h"
+#include "shmget.h"
+
+static struct telemetry_state_t *telemetry = NULL;
+
+static inline int lock_shm(void)
+{
+ int e = pthread_rwlock_wrlock( &telemetry->rwlock );
+ if ( 0 != e )
+ log_print( "ERROR: Unable to acquire shared memory write lock\n" );
+ return e;
+}
+
+static inline int unlock_shm(void)
+{
+ int e = pthread_rwlock_unlock( &telemetry->rwlock );
+ if ( 0 != e )
+ log_print( "ERROR: Unable to release shared memory write lock\n" );
+ return e;
+}
+
+static bool init_shm(void)
+{
+ if ( NULL == telemetry ) {
+ void *p;
+ p = init_shmput( TELE_SHM_KEY, sizeof *telemetry );
+ telemetry = static_cast<struct telemetry_state_t *>(p);
+ if ( NULL != telemetry )
+ pthread_rwlock_init( &telemetry->rwlock, NULL );
+ }
+ if ( NULL != telemetry ) {
+ lock_shm();
+ telemetry->version = TELE_VERSION;
+ telemetry->flags |= TELE_FLAG_ALIVE;
+ unlock_shm();
+ }
+ return NULL != telemetry;
+}
+
+static void drop_shm(void)
+{
+ if ( NULL != telemetry ) {
+ lock_shm();
+ telemetry->flags &= ~TELE_FLAG_ALIVE;
+ unlock_shm();
+ release_shm( TELE_SHM_KEY, telemetry );
+ telemetry = NULL;
+ }
+}
+
+/**
+ * @brief Last timestamp we received.
+ */
+scs_timestamp_t last_timestamp = static_cast<scs_timestamp_t>(-1);
+
+
/**
* @brief Handling of individual events.
*/
last_timestamp = 0;
}
- // Advance the timestamp by delta since last frame.
+ lock_shm();
+ // Advance the timestamp by delta since last frame.
telemetry->timestamp += (info->paused_simulation_time - last_timestamp);
last_timestamp = info->paused_simulation_time;
// The raw values.
-
telemetry->raw_rendering_timestamp = info->render_time;
telemetry->raw_simulation_timestamp = info->simulation_time;
telemetry->raw_paused_simulation_timestamp = info->paused_simulation_time;
+
+ unlock_shm();
}
SCSAPI_VOID telemetry_frame_end(const scs_event_t UNUSED(event), const void *const UNUSED(event_info), const scs_context_t UNUSED(context))
SCSAPI_VOID telemetry_pause(const scs_event_t event, const void *const UNUSED(event_info), const scs_context_t UNUSED(context))
{
+ lock_shm();
telemetry->paused = (event == SCS_TELEMETRY_EVENT_paused);
+ unlock_shm();
}
SCSAPI_VOID telemetry_gameplay(const scs_event_t event, const void *const event_info, const scs_context_t UNUSED(context))
if ( 0 == strcmp( info->id, SCS_TELEMETRY_GAMEPLAY_EVENT_job_cancelled )
|| 0 == strcmp( info->id, SCS_TELEMETRY_GAMEPLAY_EVENT_job_delivered ) ) {
+ lock_shm();
telemetry->job_isvalid = false;
+ unlock_shm();
}
// Log the gameplay event.
{
const struct scs_telemetry_configuration_t *const info = static_cast<const scs_telemetry_configuration_t *>(event_info);
+ lock_shm();
if ( 0 == strcmp( info->id, SCS_TELEMETRY_CONFIG_truck ) ) {
/*
* @li brand_id
}
}
}
+ unlock_shm();
// Log the configuration info.
log_print("<%u> Configuration: %s\n", telemetry->game_time, info->id);
tele->placement_isvalid = false;
return;
}
+ lock_shm();
tele->placement_isvalid = true;
tele->x = value->value_dplacement.position.x;
tele->y = value->value_dplacement.position.y;
tele->heading = value->value_dplacement.orientation.heading;
tele->pitch = value->value_dplacement.orientation.pitch;
tele->roll = value->value_dplacement.orientation.roll;
+ unlock_shm();
}
SCSAPI_VOID telemetry_store_double(const scs_string_t name, const scs_u32_t index, const scs_value_t *const value, const scs_context_t context)
assert(value);
assert(value->type == SCS_VALUE_TYPE_double);
assert(context);
+ lock_shm();
*static_cast<double *>(context) = value->value_double.value;
+ unlock_shm();
}
SCSAPI_VOID telemetry_store_double_nz(const scs_string_t name, const scs_u32_t index, const scs_value_t *const value, const scs_context_t context)
assert(value);
assert(value->type == SCS_VALUE_TYPE_double);
assert(context);
- if (value->value_double.value)
+ if (value->value_double.value) {
+ lock_shm();
*static_cast<double *>(context) = value->value_double.value;
+ unlock_shm();
+ }
}
SCSAPI_VOID telemetry_store_s32(const scs_string_t name, const scs_u32_t index, const scs_value_t *const value, const scs_context_t context)
assert(value);
assert(value->type == SCS_VALUE_TYPE_s32);
assert(context);
+ lock_shm();
*static_cast<int32_t *>(context) = value->value_s32.value;
+ unlock_shm();
}
SCSAPI_VOID telemetry_store_u32(const scs_string_t name, const scs_u32_t index, const scs_value_t *const value, const scs_context_t context)
assert(value);
assert(value->type == SCS_VALUE_TYPE_u32);
assert(context);
+ lock_shm();
*static_cast<uint32_t *>(context) = value->value_u32.value;
+ unlock_shm();
}
SCSAPI_VOID telemetry_store_bool(const scs_string_t name, const scs_u32_t index, const scs_value_t *const value, const scs_context_t context)
assert(value);
assert(value->type == SCS_VALUE_TYPE_bool);
assert(context);
+ lock_shm();
*static_cast<bool *>(context) = value->value_bool.value;
+ unlock_shm();
}
/**
version_params->common.log(SCS_LOG_TYPE_error, "[teleshmem] Unable to initialize shared memory");
return SCS_RESULT_generic_error;
}
+ lock_shm();
// Check application version. Note that this example uses fairly basic channels which are likely to be supported
// by any future SCS trucking game however more advanced application might want to at least warn the user if there
last_timestamp = static_cast<scs_timestamp_t>(-1);
// Initially the game is paused.
telemetry->paused = true;
+ unlock_shm();
return SCS_RESULT_ok;
}