<!doctype html>
<html lang="en-us">

<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="description" content="CANStudio is a convienent way to visualize and interact with a CANBUS." />
    <meta name="keywords" content="CANBUS, CAN, Controller Area Network" />
    <meta name="author" content="PhasorSystems" />
    <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimum-scale=1.0, height=device-height" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv='Cache-Control' content='no-cache, no-store, must-revalidate' />
    <meta http-equiv='Expires' content='0' />
    <meta http-equiv='Pragma' content='no-cache' />
    <link rel="stylesheet" href="{{ url_for('static', filename='styles/FontAwesome-4.7.0/css/font-awesome.min.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='styles/Toastify/toastify.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='styles/SweetAlert2/minimal.css') }}">
    <script src="{{ url_for('static', filename='javascript/SweetAlert2/sweetalert2.all.min.js') }}"></script>
    <link rel="stylesheet" href="{{ url_for('static', filename='styles/MicroModal/MicroModal.css') }}">
    <script src="{{ url_for('static', filename='javascript/MicroModal/MicroModal.js') }}"></script>
    <script type="text/javascript" src="{{ url_for('static', filename='javascript/Toastify/toastify.js') }}"></script>
    <script type="text/javascript" src="{{ url_for('static', filename='javascript/FileSaver/FileSaver.js') }}"></script>
    <script type="text/javascript" src="{{ url_for('static', filename='javascript/Lodash/lodash.js') }}"></script>
    <script type="text/javascript"
        src="{{ url_for('static', filename='javascript/SocketIO/SocketIO-4.8.1.js') }}"></script>
    <title>CANStudio: CANBUS Explorer</title>
    <link rel="icon" href="{{ url_for('static', filename='images/favicon.png') }}" />
    <link rel="stylesheet" href="{{ url_for('static', filename='styles/styles.css') }}">
</head>

<body oncontextmenu="return false;">
    <div id="main_wrapper" class="wrapper">
        <div id="id_left_panel" class="left_panel">

            <div id="navigation_bar" class="navbar">
                <div class="row">
                    <div class="left">
                        <div class="dropdown">
                            <input id="dbc_input_dialog" type="file" style="visibility:hidden; display:none;"
                                name="DBC_file" accept=".dbc" onchange="dbc_file_event(this)"
                                onclick="this.value=null;" />
                            <input id="dfu_input_dialog" type="file" style="visibility:hidden; display:none;"
                                name="DFU_file" accept=".dfu" onchange="dfu_file_event(this)"
                                onclick="this.value=null;" />
                        </div>
                    </div>

                    <div class="middle">
                        <div id="id_app_title" class="app_title" title="CANBUS Visualization and Interaction Tool">
                            CANStudio
                        </div>
                    </div>

                    <div class="right">
                        <a style="float:right" onclick="show_about()" title="Show about"><i class="fa fa-info"
                                aria-hidden="true"></i>&nbsp;About</a>
                        <!-- <a style="float:right" onclick="select_dfu_file()" title="Flash Device Firmware"><i
                                class="fa fa-file-code-o" aria-hidden="true"></i>&nbsp;Flash Device Firmware</a> -->
                    </div>
                </div>
                <hr style="margin:0px" color="black" noshade>
            </div>

            <div class="emscripten_border">
                <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
            </div>
        </div>

        <div id="id_right_panel" class="right_panel">

        </div>
    </div>

    <hr width="100%" size="10" color="black" noshade>

    <textarea tabindex="-1" id="clipboard" value="" style="visibility: hidden; position: fixed;"></textarea>

    <script>
const IS_LOCAL_VERSION=!0,POPUP_WIDTH_MAX=500,POPUP_WIDTH_PERCENT=.25,VERSION="1.0.0",BACKSPACE_KEY=8,DEBUGGING=!1,SOCKETIO_TIMEOUT=55E3,STRING_BUFFER_MAX=4096;var connected_to_server=!1;window.addEventListener("beforeunload",a=>{a.preventDefault();return a.returnValue="Are you sure you want to leave?"});var socket=io.connect("http://localhost:"+location.port,{pingInterval:25E3,pingTimeout:2E4});
const fake_canbus_messages=()=>{if(runtime_initialized&&Module._malloc&&Module._free&&js_push_can_message){var a=lengthBytesUTF8("")+1,b=Module._malloc(a);stringToUTF8("",b,a);js_push_can_message(0,600,0,8,0,0,cpp_random_byte(),cpp_random_byte(),cpp_random_byte(),cpp_random_byte(),cpp_random_byte(),cpp_random_byte(),cpp_random_byte(),cpp_random_byte(),b,a);Module._free(b)}};DEBUGGING&&setInterval(fake_canbus_messages,1E3);
var canbus_configuration={busSpeed:5E5,deviceChannel:"/dev/ttyACM0",messageFilter:0,messageMask:0},tx_struct={arbitration_id:-1,is_extended_id:!1,is_remote_frame:!1,dlc:0,data:[],period:.5,enable_timer:!1};function is_valid_filename(a){return!/[\\/:*?"<>|]/.test(a)}
const cpp_update_device_channel=a=>{canbus_configuration.deviceChannel=a},cpp_update_bus_speed=a=>{canbus_configuration.busSpeed=a},cpp_update_filter=a=>{canbus_configuration.messageFilter=a},cpp_update_mask=a=>{canbus_configuration.messageMask=a},cpp_configure_canbus=(a,b,c,d)=>{canbus_configuration.busSpeed=a;canbus_configuration.deviceChannel=b;canbus_configuration.messageFilter=c;canbus_configuration.messageMask=d;configure_canbus(canbus_configuration)},cpp_transmit_rtx_message=(a,b,c,d,e,f,k,
h,g,m,n,l,p,q)=>{tx_struct.arbitration_id=a;tx_struct.dlc=b;tx_struct.data=[e,f,k,h,g,m,n,l];tx_struct.period=p;tx_struct.enable_timer=q;tx_struct.is_extended_id=c;tx_struct.is_remote_frame=d;transmit_rtx_message(tx_struct)},cpp_transmit_message=(a,b,c,d,e,f,k,h,g,m,n,l)=>{tx_struct.arbitration_id=a;tx_struct.dlc=b;tx_struct.data=[e,f,k,h,g,m,n,l];tx_struct.is_extended_id=c;tx_struct.is_remote_frame=d;transmit_message(tx_struct)},cpp_update_logging=(a,b)=>{if(""!==a.trim())if(is_valid_filename(a.trim())){var c=
{EnableLogging:b,LogFileName:a};socket.timeout(SOCKETIO_TIMEOUT).emit("update_logging",{message:c},(d,e)=>{d?log_to_cpp("Logging update operation timed out.",LOG_COLORS.E_COL_RED):""!==e.error?log_to_cpp(e.error,LOG_COLORS.E_COL_RED):log_to_cpp(`Successfully updated logging. FileName:= ${a}, EnableLogging:= ${b}.`,LOG_COLORS.E_COL_GREEN)})}else log_to_cpp('Log file name cannot contain the following characters: [\\/:*?"<>|].',LOG_COLORS.E_COL_RED);else log_to_cpp("Log file name cannot be empty.",LOG_COLORS.E_COL_RED)},
transmit_message=a=>{socket.timeout(SOCKETIO_TIMEOUT).emit("transmit",a,(b,c)=>{b?log_to_cpp("Transmit message operation timed out.",LOG_COLORS.E_COL_RED):""!==c.error?log_to_cpp(c.error,LOG_COLORS.E_COL_RED):log_to_cpp("Successfully transmitted message.",LOG_COLORS.E_COL_GREEN)})},request_device_errors=()=>{socket.timeout(SOCKETIO_TIMEOUT).emit("request_device_errors",{data:""},(a,b)=>{a?log_to_cpp("Device error request operation timed out.",LOG_COLORS.E_COL_RED):""!==b.error&&log_to_cpp(b.error,
LOG_COLORS.E_COL_RED)})},transmit_rtx_message=a=>{socket.timeout(SOCKETIO_TIMEOUT).emit("repeated_transmit",a,(b,c)=>{b?log_to_cpp("Transmission of repeated message configuration operation timed out.",LOG_COLORS.E_COL_RED):""!==c.error?log_to_cpp(c.error,LOG_COLORS.E_COL_RED):log_to_cpp("Successfully updated repeated transmission.",LOG_COLORS.E_COL_GREEN)})},transmit_dbc_message=a=>{let b;try{b=JSON.parse(a)}catch(c){log_to_cpp("Error parsing DBC JSON string: "+(c instanceof Error?c.message:String(c)),
LOG_COLORS.E_COL_RED);return}socket.timeout(SOCKETIO_TIMEOUT).emit("transmit_dbc_message",b,(c,d)=>{c?log_to_cpp("Transmission of dbc message operation timed out.",LOG_COLORS.E_COL_RED):""!==d.error?log_to_cpp(d.error,LOG_COLORS.E_COL_RED):log_to_cpp("Successfully transmitted message.",LOG_COLORS.E_COL_GREEN)})},configure_canbus=a=>{socket.timeout(SOCKETIO_TIMEOUT).emit("configure",a,(b,c)=>{b?log_to_cpp("Canbus configuration operation timed out.",LOG_COLORS.E_COL_RED):""!==c.error&&log_to_cpp(c.error,
LOG_COLORS.E_COL_RED)})},cpp_refresh_ports=()=>{js_clear_serial_ports&&js_push_serial_port&&Module._malloc&&Module._free?socket.timeout(SOCKETIO_TIMEOUT).emit("list_serial_ports",{data:""},(a,b)=>{if(a)log_to_cpp("Listing serial ports operation timed out.",LOG_COLORS.E_COL_RED);else if(""!==b.error)log_to_cpp(b.error,LOG_COLORS.E_COL_RED);else if("ok"===b.response&&b.available_ports){a=Object.keys(b.available_ports);let c,d;js_clear_serial_ports();for(let e=0;e<a.length;e++)if(b=a[e].trim())c=lengthBytesUTF8(b)+
1,d=Module._malloc(c),stringToUTF8(b,d,c),js_push_serial_port(d,c),Module._free(d);log_to_cpp("Successfully refreshed ports.",LOG_COLORS.E_COL_GREEN)}else log_to_cpp(b.error||"Failed to refresh ports (unknown reason).",LOG_COLORS.E_COL_RED)}):log_to_cpp("Refresh ports required functions not available.",LOG_COLORS.E_COL_RED)},cpp_configure_mask_filter=(a,b)=>{canbus_configuration.messageFilter=a;canbus_configuration.messageMask=b;socket.timeout(SOCKETIO_TIMEOUT).emit("configure_mask_filter",canbus_configuration,
(c,d)=>{c?log_to_cpp("Configuring mask and filter operation timed out.",LOG_COLORS.E_COL_RED):""!==d.error?log_to_cpp(d.error,LOG_COLORS.E_COL_RED):log_to_cpp("Successfully updated mask and code.",LOG_COLORS.E_COL_GREEN)})},cpp_open_canbus=()=>{js_set_bus_on?socket.timeout(SOCKETIO_TIMEOUT).emit("open_canbus",{data:""},(a,b)=>{a?log_to_cpp("Open canbus operation timed out.",LOG_COLORS.E_COL_RED):""!==b.error?(log_to_cpp(b.error,LOG_COLORS.E_COL_RED),js_set_bus_on(0)):"ok"===b.response?(js_set_bus_on(1),
log_to_cpp("Successfully connected to device.",LOG_COLORS.E_COL_GREEN),configure_canbus(canbus_configuration)):(js_set_bus_on(0),log_to_cpp(b.error||"Unsuccessful connection to device (unknown reason).",LOG_COLORS.E_COL_RED))}):log_to_cpp("js_set_bus_on function not available.",LOG_COLORS.E_COL_RED)},cpp_cleanup_system=()=>{socket.timeout(SOCKETIO_TIMEOUT).emit("cleanup_system",{data:""},(a,b)=>{a?log_to_cpp("System cleanup operation timed out.",LOG_COLORS.E_COL_RED):""!==b.error&&log_to_cpp(b.error,
LOG_COLORS.E_COL_RED)})},cpp_close_canbus=()=>{js_set_bus_on?socket.timeout(SOCKETIO_TIMEOUT).emit("close_canbus",{data:""},(a,b)=>{a?log_to_cpp("Close canbus operation timed out.",LOG_COLORS.E_COL_RED):""!==b.error?log_to_cpp(b.error,LOG_COLORS.E_COL_RED):(js_set_bus_on(0),log_to_cpp("Successfully disconnected from device.",LOG_COLORS.E_COL_GREEN))}):log_to_cpp("js_set_bus_on function not available.",LOG_COLORS.E_COL_RED)},cpp_status_canbus=()=>{socket.timeout(SOCKETIO_TIMEOUT).emit("status",{data:""},
(a,b)=>{a?log_to_cpp("Status request operation timed out.",LOG_COLORS.E_COL_RED):""!==b.error?log_to_cpp(b.error,LOG_COLORS.E_COL_RED):log_to_cpp("Successfully requested status.",LOG_COLORS.E_COL_GREEN)})},cpp_random_byte=()=>255*Math.random()|0,perform_firmware_update=a=>{socket.timeout(SOCKETIO_TIMEOUT).emit("flash_firmware",{data:a},(b,c)=>{b?log_to_cpp("Flash firmware operation timed out.",LOG_COLORS.E_COL_RED):""!==c.error?log_to_cpp(c.error,LOG_COLORS.E_COL_RED):log_to_cpp("Successfully flashed device firmware.",
LOG_COLORS.E_COL_GREEN)})},perform_dbc_update=(a,b)=>{js_reset_signal_node_names&&js_push_node_name&&js_push_signal_name&&js_push_node_signal&&Module._malloc&&Module._free?socket.timeout(SOCKETIO_TIMEOUT).emit("update_dbc",{data:b},(c,d)=>{if(c)log_to_cpp("Update DBC operation timed out.",LOG_COLORS.E_COL_RED);else if(""!==d.error)log_to_cpp(d.error,LOG_COLORS.E_COL_RED);else if("ok"===d.response){set_dbc_file_name(a);var e=d.node_names.split(","),f=d.signal_names.split(",");js_reset_signal_node_names();
for(var k=0;k<e.length;k++)if(c=e[k].trim()){var h=lengthBytesUTF8(c)+1;var g=Module._malloc(h);stringToUTF8(c,g,h);js_push_node_name(g,h);Module._free(g)}for(e=0;e<f.length;e++)if(c=f[e].trim())h=lengthBytesUTF8(c)+1,g=Module._malloc(h),stringToUTF8(c,g,h),js_push_signal_name(g,h),Module._free(g);let m;try{m=JSON.parse(d.node_signals)}catch(l){log_to_cpp("Error parsing node_signals JSON: "+(l instanceof Error?l.message:String(l)),LOG_COLORS.E_COL_RED);return}d=Object.keys(m);let n;for(g=0;g<d.length;g++)if((f=
d[g].trim())&&m[d[g]]){h=lengthBytesUTF8(f)+1;c=Module._malloc(h);stringToUTF8(f,c,h);f=Object.keys(m[d[g]]);for(let l=0;l<f.length;l++){n=f[l].trim();if(!n||!m[d[g]][f[l]])continue;const p=m[d[g]][f[l]];k=lengthBytesUTF8(n)+1;e=Module._malloc(k);stringToUTF8(n,e,k);js_push_node_signal(c,e,h,k,p[1],p[0]);Module._free(e)}Module._free(c)}log_to_cpp(`Successfully loaded ${a}.`,LOG_COLORS.E_COL_GREEN)}else log_to_cpp(d.error||"Failed to update DBC (missing data or invalid response).",LOG_COLORS.E_COL_RED)}):
log_to_cpp("DBC update required functions not available.",LOG_COLORS.E_COL_RED)};socket.on("connect",function(){cpp_cleanup_system();connected_to_server=!0});socket.on("disconnect",function(){connected_to_server=!1});socket.on("cli_progress",function(a){runtime_initialized&&log_to_cpp(`Flashing:= ${a.progress}%...`,LOG_COLORS.E_COL_GREEN)});socket.on("error_register_update",function(a){runtime_initialized&&js_set_can_error_register&&js_set_can_error_register(a.register)});
socket.on("error_report",function(a){runtime_initialized&&js_set_bus_on&&(log_to_cpp(`Title:= ${a.title} ->\r\n${a.error}`,LOG_COLORS.E_COL_RED),js_set_bus_on(0),log_to_cpp("Device error reported. Disconnected from device. Reconnect to continue using it.",LOG_COLORS.E_COL_RED))});
socket.on("message",function(a){var b,c,d,e,f,k,h,g;if(runtime_initialized&&js_push_can_message&&Module._malloc&&Module._free){const m=a.signals||"",n=lengthBytesUTF8(m)+1,l=Module._malloc(n);stringToUTF8(m,l,n);js_push_can_message(a.timestamp,a.arbitration_id,0,a.dlc,a.is_extended_id?1:0,a.is_remote_frame?1:0,null!==(b=a.data[0])&&void 0!==b?b:0,null!==(c=a.data[1])&&void 0!==c?c:0,null!==(d=a.data[2])&&void 0!==d?d:0,null!==(e=a.data[3])&&void 0!==e?e:0,null!==(f=a.data[4])&&void 0!==f?f:0,null!==
(k=a.data[5])&&void 0!==k?k:0,null!==(h=a.data[6])&&void 0!==h?h:0,null!==(g=a.data[7])&&void 0!==g?g:0,l,n);Module._free(l)}});
socket.on("message_history",function(a){var b,c,d,e,f,k,h,g,m,n,l,p,q,r,t,u;if(runtime_initialized&&js_push_can_message&&js_push_can_message_history&&Module._malloc&&Module._free){const x=a.signals||"",v=lengthBytesUTF8(x)+1,w=Module._malloc(v);stringToUTF8(x,w,v);js_push_can_message(a.timestamp,a.arbitration_id,1,a.dlc,a.is_extended_id?1:0,a.is_remote_frame?1:0,null!==(b=a.data[0])&&void 0!==b?b:0,null!==(c=a.data[1])&&void 0!==c?c:0,null!==(d=a.data[2])&&void 0!==d?d:0,null!==(e=a.data[3])&&void 0!==
e?e:0,null!==(f=a.data[4])&&void 0!==f?f:0,null!==(k=a.data[5])&&void 0!==k?k:0,null!==(h=a.data[6])&&void 0!==h?h:0,null!==(g=a.data[7])&&void 0!==g?g:0,w,v);js_push_can_message_history(a.timestamp,a.arbitration_id,1,a.dlc,a.is_extended_id?1:0,a.is_remote_frame?1:0,null!==(m=a.data[0])&&void 0!==m?m:0,null!==(n=a.data[1])&&void 0!==n?n:0,null!==(l=a.data[2])&&void 0!==l?l:0,null!==(p=a.data[3])&&void 0!==p?p:0,null!==(q=a.data[4])&&void 0!==q?q:0,null!==(r=a.data[5])&&void 0!==r?r:0,null!==(t=a.data[6])&&
void 0!==t?t:0,null!==(u=a.data[7])&&void 0!==u?u:0);Module._free(w)}});
socket.on("message_wo_history",function(a){var b,c,d,e,f,k,h,g;if(runtime_initialized&&js_push_can_message&&Module._malloc&&Module._free){const m=a.signals||"",n=lengthBytesUTF8(m)+1,l=Module._malloc(n);stringToUTF8(m,l,n);js_push_can_message(a.timestamp,a.arbitration_id,1,a.dlc,a.is_extended_id?1:0,a.is_remote_frame?1:0,null!==(b=a.data[0])&&void 0!==b?b:0,null!==(c=a.data[1])&&void 0!==c?c:0,null!==(d=a.data[2])&&void 0!==d?d:0,null!==(e=a.data[3])&&void 0!==e?e:0,null!==(f=a.data[4])&&void 0!==
f?f:0,null!==(k=a.data[5])&&void 0!==k?k:0,null!==(h=a.data[6])&&void 0!==h?h:0,null!==(g=a.data[7])&&void 0!==g?g:0,l,n);Module._free(l)}});
async function push_to_system_clipboard(){if(js_get_clipboard)try{const a=await Promise.resolve(js_get_clipboard()),b=UTF8ToString(a);navigator.clipboard&&"function"===typeof navigator.clipboard.writeText?await navigator.clipboard.writeText(b):log_to_cpp("Clipboard API not available.",LOG_COLORS.E_COL_YELLOW)}catch(a){log_to_cpp("Error getting/pushing clipboard data: "+(a instanceof Error?a.message:String(a)),LOG_COLORS.E_COL_RED)}}
window.onkeydown=function(a){var b=a.target;b=b&&("INPUT"===b.tagName||"TEXTAREA"===b.tagName||b.isContentEditable);"Backspace"!==a.key||b||a.preventDefault()};
async function on_document_paste(a){if(a.clipboardData&&js_set_clipboard&&Module._malloc&&Module._free){let b=null;try{const c=a.clipboardData.getData("text/plain");a="";a=c.length>STRING_BUFFER_MAX-16?c.substring(0,STRING_BUFFER_MAX-16)+"...":c;const d=lengthBytesUTF8(a)+1;b=Module._malloc(d);stringToUTF8(a,b,d);await Promise.resolve(js_set_clipboard(b));Module._free(b);b=null}catch(c){log_to_cpp("Error processing paste event: "+(c instanceof Error?c.message:String(c)),LOG_COLORS.E_COL_RED),null!==
b&&Module._free&&Module._free(b)}}}document.addEventListener("keydown",function(a){"Tab"===a.key&&a.preventDefault()});document.body.addEventListener("paste",on_document_paste);
var Module={locateFile:function(a){return"{{ url_for('static', filename='javascript/CANStudio/') }}"+a},onRuntimeInitialized:function(){try{js_on_resize=Module.cwrap("js_on_resize",null,["number","number"]),js_push_log=Module.cwrap("js_push_log",null,["number","number"]),js_set_dbc_file_name=Module.cwrap("js_set_dbc_file_name",null,["number"]),js_enable_keyinput=Module.cwrap("js_enable_keyinput",null,[]),js_disable_keyinput=Module.cwrap("js_disable_keyinput",null,[]),js_poll_events=Module.cwrap("js_poll_events",
"number",[]),js_set_clipboard=Module.cwrap("js_set_clipboard","number",["number"]),js_get_clipboard=Module.cwrap("js_get_clipboard","number",[]),js_push_can_message=Module.cwrap("js_push_can_message",null,"number number number number number number number number number number number number number number number number".split(" ")),js_push_can_message_history=Module.cwrap("js_push_can_message_history",null,"number number number number number number number number number number number number number number".split(" ")),
js_set_bus_on=Module.cwrap("js_set_bus_on",null,["number"]),js_get_bus_on=Module.cwrap("js_get_bus_on","number",[]),js_reset_signal_node_names=Module.cwrap("js_reset_signal_node_names",null,[]),js_push_node_name=Module.cwrap("js_push_node_name",null,["number","number"]),js_push_signal_name=Module.cwrap("js_push_signal_name",null,["number","number"]),js_push_node_signal=Module.cwrap("js_push_node_signal",null,"number number number number number number".split(" ")),js_push_serial_port=Module.cwrap("js_push_serial_port",
null,["number","number"]),js_clear_serial_ports=Module.cwrap("js_clear_serial_ports",null,[]),js_clear_graph_data=Module.cwrap("js_clear_graph_data",null,[]),js_clear_can_messages=Module.cwrap("js_clear_can_messages",null,[]),js_clear_can_history_list=Module.cwrap("js_clear_can_history_list",null,[]),js_set_can_error_register=Module.cwrap("js_set_can_error_register",null,["number"]),runtime_initialized=!0,js_set_bus_on&&js_set_bus_on(0),log_to_cpp(`CANStudio Version ${VERSION}.`,LOG_COLORS.E_COL_GREEN),
log_to_cpp("If you experience any issues rendering files clear your cache or Hold SHIFT and Refresh.",LOG_COLORS.E_COL_YELLOW),throttle_loop()}catch(a){console.error("Error during Emscripten cwrap initialization:",a),runtime_initialized=!1,log_to_cpp("Failed to initialize application components. Please refresh.",LOG_COLORS.E_COL_RED)}},canvas:(()=>{const a=document.getElementById("canvas");a?a.addEventListener("webglcontextlost",b=>{b.preventDefault();Swal.fire({title:"WebGL Context Lost",width:Math.max(workspace_width*
POPUP_WIDTH_PERCENT,POPUP_WIDTH_MAX),html:"Save your configuration and reload the page.<br>File->Save Config",icon:"error",allowOutsideClick:!1,confirmButtonColor:"#3085d6",confirmButtonText:"OK"})},!1):console.error("Canvas element with ID 'canvas' not found.");return a})(),totalDependencies:0,_malloc:a=>{throw Error("Module._malloc called before runtime initialization");},_free:a=>{throw Error("Module._free called before runtime initialization");},cwrap:(a,b,c,d)=>{throw Error("Module.cwrap called before runtime initialization");
}},workspace_width=1,workspace_height=1;const LOG_COLORS={E_COL_WHITE:0,E_COL_GREEN:1,E_COL_RED:2,E_COL_BLUE:3,E_COL_YELLOW:4};var runtime_initialized=!1;
js_set_can_error_register=js_clear_can_history_list=js_clear_can_messages=js_clear_graph_data=js_clear_serial_ports=js_push_serial_port=js_push_node_signal=js_push_signal_name=js_push_node_name=js_reset_signal_node_names=js_push_can_message_history=js_get_bus_on=js_set_bus_on=js_push_can_message=js_get_clipboard=js_set_clipboard=js_poll_events=js_disable_keyinput=js_enable_keyinput=js_set_dbc_file_name=js_push_log=js_on_resize=null;var is_processing=!1;
const FPS_DIVIDER_ARRAY=[2,1],FPS=Math.round(1/(1/(60/(FPS_DIVIDER_ARRAY[0]+1))*.5+1/(60/(FPS_DIVIDER_ARRAY[1]+1))*.5)+.5)>>0;var fps_indexer=0,fps_iterator=0,second_timer=0;function set_dbc_file_name(a){if(runtime_initialized&&js_set_dbc_file_name&&Module._malloc&&Module._free){const b=lengthBytesUTF8(a)+1,c=Module._malloc(b);stringToUTF8(a,c,b);js_set_dbc_file_name(c);Module._free(c)}else console.warn("set_dbc_file_name called before runtime initialized or required functions missing.")}
function show_about(){Swal.fire({title:"CANStudio",width:Math.max(workspace_width*POPUP_WIDTH_PERCENT,POPUP_WIDTH_MAX),html:`Created by Christian Nimako-Boateng Jr.<br>Version ${VERSION}`,icon:"info",confirmButtonColor:"#3085d6",confirmButtonText:"OK"})}
function confirm_clear_can_messages(){Swal.fire({title:"Are you sure?",width:Math.max(workspace_width*POPUP_WIDTH_PERCENT,POPUP_WIDTH_MAX),text:"All live CAN message data will be erased.",icon:"warning",showCancelButton:!0,confirmButtonColor:"#d33",cancelButtonColor:"#3085d6",confirmButtonText:"Yes, clear it!",cancelButtonText:"Cancel"}).then(a=>{a.isConfirmed&&js_clear_can_messages&&(js_clear_can_messages(),log_to_cpp("Live CAN messages cleared.",LOG_COLORS.E_COL_YELLOW))})}
function confirm_clear_message_history_list(){Swal.fire({title:"Are you sure?",width:Math.max(workspace_width*POPUP_WIDTH_PERCENT,POPUP_WIDTH_MAX),text:"All CAN message history data will be erased.",icon:"warning",showCancelButton:!0,confirmButtonColor:"#d33",cancelButtonColor:"#3085d6",confirmButtonText:"Yes, clear history!",cancelButtonText:"Cancel"}).then(a=>{a.isConfirmed&&js_clear_can_history_list&&(js_clear_can_history_list(),log_to_cpp("CAN message history cleared.",LOG_COLORS.E_COL_YELLOW))})}
function confirm_clear_graph_data(){Swal.fire({title:"Are you sure?",width:Math.max(workspace_width*POPUP_WIDTH_PERCENT,POPUP_WIDTH_MAX),text:"All graph data will be erased.",icon:"warning",showCancelButton:!0,confirmButtonColor:"#d33",cancelButtonColor:"#3085d6",confirmButtonText:"Yes, clear graph!",cancelButtonText:"Cancel"}).then(a=>{a.isConfirmed&&js_clear_graph_data&&(js_clear_graph_data(),log_to_cpp("Graph data cleared.",LOG_COLORS.E_COL_YELLOW))})}
function show_docs(){Swal.fire({title:"Open Documentation?",width:Math.max(workspace_width*POPUP_WIDTH_PERCENT,POPUP_WIDTH_MAX),text:"Unsaved configurations will be lost.",icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#aaa",confirmButtonText:"Yes, open docs",cancelButtonText:"Cancel"}).then(a=>{a.isConfirmed&&(window.location.href="")})}
function log_to_cpp(a,b){if(runtime_initialized&&js_push_log&&Module._malloc&&Module._free){if(null!==a&&void 0!==a){a=String(a).split("\n");let c,d,e;for(let f=0;f<a.length;f++){c=a[f].length>STRING_BUFFER_MAX-16?a[f].substring(0,STRING_BUFFER_MAX-16)+"...":a[f];try{e=lengthBytesUTF8(c)+1,d=Module._malloc(e),stringToUTF8(c,d,e),js_push_log(d,b),Module._free(d)}catch(k){console.error("Error during log_to_cpp memory allocation/free:",k);break}}}}else console.log(`%c ${a}`,`color: ${({0:"black",1:"green",
2:"red",3:"blue",4:"orange"})[b]||"black"}`)}function select_dbc_file(){document.getElementById("dbc_input_dialog").click()}function select_dfu_file(){document.getElementById("dfu_input_dialog").click()}var current_dfu_file_contents=null,current_dbc_file_contents=null;
function dfu_file_event(a){var b;a=a.target;if(null!==(b=null===a||void 0===a?void 0:a.files)&&void 0!==b&&b.length){var c=a.files[0];current_dfu_file_contents=null;if(c){const d=new FileReader;d.onload=e=>{var f;(null===(f=e.target)||void 0===f?0:f.result)?(current_dfu_file_contents=e.target.result,e={filename:c.name,content:current_dfu_file_contents},log_to_cpp(`Attempting to flash firmware: ${c.name}`,LOG_COLORS.E_COL_BLUE),perform_firmware_update(e)):log_to_cpp(`Error reading DFU file ${c.name}: Empty result.`,
LOG_COLORS.E_COL_RED)};d.onerror=()=>{var e;log_to_cpp(`Error reading DFU file ${c.name}: ${null===(e=d.error)||void 0===e?void 0:e.message}`,LOG_COLORS.E_COL_RED)};d.readAsArrayBuffer(c)}a&&(a.value="")}}
function dbc_file_event(a){var b;a=a.target;if(null!==(b=null===a||void 0===a?void 0:a.files)&&void 0!==b&&b.length){var c=a.files[0];current_dbc_file_contents=null;if(c){const d=new FileReader;d.onload=e=>{var f;(null===(f=e.target)||void 0===f?0:f.result)&&"string"===typeof e.target.result?(current_dbc_file_contents=e.target.result,e={filename:c.name,content:current_dbc_file_contents},log_to_cpp(`Processing DBC file: ${c.name}`,LOG_COLORS.E_COL_BLUE),perform_dbc_update(c.name,e)):log_to_cpp(`Error reading DBC file ${c.name}: Invalid or empty content.`,
LOG_COLORS.E_COL_RED)};d.onerror=()=>{var e;log_to_cpp(`Error reading DBC file ${c.name}: ${null===(e=d.error)||void 0===e?void 0:e.message}`,LOG_COLORS.E_COL_RED)};d.readAsText(c)}a&&(a.value="")}}window.addEventListener("resize",js_resize_cpp_canvas,!0);
function js_resize_cpp_canvas(){var a=document.getElementById("navigation_bar");const b=document.getElementById("id_right_panel"),c=document.getElementById("canvas");a&&b&&c&&(a.style.visibility="visible",a=a.offsetHeight,c.width=Math.max(window.innerWidth-b.offsetWidth,1),c.height=Math.max(window.innerHeight-a,1),b.style.height=`${window.innerHeight}px`,workspace_width=c.width,workspace_height=c.height,runtime_initialized&&js_on_resize&&js_on_resize(workspace_width,workspace_height))}
function show_toast(a){"function"===typeof Toastify?Toastify({text:a,duration:3E3,newWindow:!0,close:!0,gravity:"bottom",position:"center",stopOnFocus:!0,style:{background:"#3085d6",color:"#ffffff"}}).showToast():console.log("Toast:",a)}"undefined"!==typeof MicroModal&&MicroModal.init?MicroModal.init({}):console.warn("MicroModal not found or init function missing.");
function copy_to_clipboard(a){var b;const c=document.getElementById("clipboard");if(c){c.value=a;c.select();c.setSelectionRange(0,99999);try{if(null===(b=navigator.clipboard)||void 0===b?0:b.writeText)navigator.clipboard.writeText(c.value).then(()=>show_toast("Copied to clipboard.")).catch(d=>{log_to_cpp("Async clipboard copy failed: "+d,LOG_COLORS.E_COL_RED);show_toast("Could not copy to clipboard.")});else if(document.execCommand){if(!document.execCommand("copy"))throw Error("Fallback copy command failed.");
show_toast("Copied to clipboard (fallback).")}else throw Error("No copy command available.");}catch(d){log_to_cpp("Clipboard copy failed: "+(d instanceof Error?d.stack:String(d)),LOG_COLORS.E_COL_RED),show_toast("Could not copy to clipboard.")}finally{setTimeout(()=>{c&&(c.value="")},150)}}else log_to_cpp("Clipboard element not found.",LOG_COLORS.E_COL_RED),show_toast("Error: Clipboard element missing.")}
async function poll_events(){if(runtime_initialized&&js_poll_events&&!is_processing){is_processing=!0;try{await Promise.resolve(js_poll_events())}catch(a){log_to_cpp("Error during event polling: "+(a instanceof Error?a.message:String(a)),LOG_COLORS.E_COL_RED)}finally{is_processing=!1}}}
async function throttle_loop(){is_processing||(fps_iterator++>=FPS_DIVIDER_ARRAY[fps_indexer]&&(fps_indexer=1-fps_indexer,fps_iterator=0,await poll_events()),second_timer++,60<=second_timer&&(js_get_bus_on&&1===js_get_bus_on()&&connected_to_server&&request_device_errors(),second_timer=0));requestAnimationFrame(throttle_loop)}
document.addEventListener("DOMContentLoaded",()=>{const a=document.getElementById("dfu_input_dialog"),b=document.getElementById("dbc_input_dialog");a&&a.addEventListener("change",dfu_file_event);b&&b.addEventListener("change",dbc_file_event);js_resize_cpp_canvas()});

</script>


    <script async type="text/javascript"
        src="{{ url_for('static', filename='javascript/CANStudio/canstudio.js') }}"></script>
</body>

</html>