Skip to content

Instantly share code, notes, and snippets.

@yonatan8070
Created June 11, 2025 08:34
Show Gist options
  • Save yonatan8070/a656d4ef69cb1e4235a3a23202665341 to your computer and use it in GitHub Desktop.
Save yonatan8070/a656d4ef69cb1e4235a3a23202665341 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<style>
html{
height: 100%;
}
body {
font-family: Arial;
display:flex;
flex-direction: column;
justify-content: center;
background: linear-gradient(180deg, rgba(63,160,127,1) 0%, rgba(9,84,124,1) 100%);
background-repeat: no-repeat;
height: 100%;
}
.mainFrame{
position: relative;
text-align: center;
margin: auto;
height: auto;
}
.subFrame{
position: relative;
text-align: center;
background-color: gainsboro;
border-radius: 10px;
text-align: left;
margin: auto;
padding: 20px;
height: auto;
margin-bottom: 20px;
}
#mainHeader{
position: relative;
text-align: center;
margin-top: 20px;
background-color: gainsboro;
border-radius: 10px;
text-align: center;
margin: auto;
text-decoration-color: azure;
}
#divError{
border-style: solid;
border-width: 1px;
border-color: red;
text-align: center;
background-color: rgb(255, 188, 177);
padding: 5px;
border-radius: 10px;
}
.divReturn{
border-style: solid;
border-width: 1px;
border-color: rgb(56, 235, 248);
background-color: rgb(192, 237, 255);
padding: 5px;
border-radius: 10px;
width: auto;
}
td{
text-align: left;
padding:5px;
}
.divFooter {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
color: rgb(165, 165, 165);
text-align: center;
}
</style>
</head>
<body>
<!-- HTML part-->
<!-- ------------------------ -->
<div class="mainFrame">
<!-- Frame cobID decoding -->
<div class="subFrame">
<!-- Header -->
<div id="mainHeader">
<h2 style="color: rgb(99, 99, 99);">Decode CobID</h2>
</div>
<!-- COB-ID input area -->
<table>
<tr>
<td><label>Enter CobId [0x]</label></td>
<td><input id="inpCobId" type="text"></input></td>
<td>
<button onclick="fDecodeCobId()">Decode</button>
</td>
</tr>
</table><br/>
<!-- return -->
<div id="divType" class="divReturn" style="display:none">
<table id="tabType">
<tr>
<td><b><label>Message type</label></b></td>
<td><label id="lblType"></label><br/></td>
</tr>
<tr>
<td><b><label>Node </label></b></td>
<td><label id="lblNode"></label></td>
</tr>
</table>
</div>
</div>
<!-- Frame data decoding -->
<div id="divData" class="subFrame" style="display:none">
<!-- Header -->
<div id="mainHeader">
<h2 style="color: rgb(99, 99, 99);">Decode Frame data</h2>
</div>
<!-- data decode -->
<table id="tabData" >
<tr>
<td><label>Enter Data [0x]</label></td>
<td><input id="inpData" type="text"></input></td>
<td>
<button onclick="fDecodeData()">Decode</button>
</td>
</tr>
</table><br/>
<!-- return -->
<div id="divDataReturn" class="divReturn" style="display:none">
<table id="tabDataReturn">
<tbody>
</tbody>
</table>
</div>
</div>
<!-- return -->
<div id="divError" class="subFrame" style="display:none">
<label id="lblError"></label>
</div>
</div>
<!-- Footer -->
<div class="divFooter">
<p>&lt;°///---&lt;</p>
</div>
</body>
</html>
<!-- Scripts -->
<script>
// decode CobId
// -------------------------------------
function fDecodeCobId(){
// reset canvas
document.getElementById("divError").style.display = "none";
document.getElementById("divType").style.display = "none";
document.getElementById('divData').style.display = 'none';
document.getElementById('divDataReturn').style.display = 'none';
// get data of input field
szData = document.getElementById("inpCobId").value;
szData = szData.replace(/ /g,'');
// check input
// --------------
// check empty string
if (!szData.length){
fSetError("No data entered");
return;
}
// check if data is hexadecimal
if ((!fIsHex(szData)) && (iDataFormat == 1)){
fSetError("Entered data not hexadecimal");
return;
}
// prepare number
iData = parseInt(szData, 16);
// check message type
// ----
fGetMessageType(iData);
}
// help functions
// -------------------------------------
// check if string is in hex
function fIsHex(iData) {
regexp = /^[0-9a-fA-F ]+$/;
return regexp.test(iData);
}
// set error
function fSetError(szErrorText){
// set error
document.getElementById("lblError").textContent = "Error : " + szErrorText;
// show output
document.getElementById("divError").style.display = "block";
}
// show data input fields
function fShowDataInput() {
document.getElementById('divData').style.display = 'block';
}
// get message type
function fGetMessageType(iData) {
iNode = -1;
// check mnessage type
switch(true) {
case iData == 0x00:
// NMT command
szType = "NMT Command";
iMsgType = 1;
fShowDataInput();
break;
case iData == 0x80:
// Sync telegram
szType = "SYNC Telegram";
iMsgType = 2;
break;
case iData >= 0x80 && iData <= 0xFF:
// Emergency telegram
szType = "EMCY Telegram";
iNode = iData % 0x80;
iMsgType = 3;
break;
case iData == 0x100:
// Time telegram
szType = "TIME Telegram";
iMsgType = 4;
break;
case iData >= 0x180 && iData <= 0x1FF:
// Transmit PDO 1
szType = "Transmit PDO 1";
iNode = iData % 0x180;
iMsgType = 5;
break;
case iData >= 0x200 && iData <= 0x27F:
// Recieve PDO 1
szType = "Recieve PDO 1";
iNode = iData % 0x201;
iMsgType = 6;
break;
case iData >= 0x280 && iData <= 0x2FF:
// Transmit PDO 2
szType = "Transmit PDO 2";
iNode = iData % 0x280;
iMsgType = 7;
break;
case iData >= 0x300 && iData <= 0x37F:
// Recieve PDO 2
szType = "Recieve PDO 2";
iNode = iData % 0x300;
iMsgType = 8;
break;
case iData >= 0x380 && iData <= 0x3FF:
// Transmit PDO 3
szType = "Transmit PDO 3"
iNode = iData % 0x380;
iMsgType = 9;
break;
case iData >= 0x400 && iData <= 0x47F:
// Recieve PDO 3
szType = "Recieve PDO 3";
iNode = iData % 0x400;
iMsgType = 10;
break;
case iData >= 0x480 && iData <= 0x4FF:
// Transmit PDO 4
szType = "Transmit PDO 4"
iNode = iData % 0x480;
iMsgType = 11;
break;
case iData >= 0x500 && iData <= 0x57F:
// Recieve PDO 4
szType = "Recieve PDO 4";
iNode = iData % 0x500;
iMsgType = 12;
break;
case iData >= 0x580 && iData <= 0x5FF:
// Transmit SDO
szType = "Transmit SDO"
iNode = iData % 0x580;
iMsgType = 14;
fShowDataInput();
break;
case iData >= 0x600 && iData <= 0x67F:
// Recieve SDO
szType = "Recieve SDO";
iNode = iData % 0x600;
iMsgType = 15;
fShowDataInput();
break;
case iData >= 0x700 && iData <= 0x77F:
// Heartbeat
szType = "Heartbeat / Nodeguarding";
iNode = iData % 0x700;
iMsgType = 16;
fShowDataInput();
break;
default:
fSetError("Unknown Cob-Id");
return;
}
// set message
document.getElementById("lblType").textContent = szType;
// append node if available
if (iNode >= 0){
document.getElementById("lblNode").textContent = "0x" + (iNode.toString(16)).toUpperCase();
}
else{
document.getElementById("lblNode").textContent = "-";
}
// show output
document.getElementById("divType").style.display = "block";
}
// decode frame specific data
function fDecodeData(){
// hide all elements
document.getElementById("divError").style.display = "none";
document.getElementById('divDataReturn').style.display = 'none';
// get data
szData = document.getElementById("inpData").value;
szData = szData.replace(/ /g,'');
// check empty string
if (!szData.length){
fSetError("No data entered");
return;
}
// check if data is hexadecimal
if ((!fIsHex(szData)) && (iDataFormat == 1)){
fSetError("Entered data not hexadecimal");
return;
}
// call depending function
switch (iMsgType){
case 1:
// NMT
iStatus = fDecodeNmt(szData);
break;
case 14:
// Transmit SDO
iStatus = fDecodeSdoTx(szData);
break;
case 15:
// Recieve SDO
iStatus = fDecodeSdoRx(szData);
break;
break;
case 16:
// Nodeguard / Hearbeat
iStatus = fDecodeHeartbeat(szData);
break;
default:
break;
}
// show return frame
if (iStatus == 0){
document.getElementById("divDataReturn").style.display = "block";
}
}
// decode heartbeat data
function fDecodeHeartbeat(szData) {
// check length
if (szData.length % 2 != 0){
fSetError("invalid length due to its telegram type");
return 1;
}
// check length
if ((szData.length != 2)){
fSetError("invalid length due to its telegram type");
return 1;
}
// prepare table
var objTable = document.getElementById("tabDataReturn").getElementsByTagName('tbody')[0];
fDeleteAllRows(objTable);
// get nmt state
szCmdByte = szData.substring(0, 2, 16);
// Nmt state
iNmtSts = (parseInt(szCmdByte,16) & 0b0111_1111);
switch(iNmtSts){
case 0x00:
szSts = "Bootup";
break;
case 0x04:
szSts = "Stopped";
break;
case 0x05:
szSts = "Operational";
break;
case 0x7F:
szSts = "Pre-Operational";
break;
default:
fSetError("unknown state");
return 1;
}
fAddRow(objTable, "Nmt-Status", szSts)
// toggle bit
iToggleBit = (parseInt("0x" + szCmdByte) & 0b1000_0000) >> 7;
// protocol type
if (iToggleBit){
fAddRow(objTable, "Service", "Node-Guarding");
}
else{
fAddRow(objTable, "Service", "Heartbeat or Node-Guarding");
}
// return no error
return 0;
}
// decode NMt data
function fDecodeNmt(szData) {
// check length
if (szData.length % 2 != 0){
fSetError("invalid length due to its telegram type");
return 1;
}
// check length
if ((szData.length != 4)){
fSetError("invalid length due to its telegram type");
return 1;
}
// prepare table
var objTable = document.getElementById("tabDataReturn").getElementsByTagName('tbody')[0];
fDeleteAllRows(objTable);
// row command
iCmd = parseInt(szData.substring(0, 2),16);
switch(iCmd){
case 0x01:
szCmd = "Enter Operational";
break;
case 0x02:
szCmd = "Enter Stop";
break;
case 0x80:
szCmd = "Enter Pre-Operational";
break;
case 0x81:
szCmd = "Reset Node";
break;
case 0x82:
szCmd = "Reset communication";
break;
default:
fSetError("unknown command");
return 1;
}
fAddRow(objTable, "Command", szCmd)
// row node
iNode = parseInt(szData.substring(2, 4), 16)
if (iNode == 0){
fAddRow(objTable, "Node", "All");
}
else{
fAddRow(objTable, "Node", iNode);
}
// return no error
return 0;
}
// decode Recive SDO
function fDecodeSdoRx(szData){
// check to long
if (szData.length > 16){
fSetError("telegram to long");
return 1;
}
// check length
if (szData.length % 2 != 0){
fSetError("invalid length due to its telegram type");
return 1;
}
// prepare table
var objTable = document.getElementById("tabDataReturn").getElementsByTagName('tbody')[0];
fDeleteAllRows(objTable);
// row sdo type
szCmdByte= szData.substring(0, 2, 16);
// Ccs
iCcs = (parseInt(szCmdByte, 16) & 0b1110_0000) >> 5;
// check command
if (iCcs == 0b010){
// read command
// read
fAddRow(objTable, "Command", "Read dictionary");
// index
szIndex1 = szData.substring(2, 4, 16);
szIndex2 = szData.substring(4, 6, 16);
if ((szIndex1 != "") || (szIndex2 != "")){
fAddRow(objTable, "Index", "0x" + szIndex2 + szIndex1);
}
// sub index
szSubIndex = szData.substring(6, 8, 16);
if (szSubIndex != ""){
fAddRow(objTable, "Subindex", "0x" + szSubIndex);
}
// data
szData = szData.substring(8, szData.length, 16);
if (szData != ""){
fAddRow(objTable, "Data", "0x" + szData);
}
} else if (iCcs == 0b001){
// write command
// read
fAddRow(objTable, "Command", "Write dictionary");
// sdo type
iSdoType = (parseInt(szCmdByte, 16) & 0b0000_0010) >> 1;
if (iSdoType == 1){
// expedited mode
fAddRow(objTable, "Mode", "Expedited (1 frame)");
}
// size
iSizeKnown = (parseInt(szCmdByte, 16) & 0b0000_0001);
iSize = (parseInt(szCmdByte, 16) & 0b0000_1100) >> 2;
iSize = (4-iSize);
if (iSizeKnown == 1){
fAddRow(objTable, "Data size", iSize);
}
else{
fAddRow(objTable, "Data size", "unknown");
}
// index
szIndex1 = szData.substring(2, 4, 16);
szIndex2 = szData.substring(4, 6, 16);
if ((szIndex1 != "") || (szIndex2 != "")){
fAddRow(objTable, "Index", "0x" + szIndex2.toUpperCase() + szIndex1.toUpperCase());
}
// sub index
szSubIndex = szData.substring(6, 8, 16);
if (szSubIndex != ""){
fAddRow(objTable, "Subindex", "0x" + szSubIndex.toUpperCase());
}
// data
if (iSizeKnown){
szData = szData.substring(8, 8 + iSize*2, 16);
}
else{
szData = szData.substring(8, szData.length, 16);
}
if (szData != ""){
fAddRow(objTable, "Data", "0x" + szData.toUpperCase());
}
}
else{
// invalid command
fSetError("Invalid command");
return 1;
}
// return no error
return 0;
}
// decode Transmit SDO
function fDecodeSdoTx(szData){
// check to long
if (szData.length > 16){
fSetError("telegram to long");
return 1;
}
// check length
if (szData.length % 2 != 0){
fSetError("invalid length due to its telegram type");
return 1;
}
// prepare table
var objTable = document.getElementById("tabDataReturn").getElementsByTagName('tbody')[0];
fDeleteAllRows(objTable);
// row sdo type
szCmdByte= szData.substring(0, 2, 16);
// Ccs
iCcs = (parseInt(szCmdByte, 16) & 0b1110_0000) >> 5;
// check command
if (parseInt(szCmdByte, 16) == 0x80){
// error response
// read
fAddRow(objTable, "Type", "Error response");
// index
szIndex1 = szData.substring(2, 4, 16);
szIndex2 = szData.substring(4, 6, 16);
if ((szIndex1 != "") || (szIndex2 != "")){
fAddRow(objTable, "Index", "0x" + szIndex2 + szIndex1);
}
// sub index
szSubIndex = szData.substring(6, 8, 16);
if (szSubIndex != ""){
fAddRow(objTable, "Subindex", "0x" + szSubIndex.toUpperCase());
}
// error
szError = szData.substring(8, szData.length, 16);
if (szError != ""){
fAddRow(objTable, "Abort code", "0x" + szError.toUpperCase());
}
}
else if (iCcs == 0b010){
// read command
// read
fAddRow(objTable, "Command", "Read dictionary");
// sdo type
iSdoType = (parseInt(szCmdByte, 16) & 0b0000_0010) >> 1;
if (iSdoType == 1){
// expedited mode
fAddRow(objTable, "Mode", "Expedited (1 frame)");
}
// size
iSizeKnown = (parseInt(szCmdByte, 16) & 0b0000_0001);
iSize = (parseInt(szCmdByte, 16) & 0b0000_1100) >> 2;
iSize = (4-iSize);
if (iSizeKnown == 1){
fAddRow(objTable, "Data size", iSize);
}
else{
fAddRow(objTable, "Data size", "unknown");
}
// index
szIndex1 = szData.substring(2, 4, 16);
szIndex2 = szData.substring(4, 6, 16);
if ((szIndex1 != "") || (szIndex2 != "")){
fAddRow(objTable, "Index", "0x" + szIndex2 + szIndex1);
}
// sub index
szSubIndex = szData.substring(6, 8, 16);
if (szSubIndex != ""){
fAddRow(objTable, "Subindex", "0x" + szSubIndex.toUpperCase());
}
// data
if (iSizeKnown){
szData = szData.substring(8, 8 + iSize*2, 16);
}
else{
szData = szData.substring(8, szData.length, 16);
}
if (szData != ""){
fAddRow(objTable, "Data", "0x" + szData.toUpperCase());
}
} else if (iCcs == 0b001){
// write command
// read
fAddRow(objTable, "Command", "Write dictionary");
// index
szIndex1 = szData.substring(2, 4, 16);
szIndex2 = szData.substring(4, 6, 16);
if ((szIndex1 != "") || (szIndex2 != "")){
fAddRow(objTable, "Index", "0x" + szIndex2.toUpperCase() + szIndex1.toUpperCase());
}
// sub index
szSubIndex = szData.substring(6, 8, 16);
if (szSubIndex != ""){
fAddRow(objTable, "Subindex", "0x" + szSubIndex.toUpperCase());
}
// data
szData = szData.substring(8, szData.length, 16);
if (szData != ""){
fAddRow(objTable, "Data", "0x" + szData.toUpperCase());
}
}
else{
// invalid command
fSetError("Invalid command");
return 1;
}
// return no error
return 0;
}
// delete all rows
function fDeleteAllRows(objTable){
// delete all rows
while(objTable.rows.length > 0) {
objTable.deleteRow(0);
}
}
// add a new row
function fAddRow(objTable, szDesc, iValue){
var objRow = objTable.insertRow(objTable.rows.length);
var objCell1 = objRow.insertCell(0);
var objCell2 = objRow.insertCell(1);
objCell1.innerHTML = "<b>" + szDesc + "</b>"
objCell2.innerHTML = iValue;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment