Forum
Notifications
Clear all
LUA Scripting
1
Posts
1
Users
0
Reactions
115
Views
Topic starter
16/07/2026 8:53 am
The following script gives you the ability to check which SAE PIDs are supported from your ECM.
You can find it inside the StartDiag's microSD card.
-- Script V1 : 26_03_30
-- Reference for PIDs: https://en.wikipedia.org/wiki/OBD-II_PIDs
-- table with description for possible PIDs (makes easier to understand what the codes mean)
idToDesc = {
[0x00] = 'PIDs supported 0x01-0x20',
[0x01] = 'Monitor status since DTCs clear',
[0x02] = 'DTC that caused Freeze Frame',
[0x03] = 'Fuel system status',
[0x04] = 'Calculated engine load / %',
[0x05] = 'Engine coolant Temperature (ECT) /°C',
[0x06] = 'Short term fuel trim Bank 1 / %',
[0x07] = 'Long term fuel trim Bank 1 / %',
[0x08] = 'Short term fuel trim Bank 2 / %',
[0x09] = 'Long term fuel trim Bank 2 / %',
[0x0A] = 'Fuel Pressure / kPa',
[0x0B] = 'Intake manifold absolute pressure / kPa',
[0x0C] = 'Engine speed / RPM',
[0x0D] = 'Vehicle speed / km/h',
[0x0E] = 'Timing advance / °',
[0x0F] = 'Intake air temperature (IAT) / °C',
[0x10] = 'Air flow rate (MAF) / g/s',
[0x11] = 'Throttle position / %',
[0x12] = 'Commanded secondary air status',
[0x13] = 'Oxygen sensor present (2 banks)',
[0x14] = 'Oxygen sensor 1',
[0x15] = 'Oxygen sensor 2',
[0x16] = 'Oxygen sensor 3',
[0x17] = 'Oxygen sensor 4',
[0x18] = 'Oxygen sensor 5',
[0x19] = 'Oxygen sensor 6',
[0x1A] = 'Oxygen sensor 7',
[0x1B] = 'Oxygen sensor 8',
[0x1C] = 'OBD standard supported',
[0x1D] = 'Oxygen sensor present (4 banks)',
[0x1E] = 'Aux input status',
[0x1F] = 'Runtime since engine start / s',
[0x20] = 'PIDs supported 0x21-0x40',
[0x21] = 'Distance traveled since MIL on / km',
[0x22] = 'Fuel rail pressure / kPa',
[0x23] = 'Fuel rail gauge pressure / kPa',
[0x24] = 'Oxygen sensor 1',
[0x25] = 'Oxygen sensor 2',
[0x26] = 'Oxygen sensor 3',
[0x27] = 'Oxygen sensor 4',
[0x28] = 'Oxygen sensor 5',
[0x29] = 'Oxygen sensor 6',
[0x2A] = 'Oxygen sensor 7',
[0x2B] = 'Oxygen sensor 8',
[0x2C] = 'Commanded EGR / %',
[0x2D] = 'EGR error / %',
[0x2E] = 'Commanded evaporative purge / %',
[0x2F] = 'Fuel tank level input / %',
[0x30] = 'Warmups since codes clear',
[0x31] = 'Distance traveled since codes clear / km',
[0x32] = 'Evaporative system pressure / Pa',
[0x33] = 'Absolute barometric pressure / kPa',
[0x34] = 'Oxygen sensor 1',
[0x35] = 'Oxygen sensor 2',
[0x36] = 'Oxygen sensor 3',
[0x37] = 'Oxygen sensor 4',
[0x38] = 'Oxygen sensor 5',
[0x39] = 'Oxygen sensor 6',
[0x3A] = 'Oxygen sensor 7',
[0x3B] = 'Oxygen sensor 8',
[0x3C] = 'Catalyst temperature: Bank 1, Sensor 1',
[0x3D] = 'Catalyst temperature: Bank 2, Sensor 1',
[0x3E] = 'Catalyst temperature: Bank 1, Sensor 2',
[0x3F] = 'Catalyst temperature: Bank 2, Sensor 2',
[0x40] = 'PID supported 0x41-0x60',
[0x41] = 'Monitor status (this drive cycle)',
[0x42] = 'Control module voltage / V',
[0x43] = 'Absolute load value / %',
[0x44] = 'Commanded air fuel eq. ratio / %',
[0x45] = 'Relative throttle position / %',
[0x46] = 'Ambient air temperature (AAT) / °C',
[0x47] = 'Absolute throttle position B / %',
[0x48] = 'Absolute throttle position C / %',
[0x49] = 'Absolute throttle position D / %',
[0x4A] = 'Absolute throttle position E / %',
[0x4B] = 'Absolute throttle position F / %',
[0x4C] = 'Commanded throttle actuator / %',
[0x4D] = 'Time run with MIL on / min',
[0x4E] = 'Time since DTC clear / min',
[0x4F] = 'Max value for Air-fuel ration',
[0x50] = 'Maximum value fro air flo from MAF / g/s',
[0x51] = 'Fuel type',
[0x52] = 'Ethanol fuel %',
[0x53] = 'Absolute evap. system pressure / kPa',
[0x54] = 'Evap. system pressure / Pa',
[0x55] = 'Short term secondary trim',
[0x56] = 'Short term secondary trim',
[0x57] = 'Short term secondary trim',
[0x58] = 'Short term secondary trim',
[0x59] = 'Fuel rail abs. pressure / kPa',
[0x5A] = 'Relative accelerator pedal position / %',
[0x5B] = 'Hybrid battery pack remaining life / %',
[0x5C] = 'Engine oil temperature / °C',
[0x5D] = 'Fuel injection timing / °',
[0x5E] = 'Engine fuel rate / L/h',
[0x5F] = 'Emission requirement to which vehicle is designed',
[0x60] = 'PIDs supported 0x61-0x80',
[0x61] = 'Drivers demanded engine percentage torque / %',
[0x62] = 'Actual engine percentage torque / %',
[0x63] = 'Engine reference torque / Nm',
[0x64] = 'Engine percent torque data / %',
[0x65] = 'Aux input/output supported',
[0x66] = 'Mass air flow sensor / g/s',
[0x67] = 'Engine coolant temperature (ECT) / °C',
[0x68] = 'Intake air temperature sensor / °C',
[0x69] = 'Actual / Commanded / Error EGR',
[0x6A] = 'Commanded diesel intake air flow control and relative intake air flow position',
[0x6B] = 'Exhaust gas recirculation temperature',
[0x6C] = 'Commanded throttle actuator control and relative throttle position',
[0x6D] = 'Fuel pressure control system',
[0x6E] = 'Injection pressure control system',
[0x6F] = 'Turbocharger compressor inlet pressure',
[0x70] = 'Boost pressure control',
[0x71] = 'VGT control',
[0x72] = 'Wastegate control',
[0x73] = 'Exhaust pressure',
[0x74] = 'Turbocharger RPM / RPM',
[0x75] = 'Turbocharger temperature',
[0x76] = 'Turbocharger temperature',
[0x77] = 'Charge air cooler temperature',
[0x78] = 'EGT bank 1',
[0x79] = 'EGT bank 2',
[0x7A] = 'DPF differential pressure',
[0x7B] = 'Diesel particulate filter (DPF)',
[0x7C] = 'DPF temperature',
[0x7D] = 'NOx NTE control status area',
[0x7E] = 'PM NTE control status area',
[0x7F] = 'Engine run time',
[0x80] = 'PID supported 0x81-0xA0',
[0x81] = 'Engine run time for auxiliary emission control device (AECD)',
[0x82] = 'Engine run time for auxiliary emission control device (AECD)',
[0x83] = 'NOx sensor',
[0x84] = 'Manifold surface temperature',
[0x85] = 'NOx reagent system',
[0x86] = 'PM sensor',
[0x87] = 'Intake manifold absolute pressure',
[0x88] = 'SCR induce system',
[0x89] = 'Runtime for AECD #11-#15',
[0x8A] = 'Runtime for AECD #16-#20',
[0x8B] = 'Diesel aftertreatment',
[0x8C] = 'O2 sensor',
[0x8D] = 'Throttle position G / %',
[0x8E] = 'Engine Friction - Percent torque / %',
[0x8F] = 'PM sensor bank 1&2',
[0x90] = 'WWH-OBD Vehicle OBD System info',
[0x91] = 'WWH-OBD Vehicle OBD System info',
[0x92] = 'Fuel control system',
[0x93] = 'WWH-OBD Vehicle OBD counters support',
[0x94] = 'NOx warning and inducement system',
[0x95] = '',
[0x96] = '',
[0x97] = '',
[0x98] = 'EGT sensor',
[0x99] = 'EGT sensor',
[0x9A] = 'Hybrid/EV vehicle system data/battery/voltage',
[0x9B] = 'Diesel exhaust fluid sensor data',
[0x9C] = 'O2 sensor data',
[0x9D] = 'Engine fuel rate / g/s',
[0x9E] = 'Exhaust engine fuel rate / kg/h',
[0x9F] = 'Fuel system percentage use',
[0xA0] = 'PID supported 0xA1-0xC0',
[0xA1] = 'NOx sensor corrected data',
[0xA2] = 'Cylinder fuel rate',
[0xA3] = 'Evap system vapor pressure',
[0xA4] = 'Transmission actual gear',
[0xA5] = 'Commanded diesel exhaust fluid dosing',
[0xA6] = 'Odometer',
[0xA7] = 'NOx sensor concentration sensor 3 and 4',
[0xA8] = 'NOx sensor corrected concentration sensor 3 and 4',
[0xA9] = 'ABS disable switch state',
[0xAA] = '',
[0xAB] = '',
[0xAC] = '',
[0xAD] = '',
[0xAE] = '',
[0xAF] = '',
[0xB0] = '',
[0xB1] = '',
[0xB2] = '',
[0xB3] = '',
[0xB4] = '',
[0xB5] = '',
[0xB6] = '',
[0xB7] = '',
[0xB8] = '',
[0xB9] = '',
[0xBA] = '',
[0xBB] = '',
[0xBC] = '',
[0xBD] = '',
[0xBE] = '',
[0xBF] = '',
[0xC0] = 'PID supported 0xC1-0xE0',
[0xC1] = '',
[0xC2] = '',
[0xC3] = '',
[0xC4] = '',
[0xC5] = '',
[0xC6] = '',
[0xC7] = '',
[0xC8] = '',
[0xC9] = '',
[0xCA] = '',
[0xCB] = '',
[0xCC] = '',
[0xCD] = '',
[0xCE] = '',
[0xCF] = ''
}
-- parameters: buffer to convert
-- return: string representing the given buffer
function hex_dump(buf)
if buf == nil then return '' end
local txt = ''
for byte=1, #buf, 16 do
local chunk = buf:sub(byte, byte+15)
chunk:gsub('.', function (c) txt = txt .. string.format('%02X ',string.byte(c)) end)
end
return txt
end
-- parameters: input buffer (string of byte), position to start from, length of byte to get the number from
-- returns: number extracted / nil on errors
function readNumber(buf, pos, len)
local val = nil
if ((len > 0) and (len <= 4)) then
val = 0
endpos = pos+len-1
-- Validation of the available data respect to the passed requested length
if (endpos > #buf) then return nil end
for idx = pos, endpos do
val = (val * 256) + string.byte( string.sub(buf, idx) )
end
end
return val
end
-- parameters: U32 value to convert
-- returns: string with the bits representation
function getU32AsBinaryString(val)
local bits = {}
for i = 31, 0, -1 do
local b = (val & (1 << i)) >> i
table.insert(bits, b)
end
return table.concat(bits)
end
-- parameters: remoteID so send request to, lcoalID to receive the message on, filename to log data into
-- returns: nil (all the relevant work is done inside the function)
function handleSAESupportMap(rid, lid, filename)
local rc
local resp
local done = false
local DID = 0x0000
local supCnt = 0
-- open the log file to write to
local fw = io.open(filename, "w")
if (fw == nil) then
print('We have not been able to open the log file.')
return
end
-- it is useful to add the useful information to read the log file later
fw:write('RemoteID = ' .. string.format('%08X', rid) .. '\n')
fw:write('LocalID = ' .. string.format('%08X', lid) .. '\n')
fw:write('\n')
-- SAE 0x01 can be parsed in a loop fashion
repeat
fw:write('\nDID: ' .. string.format('%04X', DID) ..'\n')
rc, resp = uds.xmit(rid, 0x01, DID, "", lid, 100)
if (rc ~= 0) then
print('Error in ECM communication: ' .. string.format('%08X', rc))
fw:write('Error in ECM communication: ' .. string.format('%08X', rc) .. '\n')
-- in case of communication error we stop the script altogether
return
end
local map = readNumber(resp, 1, 4);
fw:write( string.format('(Data:%s) [Value:%X] - %s\n', hex_dump(resp), map, getU32AsBinaryString(map)) )
-- Bit position: 31, 30, ....... , 1, 0
-- SAE map positions: 1, 2, ....... , 31, 32
for idx = 1, 32 do
local bm = (1 << (32 - idx))
--fw:write( string.format('map[%02d] = %08X\n', idx, (map & bm)) )
if (map & bm) ~= 0 then
-- bit is 1 / True
-- NOTE: the bitmap starts with values from 1 , not 0, so the last (bit 31 == 0x20(32d))
fw:write(string.format('%04X', (DID + idx)) .. ' is supported. ('.. idToDesc[(DID + idx)] ..') \n' )
supCnt = supCnt + 1
else
-- last bit is 0 / False -> no more component of the SAE bitmap
if idx == 32 then done = true end
end
end
-- prepare the DID to get the next SAE supported map part
DID = DID + 0x20
-- safe clean condition: single byte request DID is used by SID 0x01
if DID > 0xFF then done = true end
until done == true
print('Found ' .. supCnt .. ' SAE PID supported by request at 0x01')
fw:write('\n\nFound ' .. supCnt .. ' SAE PID supported by request at 0x01\n')
fw:close()
end
print('START...')
print('Turn Key ON for testing..')
ui.sleep(100*5) --sleep 5 secs
local rc, currentBR = can.getCurrentBaudrate()
if (currentBR == 0) then
--Ask the user here, since there is no current CAN baudrate set and validated
currentBR = ui.inputValue('Set CAN Baudrate', 'u', 1, 500000, 500000)
end
if (currentBR == nil) then
error('No CAN Baudrate provided.')
end
rc = can.init(currentBR)
if (rc ~= 0) then
error("CAN Init failed! Error: " .. rc .. " (Invalid BUS / Invalid CAN baudrate / Key off)")
end
can.disableFilters()
can.startLog('OBDTLog.log')
ui.sleep(100*5) --sleep 5 secs
print('Testing 7E0-7E8')
handleSAESupportMap(0x7E0, 0x7E8, '7E07E8.txt')
ui.sleep(100*5) --sleep 5 secs
print('Testing 0x18DB33F1-0x18DAF110')
handleSAESupportMap(0x18DB33F1, 0x18DAF110, '18DB33F1.txt')
ui.sleep(100*5) --sleep 5 secs
-- test for FIAT
print('Testing 0x18DA40F1-0x18DAF140')
handleSAESupportMap(0x18DA40F1, 0x18DAF140, '18DA40F1.txt')
print('Turn Key OFF for testing..')
ui.sleep(100*5) --sleep 5 secs
can.stopLog()
can.enableFilters()
can.uninit()
print('DONE.')
