Creating an SSN2 Session from Scratch#
This guide walks you through the process of creating a new session file (.ssn2) using the SQLRace API. You'll learn how to initialize the environment, create a session, add metadata, generate parameter data, and define laps.
Tip
Make sure you have:
- Installed .NET 6 and are targeting x64 architecture.
- Added the following NuGet packages:
MESL.SQLRace.API
- Configured your NuGet source to include the McLaren Applied GitHub packages: https://github.com/mat-docs/packages
Step 1: Initialize SQLRace#
This is a required step and scripts will work without an active SQLRace License. You can check that you have the correct license by opening License Manager from your start menu.
Core.LicenceProgramName = "SQLRace";
Core.Initialize();
Core.LicenceProgramName = "SQLRace"
Core.Initialize()
NET.setStaticProperty('MESL.SqlRace.Domain.Core.LicenceProgramName', 'SQLRace');
Core.Initialize();
Step 2: Create a New Session#
Creates a unique session at the specified location.
var sessionKey = SessionKey.NewKey();
var clientSession = SessionManager.CreateSessionManager()
.CreateSession(connectionString, sessionKey, sessionDescription, DateTime.Now, "TAG-310");
session_key = SessionKey.NewKey()
client_session = SessionManager.CreateSessionManager().CreateSession(connection_string, session_key, session_desc, DateTime.Now, "TAG-310")
sessionKey = SessionKey.NewKey();
clientSession = SessionManager.CreateSessionManager().CreateSession(connectionString, sessionKey, sessionDescription, DateTime.Now, "TAG-310");
SessionManager.CreateSession()
Info
Use the following connection strings to create your session, whether it's SSN2, SSNDB, or SQLRace:
connectionStringSSN2 = r"DbEngine=SQLite;Data Source=C:\Path\To\session.ssn2;"
connectionStringSSNDB = r"DbEngine=SQLite;Data Source=C:\Path\To\local_db.ssndb;PRAGMA journal_mode=WAL;"
connectionStringSQLRACE = r"Data Source=MCLA-42765X3\LOCAL;Initial Catalog=SQLRACE01;Integrated Security=True;"
Step 3: Create Session Configuration#
Create a configuration set for the session. Configuration will be saved when Commit() is called on this configuration set. If a configuration set is not created then the parameters will not be part of any structured groups.
Tip
Configuration can be created independently and shared across multiple sessions (non-session specific) using the ConfigurationSetManager. This improves session creation and load time.
Deprecated Method
Configuration can also be added directly to a session using CreateConfiguration(). This method is deprecated and should not be used.
Configuration Set Components
A Configuration Set is composed of the following entities:
- Parameters
- Channels
- Conversions
- Rational conversions
- Table conversions
- Text conversions
- Application Groups
- Parameter Groups
- Error Definitions
- Event Definitions
The following is an example of using the ConfigurationSetManager to add a shared configuration set:
// Define names and IDs
string parameterName = "myParam";
string applicationGroupName = "myApp";
string parameterIdentifier = $"{parameterName}:{applicationGroupName}";
string conversionFunctionName = $"CONV_{parameterName}:{applicationGroupName}";
string parameterGroupIdentifier = "myParamGroup";
string parameterSubGroupIdentifier = "myParamSubGroup";
uint parameterNameChannelId = 999998;
int applicationGroupId = 998;
// Create configuration set
ConfigurationSetManager configurationSetManager = ConfigurationSetManager.CreateConfigurationSetManager();
var configurationSet = configurationSetManager.Create(connectionString, "Configuration Set Name", "Configuration Set Description");
// Create parameter group and add sub group
var parameterGroup = new ParameterGroup(parameterGroupIdentifier, "Parameter group description");
parameterGroup.AddSubGroup(new ParameterGroup(parameterSubGroupIdentifier, "Sub group description"));
// Create application group
var applicationGroup = new ApplicationGroup(applicationGroupName, "Application group description", applicationGroupId, new List<string> { parameterGroup.Identifier });
// Add application group and parameter group to configuration set
configurationSet.AddGroup(applicationGroup);
configurationSet.AddParameterGroup(parameterGroup);
// Add a conversion function to the configuration set
configurationSet.AddConversion(RationalConversion.CreateSimple1To1Conversion(conversionFunctionName, "Units", "5.2f"));
// Create a frequency for the parameter's channel
var myParamFrequency = new Frequency(1000, FrequencyUnit.Hz);
// Create a channel for the parameter
var myParamChannel = new Channel(parameterNameChannelId, "Parameter channel description", myParamFrequency.ToInterval(), DataType.Double64Bit, ChannelDataSourceType.Periodic);
// Create the parameter
var myParam = new Parameter(parameterIdentifier, parameterName, $"{parameterName} Description", 1, -1, 0, 0, 0, 255, 0, conversionFunctionName, new List<string> { parameterSubGroupIdentifier }, myParamChannel.Id, applicationGroupName);
// Add the channel and parameter to the configuration set
configurationSet.AddChannel(myParamChannel);
configurationSet.AddParameter(myParam);
// Commit the configuration set to the database and handle exception
try
{
configurationSet.Commit();
Console.WriteLine($"Configuration Set '{configurationSet.Identifier}' committed to database.");
}
catch (ConfigurationSetAlreadyExistsException ex)
{
Console.WriteLine($"Commit of a Configuration Set '{configurationSet.Identifier}' failed. The config set already exists.");
}
# Define names and IDs
parameter_name = "myParam"
application_group_name = "myApp"
parameter_identifier = f"{parameter_name}:{application_group_name}"
conversion_function_name = f"CONV_{parameter_name}:{application_group_name}"
parameter_group_identifier = "myParamGroup"
parameter_sub_group_identifier = "myParamSubGroup"
parameter_name_channel_id = 999998 # Unique to each channel
application_group_id = 998 # Unique to each application group
# Define .NET Lists
parameter_group_identifier_list = List[str]()
parameter_sub_group_identifier_list = List[str]()
# Add variables to the .NET identifier lists
parameter_group_identifier_list.Add(parameter_group_identifier)
parameter_sub_group_identifier_list.Add(parameter_sub_group_identifier)
# Create configuration set
configuration_set = configuration_set_manager.Create(connection_string, "Configuration Set Name", "Configuration Set Description")
# Create parameter group and add sub-group
parameter_group = ParameterGroup(parameter_group_identifier, "Parameter group description")
parameter_group.AddSubGroup(ParameterGroup(parameter_sub_group_identifier, "Sub group description"))
# Create the application group
appGroup = ApplicationGroup(application_group_name, "Application group description", application_group_id, parameter_group_identifier_list)
# Add the application group and parameter group to the configuration set
configuration_set.AddGroup(appGroup)
configuration_set.AddParameterGroup(parameter_group)
# Add the conversion function to the configuration set
configuration_set.AddConversion(RationalConversion.CreateSimple1To1Conversion(conversion_function_name, "Unit", "5.2f"))
# Create a frequency for the parameter's channel
myParam_frequency = Frequency(1000, FrequencyUnit.Hz)
# Create a channel for the parameter
myParam_channel = Channel(parameter_name_channel_id, "Parameter channel description", FrequencyExtensions.ToInterval(myParam_frequency), DataType.Double64Bit, ChannelDataSourceType.Periodic)
# Create the parameter
myParam = Parameter(parameter_identifier, parameter_name, f"{parameter_name} Description", 1, -1, 0, 0, 0, 255, 0, conversion_function_name, parameter_sub_group_identifier_list, myParam_channel.Id, application_group_name)
# Add the channel and parameter to the configuration set
configuration_set.AddChannel(myParam_channel)
configuration_set.AddParameter(myParam)
# Commit the configuration set to the database and handle exception
try:
configuration_set.Commit()
print(f"Configuration Set '{configuration_set.Identifier}' committed to database.")
except ConfigurationSetAlreadyExistsException as ex:
print(f"Commit of a Configuration Set '{configuration_set.Identifier}' failed. The config set already exists.")
%% Create configuration set
% Define Names and IDs
parameterName = "myParam";
applicationGroupName = "myApp";
parameterIdentifier = sprintf("%s:%s", parameterName, applicationGroupName);
conversionFunctionName = sprintf("CONV_%s:%s", parameterName, applicationGroupName);
parameterGroupIdentifier = "myParamGroup";
parameterSubGroupIdentifier = "MyParamSubGroup";
parameterNameChannelId = 999998;
applicationGroupId = 998;
% Define .NET lists
parameterGroupIdentifierList = NET.createGeneric('System.Collections.Generic.List', {'System.String'});
parameterSubGroupIdentifierList = NET.createGeneric('System.Collections.Generic.List', {'System.String'});
% Add variable to the .NET identifier lists
parameterGroupIdentifierList.Add(parameterGroupIdentifier);
parameterSubGroupIdentifierList.Add(parameterSubGroupIdentifier);
% Create a configuration set
configurationSetManager = ConfigurationSetManager.CreateConfigurationSetManager();
configurationSet = configurationSetManager.Create(connectionString, "Configuration Set Name", "Configuration Set Description");
% Create a parameter group and sub group
parameterGroup = ParameterGroup(parameterGroupIdentifier, "Parameter group description");
parameterGroup.AddSubGroup(ParameterGroup(parameterSubGroupIdentifier, "Sub group description"));
% Create application group
applicationGroup = ApplicationGroup(applicationGroupName, "Application Group Name", applicationGroupId, parameterGroupIdentifierList);
% Add application group and parameter group to configuration set
configurationSet.AddGroup(applicationGroup);
configurationSet.AddParameterGroup(parameterGroup);
% Add a conversion function to the configuration set
configurationSet.AddConversion(RationalConversion.CreateSimple1To1Conversion(conversionFunctionName, "Units", "5.2f"));
% Create a frequency for the parameter's channel
myParamFrequency = Frequency(1000, FrequencyUnit.Hz);
% Create a channel for the parameter
myParamChannel = Channel(parameterNameChannelId, "Parameter channel description", FrequencyExtensions.ToInterval(myParamFrequency), DataType.Double64Bit, ChannelDataSourceType.Periodic);
% Create the parameter
myParam = Parameter(parameterIdentifier, parameterName, sprintf("%s Description", parameterName), 1, -1, 0, 0, 0, 255, 0, conversionFunctionName, parameterSubGroupIdentifierList, myParamChannel.Id, applicationGroupName);
% Add the channel and parameter to the configuration set
configurationSet.AddChannel(myParamChannel);
configurationSet.AddParameter(myParam);
% Commit the configuration set to the database and handle exception
try
configurationSet.Commit();
fprintf("Configuration Set '%s' committed to database.\n", configurationSet.Identifier);
catch errorMessage
fprintf("Encountered an error: %s\n", errorMessage.message);
end
ConfigurationSetManager.Create()
UseConfigurationSets Method#
var metadata = session.UseConfigurationSets(new List<KeyValuePair<string, uint>> { new("Configuration Set Name", configSetOffset) });
kvp = List[KeyValuePair[str, UInt32]]()
kvp.Add(KeyValuePair[str, UInt32]("Configuration Set Name", config_set_offset))
metadata = session.UseConfigurationSets(kvp)
kvpType = NET.GenericClass('System.Collections.Generic.KeyValuePair', 'System.String', 'System.UInt32');
kvpList = NET.createGeneric('System.Collections.Generic.List', {kvpType});
kvpList.Add(NET.createGeneric('System.Collections.Generic.KeyValuePair', {'System.String', 'System.UInt32'}, "Configuration Set Name", configSetOffset));
metadata = session.UseConfigurationSets(kvpList);
Session.UseConfigurationSets()
Step 4: Add Session Metadata#
Metadata allows tracking of essential session attributes (e.g., driver, event, date, etc.). Session metadata can be configured adding SessionDataItem objects into the session.Items.
Tip
The SessionDataItem supports the following data types for values:
- String – For textual data
- Double – For floating-point numbers
- Long – For large integer values
- Boolean – For true/false flags
- DateTime – For date and time values
- Byte[] – For binary data
session.Items.Add(new SessionDataItem("Driver Name", "Driver xxxxx"));
session.Items.Add(new SessionDataItem("Race", "Silverstone GP"));
session.Items.Add(new SessionDataItem("Date", DateTime.Now.AddDays(7)));
session.Items.Add(new SessionDataItem("Fuel level in gallons", 56.45));
session.Items.Add(SessionDataItem("Driver Name", "Driver xxxxx"))
session.Items.Add(SessionDataItem("Race", "Silverstone GP"))
session.Items.Add(SessionDataItem("Date", DateTime.Now.AddDays(7)))
session.Items.Add(SessionDataItem("Fuel level in gallons", 56.45))
session.Items.Add(SessionDataItem("Driver Name", "Driver xxxxx"));
session.Items.Add(SessionDataItem("Race", "Silverstone GP"));
session.Items.Add(SessionDataItem("Date", DateTime.Now.AddDays(7)));
session.Items.Add(SessionDataItem("Fuel level in gallons", 56.45));
Class SessionDataItemsCollection
Step 5: Configure Conversions#
Add conversion logic (e.g., rational and table conversions) for later use by parameters.
var conversions = new List<ConversionBase>
{
new RationalConversion("Rational_conv", "mph", "%5.2f", 0, 1, 0, 0, 0, 1),
new TableConversion("Table_conv", "mph", "%5.2f", rawValues, calibratedValues, false)
};
config.AddConversions(conversions);
numvalues = Array[Double]([0.0, 1.0])
stringvalues = Array[String](['Yes', 'No'])
textConvertion = TextConversion.Create(ConversionFunctionName, "kph", "%s", [0.0, 1.0], ['Yes', 'No'], "No")
config.AddConversion(RationalConversion.CreateSimple1To1Conversion(ConversionFunctionName, "kph", "%5.2f"))
formula = '(floor($fconv_dummy/60))+((($fconv_dummy/60)-(floor($fconv_dummy/60)))*0.6)'
expresion = IExpressionAdapter
config.AddConversion(FormulaConversion.Create('CONV_MYCONVERSION_NAME:TAG320BIOS', 'kph', "%s", '%2.2f', formula, IExpressionAdapter))
configurationSet.AddConversion(
RationalConversion.CreateSimple1To1Conversion(
conversionFunctionName,
"Units",
"5.2f"));
ConfigurationSet.AddConversion()
Step 6: Add Channels and Parameters#
Set up channels and map them to parameters that will receive time-series data. For more information on channels and parameters, see Understanding Channels and Parameters.
var channel = new Channel(1,
"lowFrequencyPeriodic1",
100_000_000,
DataType.FloatingPoint32Bit,
ChannelDataSourceType.Periodic);
var parameter = new Parameter("lowFrequency_10Hz",
"lowFrequency_10Hz",
"Low frequency parameter",
200,
0,
200,
0,
0,
0xffffffff,
0,
"Rational_conv",
new List<string> { "chassis" },
channel.Id);
config.AddChannels(new List<Channel> { channel });
config.AddParameters(new List<ParameterBase> { parameter });
# Create a channel for the parameter
myParam_channel = Channel(
parameter_name_channel_id,
"Parameter channel description",
FrequencyExtensions.ToInterval(myParam_frequency),
DataType.Double64Bit,
ChannelDataSourceType.Periodic)
# Create the parameter
myParam = Parameter(
parameter_identifier,
parameter_name,
f"{parameter_name} Description",
1, # Max value
-1, # Min value
0, # Max Warning value
0, # Min Warning value
0, # Offset value
255, # Data Bit Mask
0, # Error Bit Mask
conversion_function_name,
parameter_sub_group_identifier_list,
myParam_channel.Id,
application_group_name)
# Add the channel and parameter to the configuration set
configuration_set.AddChannel(myParam_channel)
configuration_set.AddParameter(myParam)
% Create a channel for the parameter
myParamChannel = Channel(
parameterNameChannelId,
"Parameter channel description",
FrequencyExtensions.ToInterval(myParamFrequency),
DataType.Double64Bit,
ChannelDataSourceType.Periodic);
% Create the parameter
myParam = Parameter(
parameterIdentifier,
parameterName,
sprintf("%s Description", parameterName),
1,
-1,
0,
0,
0,
255,
0,
conversionFunctionName,
parameterSubGroupIdentifierList,
myParamChannel.Id,
applicationGroupName);
% Add the channel and parameter to the configuration set
configurationSet.AddChannel(myParamChannel);
configurationSet.AddParameter(myParam);
ConfigurationSet.AddParameter()
Available Data Types
| Data Type | Description |
|---|---|
Double64Bit |
Double 64 bits of data. |
FloatingPoint32Bit |
Floating point 32 bits of data. |
Signed16Bit |
Signed 16 bits of data. |
Signed32Bit |
Signed 32 bits of data. |
Signed8Bit |
Signed 8 bits of data. |
TripleFloatingPoint32Bit |
Triple Floating point values. |
Unsigned16Bit |
Unsigned 16 bits of data. |
Unsigned32Bit |
Unsigned 32 bits of data. |
Unsigned8Bit |
Unsigned 8 bits of data. |
Step 7: Define Event Metadata#
Events let you log significant occurrences during a session (e.g., start, end, pit stops).
var eventDefinitions = new List<EventDefinition>
{
new EventDefinition(1, "FirstEvent", EventPriorityType.High, new List<string> { "Rational_conv" }, "Group1"),
new EventDefinition(2, "SecondEvent", EventPriorityType.Low, new List<string> { "Rational_conv" }, "Group1"),
new EventDefinition(3, "LastEvent", EventPriorityType.Medium, new List<string> { "Rational_conv" }, "Group2")
};
config.AddEventDefinitions(eventDefinitions);
event_definitions = List[EventDefinition]()
event_definitions.Add(EventDefinition(1, "FirstEvent", EventPriorityType.High, List[String]().Add("Rational_conv"), "Group1"))
event_definitions.Add(EventDefinition(2, "SecondEvent", EventPriorityType.Medium, List[String]().Add("Rational_conv"), "Group1"))
event_definitions.Add(EventDefinition(3, "ThirdEvent", EventPriorityType.Low, List[String]().Add("Rational_conv"), "Group2"))
configuration_set.AddEventDefinitions(event_definitions)
% Get EventDefinition type
eventDefinitionType = System.Type.GetType('MESL.SqlRace.Domain.EventDefinition, MESL.SqlRace.Domain');
% Add EventDefinition as argument for List<EventDefinition>
listOfEventDefinitionTypeArgs = NET.createArray('System.Type', 1);
listOfEventDefinitionTypeArgs.Set(0, eventDefinitionType);
listOfEventDefinitionType = listTypeDef.MakeGenericType(listOfEventDefinitionTypeArgs);
% Create List<EventDefinition> and List<String>
eventDefinitions = System.Activator.CreateInstance(listOfEventDefinitionType);
convFuncNames = System.Activator.CreateInstance(listOfStringType);
% Add conversion function name to List<String>
convFuncNames.Add("Rational_conv");
% Add event definitions to List<EventDefinition>
eventDefinitions.Add(EventDefinition(1, "FirstEvent", EventPriorityType.High, convFuncNames, "Group1"));
eventDefinitions.Add(EventDefinition(2, "SecondEvent", EventPriorityType.Medium, convFuncNames, "Group1"));
eventDefinitions.Add(EventDefinition(3, "ThirdEvent", EventPriorityType.Low, convFuncNames, "Group2"));
% Add event definitions to configuration set
configurationSet.AddEventDefinitions(eventDefinitions);
ConfigurationSet.AddEventDefinition()
Step 8: Write Parameter and Event Data#
Adds time-stamped numeric data to your session’s channels and logs events using IDs and timestamps.
session.AddChannelData(channel.Id, timestamp, sampleCount, doubleDataBytes);
session.Events.AddEventData(1, "Group1", timestamp, new List<double> { 300, 200, 100 }, true, "Status Text");
session.AddChannelData(
channel.Id,
timestamp,
sample_count,
struct.pack('<d', value) # convert 'value' to bytes <d == little endian double
)
event_data = List[System.Double]()
event_data.Add(300)
event_data.Add(200)
event_data.Add(100)
session.Events.AddEventData(1, "Group1", timestamp, event_data, True, "Status Text")
session.AddChannelData(channelId, timeStamp, sampleCount, BitConverter.GetBytes(value));
eventData = NET.createGeneric('System.Collections.Generic.List', {'System.Double'});
eventData.Add(300);
eventData.Add(200);
eventData.Add(100);
session.Events.AddEventData(1, "Group1", timestamp, eventData, true, "Status Text");
Step 9: Add Laps#
Lap data enrich your session context with performance and environmental data.
session.LapCollection.Add(new Lap(lapTimestamp, 1, 0, "Lap1", true));
session.LapCollection.Add(Lap(lap_timestamp, 1, 0, "Lap1", true))
session.LapCollection.Add(Lap(lapTimestamp, 1, 0, "Lap1", true));
Step 10: Add Constants#
Constants enrich your session context with performance and environmental data.
session.Constants.Add(new Constant("Race Start car weight", 653.92, "Car weight", "kg", "%5.2f"));
session.Constants.Add(Constant("Race Start car weight", 653.92, "Car weight", "kg", "5.2f"))
session.Constants.Add(Constant("Race Start car weight", 653.92, "Car weight", "kg", "5.2f"));
Session.Constants - SessionDataItemsCollection
Step 11: Add CAN Data#
CAN Data can be added thogh the CAN Collection object. CAN Collection only accepts RAW CAN messages.
long timeStamp = 1627845123456;
byte isReceived = 1;
ushort busId = 99;
uint canId = 123456;
byte[] message = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
session.CanData.AddCanData(timeStamp, isReceived, busId, canId, message);
timeStamp = Int64(1627845123456)
isReceived = Byte(1) # 1 for received, 0 for transmitted
busId = UInt16(99)
canId = UInt32(123456)
message = Array.CreateInstance(Byte, 8)
message[0] = Byte(0x01)
message[1] = Byte(0x02)
message[2] = Byte(0x03)
message[3] = Byte(0x04)
message[4] = Byte(0x05)
message[5] = Byte(0x06)
message[6] = Byte(0x07)
message[7] = Byte(0x08)
session.CanData.AddCanData(timeStamp, isReceived, busId, canId, message)
timeStamp = int64(1627845123456);
isReceived = uint8(1);
busId = uint16(99);
canId = uint32(123456);
message = NET.createArray('System.Byte', 8);
message(1) = uint8(1);
message(2) = uint8(2);
message(3) = uint8(3);
message(4) = uint8(4);
message(5) = uint8(5);
message(6) = uint8(6);
message(7) = uint8(7);
message(8) = uint8(8);
session.CanData.AddCanData(timeStamp, isReceived, busId, canId, message);
Warning
Only SSN2 and SQLRace Sessions support CAN data, SSN sessions do not contain any CAN data.
Tip
Sessions generated from a TAG-320 or TAG-700 will only contain CAN data from the PCU-8D or PCU-700.
Step 12: Finalize Session#
Close the session to ensure all data is written and saved to the .ssn2 file.
session.EndData();
clientSession.Close();
session.EndData()
client_session.Close()
session.EndData();
clientSession.Close();
Warning
EndData() is needed for the session's state to be properly updated to 'Historical', otherwise it would be stuck as 'LiveNotInServer' or 'Live'.
Close() or Dispose() is used to free system resources and reduce memory leaks.
Summary#
By following these steps, you can build a comprehensive .ssn2 session file with:
- Structured metadata
- Parameter/channel setup
- Event definitions and logging
- Sampled and synchronized data
- Lap and constant annotation
Explore further via SQLRace API documentation.
Additional examples in the GitHub repository HelloCreateSSN2FromZeroWithParameters & SessionCreationExample.