[{"data":1,"prerenderedAt":984},["ShallowReactive",2],{"docs-nav-docs_en":3,"docs-page-\u002Fen\u002Fdevice-sdk\u002Fengine-contract":367,"docs-surround-\u002Fen\u002Fdevice-sdk\u002Fengine-contract":981},[4],{"title":5,"path":6,"stem":7,"children":8},"En","\u002Fen","en",[9,13,41,58,76,103,157,171,190,211,238,283,303],{"title":10,"path":6,"stem":11,"navTitle":12},"QInsight Documentation","en\u002Findex","Overview",{"title":14,"navTitle":15,"path":16,"stem":17,"children":18,"page":40},"Getting Started",null,"\u002Fen\u002Fgetting-started","en\u002F01.getting-started",[19,23,27,31,36],{"title":20,"path":21,"stem":22,"navTitle":20},"What is QENEX Suite","\u002Fen\u002Fgetting-started\u002Fwhat-is-qenex-suite","en\u002F01.getting-started\u002F1.what-is-qenex-suite",{"title":24,"path":25,"stem":26,"navTitle":24},"What is QInsight","\u002Fen\u002Fgetting-started\u002Fwhat-is-qinsight","en\u002F01.getting-started\u002F2.what-is-qinsight",{"title":28,"path":29,"stem":30,"navTitle":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F01.getting-started\u002F3.installation",{"title":32,"path":33,"stem":34,"navTitle":35},"The QInsight user interface","\u002Fen\u002Fgetting-started\u002Fthe-qinsight-interface","en\u002F01.getting-started\u002F4.the-qinsight-interface","User interface",{"title":37,"path":38,"stem":39,"navTitle":37},"Licensing","\u002Fen\u002Fgetting-started\u002Flicensing","en\u002F01.getting-started\u002F5.licensing",false,{"title":42,"navTitle":15,"path":43,"stem":44,"children":45,"page":40},"First Project","\u002Fen\u002Ffirst-project","en\u002F02.first-project",[46,50,54],{"title":47,"path":48,"stem":49,"navTitle":47},"Create a project","\u002Fen\u002Ffirst-project\u002Fcreate-a-project","en\u002F02.first-project\u002F1.create-a-project",{"title":51,"path":52,"stem":53,"navTitle":51},"Project structure","\u002Fen\u002Ffirst-project\u002Fproject-structure","en\u002F02.first-project\u002F2.project-structure",{"title":55,"path":56,"stem":57,"navTitle":55},"Project password","\u002Fen\u002Ffirst-project\u002Fproject-password","en\u002F02.first-project\u002F3.project-password",{"title":59,"navTitle":15,"path":60,"stem":61,"children":62,"page":40},"Connecting a Device","\u002Fen\u002Fconnecting-a-device","en\u002F03.connecting-a-device",[63,67,71],{"title":64,"path":65,"stem":66,"navTitle":64},"Add a driver","\u002Fen\u002Fconnecting-a-device\u002Fadd-a-driver","en\u002F03.connecting-a-device\u002F1.add-a-driver",{"title":68,"path":69,"stem":70,"navTitle":68},"Add a protocol","\u002Fen\u002Fconnecting-a-device\u002Fadd-a-protocol","en\u002F03.connecting-a-device\u002F2.add-a-protocol",{"title":72,"path":73,"stem":74,"navTitle":75},"Link a driver and a protocol","\u002Fen\u002Fconnecting-a-device\u002Flink-driver-and-protocol","en\u002F03.connecting-a-device\u002F3.link-driver-and-protocol","Linking",{"title":77,"navTitle":15,"path":78,"stem":79,"children":80,"page":40},"Variables","\u002Fen\u002Fvariables","en\u002F04.variables",[81,85,90,94,99],{"title":82,"path":83,"stem":84,"navTitle":82},"What is a variable","\u002Fen\u002Fvariables\u002Fwhat-is-a-variable","en\u002F04.variables\u002F1.what-is-a-variable",{"title":86,"path":87,"stem":88,"navTitle":89},"Conversion and presentation","\u002Fen\u002Fvariables\u002Fconversion-and-presentation","en\u002F04.variables\u002F2.conversion-and-presentation","Conversion & presentation",{"title":91,"path":92,"stem":93,"navTitle":91},"Add a variable","\u002Fen\u002Fvariables\u002Fadd-a-variable","en\u002F04.variables\u002F3.add-a-variable",{"title":95,"path":96,"stem":97,"navTitle":98},"Matrix variable (array, curve, map)","\u002Fen\u002Fvariables\u002Fmatrix-variable","en\u002F04.variables\u002F4.matrix-variable","Matrix variable",{"title":100,"path":101,"stem":102,"navTitle":100},"Events","\u002Fen\u002Fvariables\u002Fevents","en\u002F04.variables\u002F5.events",{"title":104,"navTitle":15,"path":105,"stem":106,"children":107,"page":40},"Visualization","\u002Fen\u002Fvisualization","en\u002F05.visualization",[108,113,118,122,127,132,137,142,147,152],{"title":109,"path":110,"stem":111,"navTitle":112},"Create a workspace","\u002Fen\u002Fvisualization\u002Fcreate-a-workspace","en\u002F05.visualization\u002F1.create-a-workspace","Workspace",{"title":114,"path":115,"stem":116,"navTitle":117},"Writing values to the device","\u002Fen\u002Fvisualization\u002Fwrite-to-device","en\u002F05.visualization\u002F10.write-to-device","Writing to the device",{"title":119,"path":120,"stem":121,"navTitle":119},"Add a control","\u002Fen\u002Fvisualization\u002Fadd-a-control","en\u002F05.visualization\u002F2.add-a-control",{"title":123,"path":124,"stem":125,"navTitle":126},"Bind a control to a variable","\u002Fen\u002Fvisualization\u002Fbind-a-control","en\u002F05.visualization\u002F3.bind-a-control","Bind a control",{"title":128,"path":129,"stem":130,"navTitle":131},"Graph — signal time course","\u002Fen\u002Fvisualization\u002Fgraph-control","en\u002F05.visualization\u002F4.graph-control","Graph",{"title":133,"path":134,"stem":135,"navTitle":136},"XY Graph — signal versus signal","\u002Fen\u002Fvisualization\u002Fxy-graph-control","en\u002F05.visualization\u002F5.xy-graph-control","XY Graph",{"title":138,"path":139,"stem":140,"navTitle":141},"Gauge — instantaneous value indicator","\u002Fen\u002Fvisualization\u002Fgauge-control","en\u002F05.visualization\u002F6.gauge-control","Gauge",{"title":143,"path":144,"stem":145,"navTitle":146},"Single-Signal — a value with a caption","\u002Fen\u002Fvisualization\u002Fsignal-control","en\u002F05.visualization\u002F7.signal-control","Single-Signal",{"title":148,"path":149,"stem":150,"navTitle":151},"Watch Table — a table of variables","\u002Fen\u002Fvisualization\u002Fwatch-table-control","en\u002F05.visualization\u002F8.watch-table-control","Watch Table",{"title":153,"path":154,"stem":155,"navTitle":156},"Matrix control — maps and calibration","\u002Fen\u002Fvisualization\u002Fmatrix-control","en\u002F05.visualization\u002F9.matrix-control","Matrix control",{"title":158,"navTitle":15,"path":159,"stem":160,"children":161,"page":40},"Running and Monitoring","\u002Fen\u002Frunning","en\u002F06.running",[162,166],{"title":163,"path":164,"stem":165,"navTitle":163},"Start and stop","\u002Fen\u002Frunning\u002Fstart-and-stop","en\u002F06.running\u002F1.start-and-stop",{"title":167,"path":168,"stem":169,"navTitle":170},"Watching live data","\u002Fen\u002Frunning\u002Fwatching-live-data","en\u002F06.running\u002F2.watching-live-data","Live data",{"title":172,"navTitle":15,"path":173,"stem":174,"children":175,"page":40},"Logging and Replay","\u002Fen\u002Flogging-and-replay","en\u002F07.logging-and-replay",[176,180,185],{"title":177,"path":178,"stem":179,"navTitle":177},"Logging data","\u002Fen\u002Flogging-and-replay\u002Flogging-data","en\u002F07.logging-and-replay\u002F1.logging-data",{"title":181,"path":182,"stem":183,"navTitle":184},"Replaying a log","\u002Fen\u002Flogging-and-replay\u002Freplaying-a-log","en\u002F07.logging-and-replay\u002F2.replaying-a-log","Replay",{"title":186,"path":187,"stem":188,"navTitle":189},"Exporting data","\u002Fen\u002Flogging-and-replay\u002Fexporting-data","en\u002F07.logging-and-replay\u002F3.exporting-data","Export",{"title":191,"navTitle":15,"path":192,"stem":193,"children":194,"page":40},"Python Scripts","\u002Fen\u002Fpython-scripts","en\u002F08.python-scripts",[195,199,203,207],{"title":196,"path":197,"stem":198,"navTitle":12},"Scripts overview","\u002Fen\u002Fpython-scripts\u002Fscripts-overview","en\u002F08.python-scripts\u002F1.scripts-overview",{"title":200,"path":201,"stem":202,"navTitle":200},"Accessing variables","\u002Fen\u002Fpython-scripts\u002Faccessing-variables","en\u002F08.python-scripts\u002F2.accessing-variables",{"title":204,"path":205,"stem":206,"navTitle":204},"Example script","\u002Fen\u002Fpython-scripts\u002Fexample-script","en\u002F08.python-scripts\u002F3.example-script",{"title":208,"path":209,"stem":210,"navTitle":208},"CSV post-processing","\u002Fen\u002Fpython-scripts\u002Fcsv-post-processing","en\u002F08.python-scripts\u002F4.csv-post-processing",{"title":212,"navTitle":15,"path":213,"stem":214,"children":215,"page":40},"Custom extensions","\u002Fen\u002Fcustom-extensions","en\u002F09.custom-extensions",[216,220,224,228,233],{"title":217,"path":218,"stem":219,"navTitle":217},"Custom driver","\u002Fen\u002Fcustom-extensions\u002Fcustom-driver","en\u002F09.custom-extensions\u002F1.custom-driver",{"title":221,"path":222,"stem":223,"navTitle":221},"Custom protocol","\u002Fen\u002Fcustom-extensions\u002Fcustom-protocol","en\u002F09.custom-extensions\u002F2.custom-protocol",{"title":225,"path":226,"stem":227,"navTitle":225},"Custom Control","\u002Fen\u002Fcustom-extensions\u002Fcustom-control","en\u002F09.custom-extensions\u002F3.custom-control",{"title":229,"path":230,"stem":231,"navTitle":232},"Complete example — ISS position","\u002Fen\u002Fcustom-extensions\u002Fiss-example","en\u002F09.custom-extensions\u002F4.iss-example","Example ISS",{"title":234,"path":235,"stem":236,"navTitle":237},"Complete example — temperature sensor","\u002Fen\u002Fcustom-extensions\u002Ftemp-sensor-example","en\u002F09.custom-extensions\u002F5.temp-sensor-example","Example temp sensor",{"title":239,"navTitle":15,"path":240,"stem":241,"children":242,"page":40},"QFW SDK","\u002Fen\u002Fdevice-sdk","en\u002F10.device-sdk",[243,248,253,258,263,268,273,278],{"title":244,"path":245,"stem":246,"navTitle":247},"QFW SDK — introduction","\u002Fen\u002Fdevice-sdk\u002Fintroduction","en\u002F10.device-sdk\u002F1.introduction","Introduction",{"title":249,"path":250,"stem":251,"navTitle":252},"XCP in the QFW SDK","\u002Fen\u002Fdevice-sdk\u002Fxcp","en\u002F10.device-sdk\u002F2.xcp","XCP",{"title":254,"path":255,"stem":256,"navTitle":257},"Integration step by step: XCP on TCP with FreeRTOS + lwIP","\u002Fen\u002Fdevice-sdk\u002Fintegration-tcp","en\u002F10.device-sdk\u002F3.integration-tcp","Integration: XCP on TCP",{"title":259,"path":260,"stem":261,"navTitle":262},"XCP on classic CAN — what changes","\u002Fen\u002Fdevice-sdk\u002Fcan","en\u002F10.device-sdk\u002F4.can","XCP on classic CAN",{"title":264,"path":265,"stem":266,"navTitle":267},"Integration without an RTOS: XCP on TCP from the main loop","\u002Fen\u002Fdevice-sdk\u002Fbaremetal","en\u002F10.device-sdk\u002F5.baremetal","Integration without an RTOS",{"title":269,"path":270,"stem":271,"navTitle":272},"The engine contract","\u002Fen\u002Fdevice-sdk\u002Fengine-contract","en\u002F10.device-sdk\u002F6.engine-contract","Engine contract",{"title":274,"path":275,"stem":276,"navTitle":277},"Variable addresses for QInsight","\u002Fen\u002Fdevice-sdk\u002Fvariable-addresses","en\u002F10.device-sdk\u002F7.variable-addresses","Variable addresses",{"title":279,"path":280,"stem":281,"navTitle":282},"Troubleshooting the SDK integration","\u002Fen\u002Fdevice-sdk\u002Ftroubleshooting","en\u002F10.device-sdk\u002F8.troubleshooting","Troubleshooting",{"title":284,"navTitle":15,"path":285,"stem":286,"children":287,"page":40},"Reference","\u002Fen\u002Freference","en\u002F11.reference",[288,292,296,300],{"title":289,"path":290,"stem":291,"navTitle":289},"Drivers","\u002Fen\u002Freference\u002Fdrivers","en\u002F11.reference\u002F1.drivers",{"title":293,"path":294,"stem":295,"navTitle":293},"Protocols","\u002Fen\u002Freference\u002Fprotocols","en\u002F11.reference\u002F2.protocols",{"title":297,"path":298,"stem":299,"navTitle":297},"Controls","\u002Fen\u002Freference\u002Fcontrols","en\u002F11.reference\u002F3.controls",{"title":282,"path":301,"stem":302,"navTitle":282},"\u002Fen\u002Freference\u002Ftroubleshooting","en\u002F11.reference\u002F4.troubleshooting",{"title":304,"navTitle":15,"path":305,"stem":306,"children":307,"page":40},"Examples","\u002Fen\u002Fexamples","en\u002F12.examples",[308,312,317,322,327,331,335,339,343,347,352,357,362],{"title":309,"path":310,"stem":311,"navTitle":309},"Simulation: all signals","\u002Fen\u002Fexamples\u002Fsimulation-all-signals","en\u002F12.examples\u002F01.simulation-all-signals",{"title":313,"path":314,"stem":315,"navTitle":316},"Modbus RTU master over a serial line","\u002Fen\u002Fexamples\u002Fserial-modbus-master","en\u002F12.examples\u002F02.serial-modbus-master","Modbus RTU master",{"title":318,"path":319,"stem":320,"navTitle":321},"Modbus RTU slave with simulated sensors","\u002Fen\u002Fexamples\u002Fserial-modbus-slave","en\u002F12.examples\u002F03.serial-modbus-slave","Modbus RTU slave",{"title":323,"path":324,"stem":325,"navTitle":326},"Modbus TCP master over a TCP client","\u002Fen\u002Fexamples\u002Ftcp-client-modbus-master","en\u002F12.examples\u002F04.tcp-client-modbus-master","Modbus TCP master",{"title":328,"path":329,"stem":330,"navTitle":328},"Modbus TCP slave on the TCP Server","\u002Fen\u002Fexamples\u002Ftcp-server-modbus-slave","en\u002F12.examples\u002F05.tcp-server-modbus-slave",{"title":332,"path":333,"stem":334,"navTitle":332},"Bit field and a script","\u002Fen\u002Fexamples\u002Fbit-field-script","en\u002F12.examples\u002F08.bit-field-script",{"title":336,"path":337,"stem":338,"navTitle":336},"Two ECUs at once","\u002Fen\u002Fexamples\u002Ftwo-ecus","en\u002F12.examples\u002F09.two-ecus",{"title":340,"path":341,"stem":342,"navTitle":340},"ISS position live","\u002Fen\u002Fexamples\u002Fiss-live-tracking","en\u002F12.examples\u002F10.iss-live-tracking",{"title":344,"path":345,"stem":346,"navTitle":344},"Simulated thermometer","\u002Fen\u002Fexamples\u002Fsimul-temp-measure","en\u002F12.examples\u002F11.simul-temp-measure",{"title":348,"path":349,"stem":350,"navTitle":351},"JSON signals from a Python generator","\u002Fen\u002Fexamples\u002Fjson-signal-python","en\u002F12.examples\u002F12.json-signal-python","JSON signals from Python",{"title":353,"path":354,"stem":355,"navTitle":356},"Raw CAN frames from a Raspberry Pi","\u002Fen\u002Fexamples\u002Fraw-can-python","en\u002F12.examples\u002F13.raw-can-python","Raw CAN from a Raspberry Pi",{"title":358,"path":359,"stem":360,"navTitle":361},"XCP on TCP on a NUCLEO-H723ZG: measurement, stimulation and calibration maps","\u002Fen\u002Fexamples\u002Ftcp-client-xcp-nucleo-maps","en\u002F12.examples\u002F14.tcp-client-xcp-nucleo-maps","XCP on TCP on NUCLEO-H723ZG",{"title":363,"path":364,"stem":365,"navTitle":366},"XCP on CAN on a NUCLEO-H723ZG: measurement, stimulation and calibration maps","\u002Fen\u002Fexamples\u002Fcan-xcp-nucleo-maps","en\u002F12.examples\u002F15.can-xcp-nucleo-maps","XCP on CAN on NUCLEO-H723ZG",{"id":368,"title":269,"body":369,"description":975,"extension":976,"meta":977,"navTitle":272,"navigation":978,"path":270,"seo":979,"stem":271,"__hash__":980},"docs_en\u002Fen\u002F10.device-sdk\u002F6.engine-contract.md",{"type":370,"value":371,"toc":958},"minimark",[372,376,393,406,441,445,484,488,504,511,521,585,592,599,603,628,632,657,661,701,705,715,719,730,819,822,875,884,888,944,948,954],[373,374,269],"h1",{"id":375},"the-engine-contract",[377,378,379,380,384,385,388,389,392],"p",{},"Everything in this chapter is enforced by the engine's design, not by the\ncompiler. Getting it wrong shows up as rare corruption, not as an error\ncode. The shipped glues (",[381,382,383],"code",{},"glue\u002Ffreertos_lwip",", ",[381,386,387],{},"glue\u002Ffreertos_can",",\n",[381,390,391],{},"glue\u002Fbaremetal_lwip_raw",") honour all of it; keep it when you change\nthem or write your own.",[394,395,397,398,401,402,405],"h2",{"id":396},"contexts-rx-and-poll-belong-together","Contexts: ",[381,399,400],{},"rx"," and ",[381,403,404],{},"poll"," belong together",[377,407,408,411,412,415,416,419,420,424,425,428,429,432,433,436,437,440],{},[381,409,410],{},"qfw_xcp_rx()"," (or ",[381,413,414],{},"qfw_xcp_rx_can_frame()",") and ",[381,417,418],{},"qfw_xcp_poll()"," must run\nin ",[421,422,423],"strong",{},"the same context"," — one task — or you serialize them yourself. The\nFreeRTOS glues do both in their server task; the bare-metal glue in the\nmain loop (the lwIP ",[381,426,427],{},"recv"," callback and ",[381,430,431],{},"QfwXcpTcpRawGlue_Poll"," run in\none context). ",[381,434,435],{},"qfw_xcp_trigger_event()"," is\nthe only engine function designed to be called from elsewhere (your data\ntasks). ",[381,438,439],{},"qfw_xcp_create_event()"," is an init-time call.",[394,442,444],{"id":443},"critical-section-must-be-reentrant","Critical section — must be reentrant",[377,446,447,450,451,454,455,458,459,462,463,466,467,470,471,474,475,478,479,483],{},[381,448,449],{},"crit_enter"," \u002F ",[381,452,453],{},"crit_leave"," protect the engine's shared state (event list,\nDAQ tables, transmit queue). Engine code paths enter the section while\nalready holding it, so the pair ",[421,456,457],{},"must tolerate nesting",": with FreeRTOS a\n",[421,460,461],{},"recursive"," mutex (",[381,464,465],{},"xSemaphoreCreateRecursiveMutexStatic"," in the glue) —\na plain mutex deadlocks. The section is held briefly (queue push\u002Fpop, list\nupdates); keep your own work out of it. The ",[381,468,469],{},"log"," callback may be invoked\ninside it, so logging must not block. ",[381,472,473],{},"NULL"," for both callbacks is allowed\nonly when every engine call, including every ",[381,476,477],{},"qfw_xcp_trigger_event",",\ncomes from one single context — that is how the bare-metal glue works:\nthe engine runs in the main loop without a critical section and events\nare triggered from the same loop, never from an interrupt (see\n",[480,481,267],"a",{"href":482},"\u002Fdevice-sdk\u002Fbaremetal#context-model-critical-section-and-interrupts",").",[394,485,487],{"id":486},"triggering-events","Triggering events",[377,489,490,492,493,496,497,500,501,503],{},[381,491,477],{}," copies the DAQ variables of the event into the\ntransmit queue under the critical section, and applies STIM data before\nthat. From another ",[421,494,495],{},"task",": fine with the recursive mutex. From an\n",[421,498,499],{},"ISR",": not with a FreeRTOS mutex — trigger from the task the ISR wakes.\nThe transmission itself happens later, in the server task's ",[381,502,404],{},", never\nin the triggering task.",[394,505,507,510],{"id":506},"transmit-never-block-report-backpressure-honestly",[381,508,509],{},"transmit"," — never block, report backpressure honestly",[377,512,513,514,516,517,520],{},"Called from the ",[381,515,404],{}," context, outside the critical section, with one\nframed transport segment (TCP: one or more ",[381,518,519],{},"LEN+CTR"," messages back to\nback — write the bytes to the stream as they are). Rules:",[522,523,524,536,550,579],"ul",{},[525,526,527,528,531,532,535],"li",{},"return ",[381,529,530],{},"true"," when the transport accepted the ",[421,533,534],{},"whole"," segment;",[525,537,527,538,541,542,545,546,549],{},[381,539,540],{},"false"," when it accepted ",[421,543,544],{},"nothing"," (send buffer full) — the\nengine keeps the segment and retries it on the next poll;\n",[381,547,548],{},"qfw_xcp_is_backpressured()"," is true meanwhile;",[525,551,552,553,556,557,560,561,563,564,567,568,571,572,574,575,578],{},"a ",[421,554,555],{},"partial"," write is your problem: the remainder must follow or the\nTCP stream desynchronizes. The FreeRTOS glue retries a stalled\nremainder for up to 2 s (",[381,558,559],{},"GLUE_SEND_STALL_LIMIT_MS","), then shuts the\nsocket down and returns ",[381,562,530],{}," (segment dropped, the master sees the\nconnection go away, the server task recovers to ",[381,565,566],{},"accept","); the\nbare-metal glue never writes partially — it queues the whole segment\nwith one ",[381,569,570],{},"tcp_write"," or returns ",[381,573,540],{}," (which is why it requires\n",[381,576,577],{},"TCP_SND_BUF"," of at least one segment);",[525,580,581,582,584],{},"never block for long: a blocking send inside ",[381,583,509],{}," stalls command\nprocessing and STIM for everything else.",[394,586,588,591],{"id":587},"get_clock-monotonic-microseconds-64-bit",[381,589,590],{},"get_clock"," — monotonic, microseconds, 64 bit",[377,593,594,595,598],{},"Used for DAQ timestamps. Must be monotonic across the whole run, 1 µs\nresolution, never wrap — that is why the clock port widens the DWT counter\nto 64 bit and needs the periodic ",[381,596,597],{},"Clock64_Update"," from one writer.",[394,600,602],{"id":601},"transmit-queue-memory","Transmit queue memory",[377,604,605,606,609,610,415,613,616,617,384,620,623,624,627],{},"You provide the transmit queue: ",[381,607,608],{},"queue_mem"," (8-byte aligned, e.g. a\n",[381,611,612],{},"static uint64_t[]",[381,614,615],{},"queue_mem_size ≥ QFW_XCP_QUEUE_MEM_SIZE(2)",".\nSize it with ",[381,618,619],{},"QFW_XCP_QUEUE_MEM_SIZE(n)",[381,621,622],{},"n"," = number of 1480-byte\nsegments; one segment is always the open accumulation buffer, so 2 is the\nfloor. Both TCP glues use 6 (",[381,625,626],{},"GLUE_QUEUE_SEGMENTS","), the CAN glue 3. More segments = more DAQ data buffered across a slow\ntransport; an overflow under load is reported to the master as a\ntransport counter gap (TCP) or the overrun flag (CAN), never as corrupted\ndata.",[394,629,631],{"id":630},"log-callback","Log callback",[377,633,634,637,638,641,642,645,646,649,650,653,654,656],{},[381,635,636],{},"log(level, msg, user)"," receives one complete line without a newline. The\nlevels follow the XCPlite convention (not the XCP standard): 1 error,\n2 warning, 3 info, 4 trace, 5–6 debug; ",[381,639,640],{},"config.log_level"," gates them at\nruntime (0 = silent even with a callback). The engine itself never calls\n",[381,643,644],{},"printf","; the glue's ",[381,647,648],{},"GlueLog"," prints ",[381,651,652],{},"[XCP E|W|I|T|D] …"," through\n",[381,655,644],{},", which the example retargets to the ST-LINK virtual COM port. The\ncallback may run inside the critical section — a UART with a FIFO is\nfine, semihosting is not.",[394,658,660],{"id":659},"init-failure-reasons","Init failure reasons",[377,662,663,666,667,669,670,673,674,677,678,450,681,450,684,450,686,688,689,450,691,693,694,696,697,700],{},[381,664,665],{},"qfw_xcp_init"," returns ",[381,668,540],{}," (and ",[381,671,672],{},"QfwXcpGlue_Init"," passes it through)\nwhen: the config was not initialized with ",[381,675,676],{},"QFW_XCP_CONFIG_DEFAULT","\n(magic \u002F struct-size guard = header and engine sources do not belong\ntogether), ",[381,679,680],{},"project_name",[381,682,683],{},"epk",[381,685,509],{},[381,687,590],{}," missing, only\none of ",[381,690,449],{},[381,692,453],{}," set, ",[381,695,608],{}," missing or smaller\nthan ",[381,698,699],{},"QFW_XCP_QUEUE_MEM_SIZE(2)",", a second init, or the protocol layer\nrefusing the identity strings.",[394,702,704],{"id":703},"connection-state","Connection state",[377,706,707,710,711,714],{},[381,708,709],{},"qfw_xcp_is_connected()"," is true between a successful CONNECT and a\nDISCONNECT or ",[381,712,713],{},"qfw_xcp_on_transport_reset()",". The engine does not act on\na lost master beyond that: DAQ sampling stops, pending STIM data is no\nlonger applied, memory keeps its last contents. Any application reaction\n(return of stimulated variables to the internal model, safe outputs)\nbelongs into your task, polling this function. Both TCP glues turn a\nvanished master into a reset through keepalive (~11 s); the CAN glue can\nonly rely on a regular DISCONNECT or bus-off.",[394,716,718],{"id":717},"your-own-glue-another-stack-or-rtos","Your own glue (another stack or RTOS)",[377,720,721,722,725,726,729],{},"The engine does not care what drives it. The package ships two FreeRTOS\nglues (lwIP sockets, FDCAN) and one without an RTOS (lwIP RAW API); for\nanother TCP\u002FIP stack, another RTOS or another byte transport, write your\nown — ",[381,723,724],{},"glue\u002Ffreertos_lwip\u002Fxcp_sdk_glue.c"," (230 lines) is the reference,\n",[381,727,728],{},"glue\u002Fbaremetal_lwip_raw\u002Fxcp_tcp_raw_glue.c"," for an integration without\nthreads. What stays and what changes:",[731,732,733,746],"table",{},[734,735,736],"thead",{},[737,738,739,743],"tr",{},[740,741,742],"th",{},"Stays the same",[740,744,745],{},"Changes",[747,748,749,768,786,804],"tbody",{},[737,750,751,761],{},[752,753,754,757,758],"td",{},[381,755,756],{},"qfw_xcp.h",", the engine sources, ",[381,759,760],{},"cmake\u002Fqfw_xcp.cmake",[752,762,763,764,767],{},"the transport calls (",[381,765,766],{},"lwip_*"," → your stack)",[737,769,770,783],{},[752,771,772,773,384,775,384,777,384,780,782],{},"the four callbacks (",[381,774,509],{},[381,776,590],{},[381,778,779],{},"crit_enter\u002Fleave",[381,781,469],{},") and the queue memory",[752,784,785],{},"how the critical section is implemented (a recursive mutex of your RTOS)",[737,787,788,801],{},[752,789,790,791,450,794,450,797,800],{},"the three engine entries ",[381,792,793],{},"qfw_xcp_rx",[381,795,796],{},"qfw_xcp_poll",[381,798,799],{},"qfw_xcp_on_transport_reset"," and the contract above",[752,802,803],{},"how the server task is created and how it waits (a 1–10 ms receive timeout, or a queue with timeout), or a poll from the main loop without a task",[737,805,806,812],{},[752,807,808,809],{},"your integration file and the three calls in ",[381,810,811],{},"freertos.c",[752,813,814,815,818],{},"the glue's config struct and ",[381,816,817],{},"Qfw…Glue_Init"," name, if you want them different",[377,820,821],{},"Minimum body of a server task:",[823,824,829],"pre",{"className":825,"code":826,"language":827,"meta":828,"style":828},"language-c shiki shiki-themes github-light github-dark-default","for (;;) {\n    \u002F* on a new connection: qfw_xcp_on_transport_reset(); *\u002F\n    n = receive_with_timeout(buf, sizeof buf, 1 \u002F* ms *\u002F);\n    if (n > 0 && !qfw_xcp_rx(buf, n)) { reset_connection(); }   \u002F* false = stream desynchronized *\u002F\n    (void)qfw_xcp_poll();                                        \u002F* responses + DAQ out *\u002F\n    \u002F* connection lost: close, qfw_xcp_on_transport_reset(), back to accept *\u002F\n}\n","c","",[381,830,831,839,845,851,857,863,869],{"__ignoreMap":828},[832,833,836],"span",{"class":834,"line":835},"line",1,[832,837,838],{},"for (;;) {\n",[832,840,842],{"class":834,"line":841},2,[832,843,844],{},"    \u002F* on a new connection: qfw_xcp_on_transport_reset(); *\u002F\n",[832,846,848],{"class":834,"line":847},3,[832,849,850],{},"    n = receive_with_timeout(buf, sizeof buf, 1 \u002F* ms *\u002F);\n",[832,852,854],{"class":834,"line":853},4,[832,855,856],{},"    if (n > 0 && !qfw_xcp_rx(buf, n)) { reset_connection(); }   \u002F* false = stream desynchronized *\u002F\n",[832,858,860],{"class":834,"line":859},5,[832,861,862],{},"    (void)qfw_xcp_poll();                                        \u002F* responses + DAQ out *\u002F\n",[832,864,866],{"class":834,"line":865},6,[832,867,868],{},"    \u002F* connection lost: close, qfw_xcp_on_transport_reset(), back to accept *\u002F\n",[832,870,872],{"class":834,"line":871},7,[832,873,874],{},"}\n",[377,876,877,879,880,883],{},[381,878,713],{}," after every connect and disconnect is what\nmakes the master's next ",[381,881,882],{},"CONNECT"," start from a clean state.",[394,885,887],{"id":886},"the-version-string","The version string",[522,889,890,914,937],{},[525,891,892,666,895,898,899,901,902,905,906,909,910,913],{},[381,893,894],{},"qfw_xcp_version()",[381,896,897],{},"\"QFW-XCP \u003Csemver> (\u003Cgit>)\""," — the SDK\nversion and the git revision of the package the engine sources came\nfrom (a plain source build outside ",[381,900,760],{}," says ",[381,903,904],{},"(dev)",").\nThe same provenance is in ",[381,907,908],{},"include\u002Fqfw_xcp_version.h"," (",[381,911,912],{},"QFW_XCP_SDK_*",").\nQuote the string in every support request.",[525,915,916,909,919,921,922,926,927,930,931,388,934,483],{},[421,917,918],{},"EPK",[381,920,683],{}," in the glue config) is the XCP identification string of\n",[923,924,925],"em",{},"your"," software version, returned to the master by ",[381,928,929],{},"GET_ID",". QInsight\ndoes not evaluate it; it is informative. Recommended: your firmware\nversion, at most 31 characters, no spaces or colons (e.g. ",[381,932,933],{},"V100",[381,935,936],{},"fw-2.3.1",[525,938,939,940,943],{},"There is no license mode: the engine runs without a time limit and\nneeds no key. Your use of the sources is governed by the QENEX Software\nLicense Agreement in ",[381,941,942],{},"LICENSES\u002F",".",[394,945,947],{"id":946},"next","Next",[377,949,950,953],{},[480,951,274],{"href":952},"\u002Fdevice-sdk\u002Fvariable-addresses"," — from\nthe ELF to the QInsight project.",[955,956,957],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":828,"searchDepth":847,"depth":847,"links":959},[960,962,963,964,966,968,969,970,971,972,973,974],{"id":396,"depth":841,"text":961},"Contexts: rx and poll belong together",{"id":443,"depth":841,"text":444},{"id":486,"depth":841,"text":487},{"id":506,"depth":841,"text":965},"transmit — never block, report backpressure honestly",{"id":587,"depth":841,"text":967},"get_clock — monotonic, microseconds, 64 bit",{"id":601,"depth":841,"text":602},{"id":630,"depth":841,"text":631},{"id":659,"depth":841,"text":660},{"id":703,"depth":841,"text":704},{"id":717,"depth":841,"text":718},{"id":886,"depth":841,"text":887},{"id":946,"depth":841,"text":947},"The rules the engine relies on and every glue must keep — contexts, the reentrant critical section, event triggering, the transmit and clock callbacks, queue memory, logging, init failures and connection state; writing your own glue for another stack or RTOS; the version string.","md",{},true,{"title":269,"description":975},"TbeJnOjqFuTdNvKhZfoMlnUOVMXRkJTVRkG9qpNJcrU",[982,983],{"title":264,"path":265,"stem":266,"navTitle":267,"children":-1},{"title":274,"path":275,"stem":276,"navTitle":277,"children":-1},1791554568268]