[{"data":1,"prerenderedAt":1825},["ShallowReactive",2],{"docs-nav-docs_en":3,"docs-page-\u002Fen\u002Fdevice-sdk\u002Fbaremetal":367,"docs-surround-\u002Fen\u002Fdevice-sdk\u002Fbaremetal":1822},[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":264,"body":369,"description":1817,"extension":1818,"meta":1819,"navTitle":267,"navigation":848,"path":265,"seo":1820,"stem":266,"__hash__":1821},"docs_en\u002Fen\u002F10.device-sdk\u002F5.baremetal.md",{"type":370,"value":371,"toc":1807},"minimark",[372,376,417,422,570,574,591,808,812,827,944,961,967,986,1281,1334,1467,1471,1500,1534,1537,1617,1621,1624,1769,1779,1790,1794,1803],[373,374,264],"h1",{"id":375},"integration-without-an-rtos-xcp-on-tcp-from-the-main-loop",[377,378,379,380,384,385,388,389,393,394,397,398,401,402,406,407,411,412,416],"p",{},"The example ",[381,382,383],"code",{},"examples\u002Fnucleo_h723zg_baremetal"," is the same board and the\nsame demo content as ",[381,386,387],{},"examples\u002Fnucleo_h723zg",", built ",[390,391,392],"strong",{},"without FreeRTOS\nand without sockets",": lwIP runs in ",[381,395,396],{},"NO_SYS"," mode and the XCP server is\nthe glue template ",[381,399,400],{},"glue\u002Fbaremetal_lwip_raw\u002Fxcp_tcp_raw_glue.c",", driven\nfrom the main loop. Everything in this chapter is what changes compared\nto ",[403,404,257],"a",{"href":405},"\u002Fdevice-sdk\u002Fintegration-tcp","; the engine,\nthe ",[403,408,410],{"href":409},"\u002Fdevice-sdk\u002Fengine-contract","engine contract",", the variable rules\nand the ",[403,413,415],{"href":414},"\u002Fdevice-sdk\u002Fvariable-addresses","address tools"," are the same.",[418,419,421],"h2",{"id":420},"same-and-different","Same and different",[423,424,425,438],"table",{},[426,427,428],"thead",{},[429,430,431,435],"tr",{},[432,433,434],"th",{},"Same as with FreeRTOS",[432,436,437],{},"Different without an RTOS",[439,440,441,467,487,507,541],"tbody",{},[429,442,443,457],{},[444,445,446,447,450,451,450,454],"td",{},"the engine sources, ",[381,448,449],{},"qfw_xcp.h",", ",[381,452,453],{},"cmake\u002Fqfw_xcp.cmake",[381,455,456],{},"QFW_XCP_TRANSPORT=eth",[444,458,459,460,462,463,466],{},"the glue: ",[381,461,400],{}," instead of ",[381,464,465],{},"glue\u002Ffreertos_lwip\u002Fxcp_sdk_glue.c"," — lwIP RAW (callback) API, no task, no socket",[429,468,469,472],{},[444,470,471],{},"the clock port and the clock contract",[444,473,474,475,478,479,482,483,486],{},"the glue API: ",[381,476,477],{},"QfwXcpTcpRawGlue_Init(&config)"," once ",[390,480,481],{},"plus"," ",[381,484,485],{},"QfwXcpTcpRawGlue_Poll()"," on every pass of the main loop (the poll replaces the server task)",[429,488,489,500],{},[444,490,491,492,495,496,499],{},"identity, log level and port in the config struct (",[381,493,494],{},"tQfwXcpTcpRawGlueConfig"," has the same five fields as ",[381,497,498],{},"tQfwXcpGlueConfig",")",[444,501,502,503,506],{},"the context model: the transport on the main loop, the DAQ trigger from an interrupt — the glue gives the engine a ",[381,504,505],{},"PRIMASK"," critical section (see below)",[429,508,509,522],{},[444,510,511,514,515,450,518,521],{},[381,512,513],{},"qfw_xcp_create_event"," \u002F ",[381,516,517],{},"qfw_xcp_trigger_event",[381,519,520],{},"daqId"," in QInsight",[444,523,524,525,528,529,532,533,536,537,540],{},"where the calls live: ",[381,526,527],{},"main.c"," and ",[381,530,531],{},"stm32h7xx_it.c"," (",[381,534,535],{},"USER CODE"," sections) instead of ",[381,538,539],{},"freertos.c","; the DAQ event is triggered from the SysTick interrupt",[429,542,543,553],{},[444,544,545,546,549,550,499],{},"the lwIP corrections of the STM32H7 project (linker script, ",[381,547,548],{},"ethernetif.c",", see ",[403,551,282],{"href":552},"\u002Fdevice-sdk\u002Ftroubleshooting#regenerating-a-cubemx-project",[444,554,555,556,559,560,514,563,482,566,569],{},"the lwIP options: ",[381,557,558],{},"NO_SYS 1",", no socket options, but ",[381,561,562],{},"TCP_MSS",[381,564,565],{},"TCP_SND_BUF",[390,567,568],{},"must"," be raised (see below)",[418,571,573],{"id":572},"cubemx-lwip-without-an-rtos","CubeMX: lwIP without an RTOS",[377,575,576,579,580,528,583,586,587,590],{},[390,577,578],{},"Where:"," your ",[381,581,582],{},".ioc",[381,584,585],{},"LWIP\u002FTarget\u002Flwipopts.h",". ",[390,588,589],{},"What"," differs\nfrom the FreeRTOS project:",[592,593,594,613,623,651,791],"ol",{},[595,596,597,600,601,604,605,608,609,612],"li",{},[390,598,599],{},"Middleware → FREERTOS:"," not enabled. ",[390,602,603],{},"SYS → Timebase source:","\nSysTick (",[381,606,607],{},"HAL_GetTick"," drives the lwIP timers through ",[381,610,611],{},"sys_now"," and\nthe example's demo scheduler).",[595,614,615,618,619,622],{},[390,616,617],{},"Connectivity → ETH:"," as in the FreeRTOS project. The ETH interrupt\npriority is free (no FreeRTOS syscall limit); in the CubeMX driver\nwithout an RTOS the ISR only clears DMA flags — frames are read by\n",[381,620,621],{},"MX_LWIP_Process()"," from the main loop. Keep it that way (see the\ncontext model below).",[595,624,625,628,629,450,631,634,635,638,639,642,643,646,647,650],{},[390,626,627],{},"Middleware → LWIP:"," CubeMX generates ",[381,630,558],{},[381,632,633],{},"LWIP_NETCONN 0",",\n",[381,636,637],{},"LWIP_SOCKET 0"," automatically when no RTOS is enabled. DHCP off,\nstatic IP as in the FreeRTOS project; ",[381,640,641],{},"MEM_SIZE"," 16384 and\n",[381,644,645],{},"LWIP_RAM_HEAP_POINTER"," as in the example (the lwIP heap is where\n",[381,648,649],{},"tcp_write"," copies the XCP segments).",[595,652,653,662,663,666,667,670,671,750,753,754,757,758,763,764,766,767,450,770,773,774,777,778,514,780,782,783,786,787,790],{},[390,654,655,658,659],{},[381,656,657],{},"USER CODE BEGIN 1"," of ",[381,660,661],{},"lwipopts.h"," — the options the glue\ndepends on (the glue checks them at compile time: ",[381,664,665],{},"#error"," \u002F\n",[381,668,669],{},"_Static_assert","):",[423,672,673,686],{},[426,674,675],{},[429,676,677,680,683],{},[432,678,679],{},"Option",[432,681,682],{},"Value",[432,684,685],{},"Why",[439,687,688,701,717,729],{},[429,689,690,695,698],{},[444,691,692],{},[381,693,694],{},"LWIP_TCP_KEEPALIVE",[444,696,697],{},"1",[444,699,700],{},"per-connection keepalive timing (2 s idle, 3 probes every 1 s): a master that vanished beyond the board's own link is detected within ~5 s and the port is free again (a cable pulled at the board: link callback, see Connections below)",[429,702,703,708,710],{},[444,704,705],{},[381,706,707],{},"LWIP_NETIF_TX_SINGLE_PBUF",[444,709,697],{},[444,711,712,713,716],{},"one ",[381,714,715],{},"pbuf"," per transmitted segment — the STM32H7 driver has only 4 TX descriptors",[429,718,719,723,726],{},[444,720,721],{},[381,722,562],{},[444,724,725],{},"1460",[444,727,728],{},"the Ethernet maximum (1500 − 40). With the lwIP default 536 every full engine segment would be cut into three TCP packets",[429,730,731,735,741],{},[444,732,733],{},[381,734,565],{},[444,736,737,740],{},[381,738,739],{},"4 * TCP_MSS"," (5840)",[444,742,743,746,747,749],{},[390,744,745],{},"required."," The glue queues a whole engine segment (up to 1480 B) with one ",[381,748,649],{}," or not at all; the lwIP default (2 × 536 = 1072) could never accept a full segment and the engine would stay backpressured forever. Four segments in flight is a good default",[751,752],"br",{},"All four are ",[381,755,756],{},"#ifndef","-guarded and ",[390,759,760,761],{},"not in the ",[381,762,582],{}," — the CubeMX\nGUI keeps showing the defaults; the ",[381,765,535],{}," block survives\nregeneration. The values CubeMX emits for the default MSS\n(",[381,768,769],{},"TCP_SND_QUEUELEN 9",[381,771,772],{},"TCP_SNDLOWAT 1071",", …) still pass the lwIP\nsanity checks with these settings (",[381,775,776],{},"TCP_SND_QUEUELEN"," ≥\n2 × ",[381,779,565],{},[381,781,562],{}," = 8).\nWhy whole segments: the engine drops queued segments on ",[381,784,785],{},"DISCONNECT",",\non a new ",[381,788,789],{},"CONNECT"," and on a transport reset; a half-written segment\nwould desynchronize the byte stream. The FreeRTOS glue can afford\npartial writes because it may wait in its task; a main loop cannot.",[595,792,793,796,797,634,800,803,804,807],{},[390,794,795],{},"Generate code",", then apply the STM32H7 corrections exactly as for\nthe FreeRTOS project (linker script, ",[381,798,799],{},"ETH_RX_BUFFER_CNT",[381,801,802],{},"HAL_ETH_RxLinkCallback"," guard — ",[381,805,806],{},"REGEN-NOTES.md"," of the bare-metal\nexample).",[418,809,811],{"id":810},"cmake","CMake",[377,813,814,816,817,586,820,823,824,826],{},[390,815,578],{}," your root ",[381,818,819],{},"CMakeLists.txt",[390,821,822],{},"How"," (the bare-metal example's\n",[381,825,819],{},", only the SDK path differs):",[828,829,833],"pre",{"className":830,"code":831,"language":810,"meta":832,"style":832},"language-cmake shiki shiki-themes github-light github-dark-default","include(${SDK}\u002Fcmake\u002Fqfw_xcp.cmake)               # transport eth (default)\n\nadd_library(qfw_example STATIC\n    app\u002Fxcp_demo.c                                 # your application: event + cyclic work\n    app\u002Fdemo_map.c\n    app\u002Fdemo_signals.cpp\n    ${QFW_XCP_GLUE_BAREMETAL_LWIP_RAW_SOURCES}   # glue\u002Fbaremetal_lwip_raw\u002Fxcp_tcp_raw_glue.c\n    ${QFW_XCP_PORT_CLOCK_SOURCES}                # port\u002Fclock\u002Fclock64.c\n)\ntarget_include_directories(qfw_example PUBLIC\n    ${CMAKE_CURRENT_SOURCE_DIR}\u002Fapp\n    ${QFW_XCP_GLUE_BAREMETAL_LWIP_RAW_INCLUDE_DIRS}\n    ${QFW_XCP_PORT_CLOCK_INCLUDE_DIRS}\n)\ntarget_compile_definitions(qfw_example PUBLIC CLOCK_TICKS_PER_S=550000000UL)   # YOUR CPU clock\ntarget_link_libraries(qfw_example PUBLIC qfw::xcp PRIVATE stm32cubemx)\n\ntarget_link_libraries(${CMAKE_PROJECT_NAME} stm32cubemx qfw_example)\n","",[381,834,835,843,850,856,862,868,874,880,886,892,898,904,910,916,921,927,933,938],{"__ignoreMap":832},[836,837,840],"span",{"class":838,"line":839},"line",1,[836,841,842],{},"include(${SDK}\u002Fcmake\u002Fqfw_xcp.cmake)               # transport eth (default)\n",[836,844,846],{"class":838,"line":845},2,[836,847,849],{"emptyLinePlaceholder":848},true,"\n",[836,851,853],{"class":838,"line":852},3,[836,854,855],{},"add_library(qfw_example STATIC\n",[836,857,859],{"class":838,"line":858},4,[836,860,861],{},"    app\u002Fxcp_demo.c                                 # your application: event + cyclic work\n",[836,863,865],{"class":838,"line":864},5,[836,866,867],{},"    app\u002Fdemo_map.c\n",[836,869,871],{"class":838,"line":870},6,[836,872,873],{},"    app\u002Fdemo_signals.cpp\n",[836,875,877],{"class":838,"line":876},7,[836,878,879],{},"    ${QFW_XCP_GLUE_BAREMETAL_LWIP_RAW_SOURCES}   # glue\u002Fbaremetal_lwip_raw\u002Fxcp_tcp_raw_glue.c\n",[836,881,883],{"class":838,"line":882},8,[836,884,885],{},"    ${QFW_XCP_PORT_CLOCK_SOURCES}                # port\u002Fclock\u002Fclock64.c\n",[836,887,889],{"class":838,"line":888},9,[836,890,891],{},")\n",[836,893,895],{"class":838,"line":894},10,[836,896,897],{},"target_include_directories(qfw_example PUBLIC\n",[836,899,901],{"class":838,"line":900},11,[836,902,903],{},"    ${CMAKE_CURRENT_SOURCE_DIR}\u002Fapp\n",[836,905,907],{"class":838,"line":906},12,[836,908,909],{},"    ${QFW_XCP_GLUE_BAREMETAL_LWIP_RAW_INCLUDE_DIRS}\n",[836,911,913],{"class":838,"line":912},13,[836,914,915],{},"    ${QFW_XCP_PORT_CLOCK_INCLUDE_DIRS}\n",[836,917,919],{"class":838,"line":918},14,[836,920,891],{},[836,922,924],{"class":838,"line":923},15,[836,925,926],{},"target_compile_definitions(qfw_example PUBLIC CLOCK_TICKS_PER_S=550000000UL)   # YOUR CPU clock\n",[836,928,930],{"class":838,"line":929},16,[836,931,932],{},"target_link_libraries(qfw_example PUBLIC qfw::xcp PRIVATE stm32cubemx)\n",[836,934,936],{"class":838,"line":935},17,[836,937,849],{"emptyLinePlaceholder":848},[836,939,941],{"class":838,"line":940},18,[836,942,943],{},"target_link_libraries(${CMAKE_PROJECT_NAME} stm32cubemx qfw_example)\n",[377,945,946,947,634,950,953,954,956,957,960],{},"The glue needs the lwIP headers of your project (",[381,948,949],{},"lwip\u002Ftcp.h",[381,951,952],{},"lwip\u002Fpbuf.h",", your ",[381,955,661],{},"), which is why it sits in your target\nand links ",[381,958,959],{},"stm32cubemx"," privately, exactly like the FreeRTOS glue.",[418,962,964,966],{"id":963},"mainc-init-once-poll-forever",[381,965,527],{},": init once, poll forever",[377,968,969,482,971,450,974,976,977,980,981,983,984,670],{},[390,970,578],{},[381,972,973],{},"Core\u002FSrc\u002Fmain.c",[381,975,535],{}," sections only. ",[390,978,979],{},"What:"," a\nclock callback, the glue config, two init calls and the loop body.\n",[390,982,822],{}," (the example's ",[381,985,527],{},[828,987,991],{"className":988,"code":989,"language":990,"meta":832,"style":832},"language-c shiki shiki-themes github-light github-dark-default","\u002F* USER CODE BEGIN Includes *\u002F\n#include \"clock64.h\"\n#include \"qfw_xcp.h\"\n#include \"xcp_tcp_raw_glue.h\"\n#include \"xcp_demo.h\"\n\u002F* USER CODE END Includes *\u002F\n\n\u002F* USER CODE BEGIN 0 *\u002F\nstatic uint64_t XcpClockUs(void)      \u002F* engine clock contract: monotonic 64-bit microseconds *\u002F\n{\n  return Clock64_Get();\n}\n\u002F* USER CODE END 0 *\u002F\n\nint main(void)\n{\n  ...\n  MX_GPIO_Init();\n  MX_LWIP_Init();                     \u002F* generated: lwIP is up after this line (NO_SYS: no thread is started) *\u002F\n  \u002F* USER CODE BEGIN 2 *\u002F\n  Clock64_Init();\n  \u002F* USER CODE END 2 *\u002F\n  ... BSP LEDs, COM1 (printf) ...\n\n  \u002F* USER CODE BEGIN WHILE *\u002F\n  tQfwXcpTcpRawGlueConfig xcpConfig =\n  {\n    .project_name = \"baremetal\",      \u002F* shown to the master, \u003C= 31 chars *\u002F\n    .epk = \"V100\",                    \u002F* software version id *\u002F\n    .port = 5555U,\n    .log_level = 2U,                  \u002F* 1 error, 2 warning, 3 info (adds connection messages) *\u002F\n    .get_clock_us = XcpClockUs,\n  };\n  if (!QfwXcpTcpRawGlue_Init(&xcpConfig))   \u002F* engine init + listening pcb *\u002F\n  {\n    Error_Handler();\n  }\n  if (!QfwXcpDemo_Init())                   \u002F* qfw_xcp_create_event(\"demo10ms\", 10000) -> id 0, maps *\u002F\n  {\n    Error_Handler();\n  }\n\n  while (1)\n  {\n    MX_LWIP_Process();         \u002F* ETH RX + lwIP timers; the glue's TCP callbacks run in here -> qfw_xcp_rx *\u002F\n    Clock64_Update();          \u002F* single writer of the 64-bit clock, must run well below every 7.8 s *\u002F\n    QfwXcpTcpRawGlue_Poll();   \u002F* qfw_xcp_poll -> transmit callback -> tcp_write, then one tcp_output *\u002F\n    QfwXcpDemo_Poll();         \u002F* every 500 ms: map tick (the 10 ms signal step + DAQ event runs in SysTick, see below) *\u002F\n    \u002F* USER CODE END WHILE *\u002F\n    \u002F* USER CODE BEGIN 3 *\u002F\n  }\n  \u002F* USER CODE END 3 *\u002F\n}\n","c",[381,992,993,998,1003,1008,1013,1018,1023,1027,1032,1037,1042,1047,1052,1057,1061,1066,1070,1075,1080,1086,1092,1098,1104,1110,1115,1121,1127,1133,1139,1145,1151,1157,1163,1169,1175,1180,1186,1192,1198,1203,1208,1213,1218,1224,1229,1235,1241,1247,1253,1259,1265,1270,1276],{"__ignoreMap":832},[836,994,995],{"class":838,"line":839},[836,996,997],{},"\u002F* USER CODE BEGIN Includes *\u002F\n",[836,999,1000],{"class":838,"line":845},[836,1001,1002],{},"#include \"clock64.h\"\n",[836,1004,1005],{"class":838,"line":852},[836,1006,1007],{},"#include \"qfw_xcp.h\"\n",[836,1009,1010],{"class":838,"line":858},[836,1011,1012],{},"#include \"xcp_tcp_raw_glue.h\"\n",[836,1014,1015],{"class":838,"line":864},[836,1016,1017],{},"#include \"xcp_demo.h\"\n",[836,1019,1020],{"class":838,"line":870},[836,1021,1022],{},"\u002F* USER CODE END Includes *\u002F\n",[836,1024,1025],{"class":838,"line":876},[836,1026,849],{"emptyLinePlaceholder":848},[836,1028,1029],{"class":838,"line":882},[836,1030,1031],{},"\u002F* USER CODE BEGIN 0 *\u002F\n",[836,1033,1034],{"class":838,"line":888},[836,1035,1036],{},"static uint64_t XcpClockUs(void)      \u002F* engine clock contract: monotonic 64-bit microseconds *\u002F\n",[836,1038,1039],{"class":838,"line":894},[836,1040,1041],{},"{\n",[836,1043,1044],{"class":838,"line":900},[836,1045,1046],{},"  return Clock64_Get();\n",[836,1048,1049],{"class":838,"line":906},[836,1050,1051],{},"}\n",[836,1053,1054],{"class":838,"line":912},[836,1055,1056],{},"\u002F* USER CODE END 0 *\u002F\n",[836,1058,1059],{"class":838,"line":918},[836,1060,849],{"emptyLinePlaceholder":848},[836,1062,1063],{"class":838,"line":923},[836,1064,1065],{},"int main(void)\n",[836,1067,1068],{"class":838,"line":929},[836,1069,1041],{},[836,1071,1072],{"class":838,"line":935},[836,1073,1074],{},"  ...\n",[836,1076,1077],{"class":838,"line":940},[836,1078,1079],{},"  MX_GPIO_Init();\n",[836,1081,1083],{"class":838,"line":1082},19,[836,1084,1085],{},"  MX_LWIP_Init();                     \u002F* generated: lwIP is up after this line (NO_SYS: no thread is started) *\u002F\n",[836,1087,1089],{"class":838,"line":1088},20,[836,1090,1091],{},"  \u002F* USER CODE BEGIN 2 *\u002F\n",[836,1093,1095],{"class":838,"line":1094},21,[836,1096,1097],{},"  Clock64_Init();\n",[836,1099,1101],{"class":838,"line":1100},22,[836,1102,1103],{},"  \u002F* USER CODE END 2 *\u002F\n",[836,1105,1107],{"class":838,"line":1106},23,[836,1108,1109],{},"  ... BSP LEDs, COM1 (printf) ...\n",[836,1111,1113],{"class":838,"line":1112},24,[836,1114,849],{"emptyLinePlaceholder":848},[836,1116,1118],{"class":838,"line":1117},25,[836,1119,1120],{},"  \u002F* USER CODE BEGIN WHILE *\u002F\n",[836,1122,1124],{"class":838,"line":1123},26,[836,1125,1126],{},"  tQfwXcpTcpRawGlueConfig xcpConfig =\n",[836,1128,1130],{"class":838,"line":1129},27,[836,1131,1132],{},"  {\n",[836,1134,1136],{"class":838,"line":1135},28,[836,1137,1138],{},"    .project_name = \"baremetal\",      \u002F* shown to the master, \u003C= 31 chars *\u002F\n",[836,1140,1142],{"class":838,"line":1141},29,[836,1143,1144],{},"    .epk = \"V100\",                    \u002F* software version id *\u002F\n",[836,1146,1148],{"class":838,"line":1147},30,[836,1149,1150],{},"    .port = 5555U,\n",[836,1152,1154],{"class":838,"line":1153},31,[836,1155,1156],{},"    .log_level = 2U,                  \u002F* 1 error, 2 warning, 3 info (adds connection messages) *\u002F\n",[836,1158,1160],{"class":838,"line":1159},32,[836,1161,1162],{},"    .get_clock_us = XcpClockUs,\n",[836,1164,1166],{"class":838,"line":1165},33,[836,1167,1168],{},"  };\n",[836,1170,1172],{"class":838,"line":1171},34,[836,1173,1174],{},"  if (!QfwXcpTcpRawGlue_Init(&xcpConfig))   \u002F* engine init + listening pcb *\u002F\n",[836,1176,1178],{"class":838,"line":1177},35,[836,1179,1132],{},[836,1181,1183],{"class":838,"line":1182},36,[836,1184,1185],{},"    Error_Handler();\n",[836,1187,1189],{"class":838,"line":1188},37,[836,1190,1191],{},"  }\n",[836,1193,1195],{"class":838,"line":1194},38,[836,1196,1197],{},"  if (!QfwXcpDemo_Init())                   \u002F* qfw_xcp_create_event(\"demo10ms\", 10000) -> id 0, maps *\u002F\n",[836,1199,1201],{"class":838,"line":1200},39,[836,1202,1132],{},[836,1204,1206],{"class":838,"line":1205},40,[836,1207,1185],{},[836,1209,1211],{"class":838,"line":1210},41,[836,1212,1191],{},[836,1214,1216],{"class":838,"line":1215},42,[836,1217,849],{"emptyLinePlaceholder":848},[836,1219,1221],{"class":838,"line":1220},43,[836,1222,1223],{},"  while (1)\n",[836,1225,1227],{"class":838,"line":1226},44,[836,1228,1132],{},[836,1230,1232],{"class":838,"line":1231},45,[836,1233,1234],{},"    MX_LWIP_Process();         \u002F* ETH RX + lwIP timers; the glue's TCP callbacks run in here -> qfw_xcp_rx *\u002F\n",[836,1236,1238],{"class":838,"line":1237},46,[836,1239,1240],{},"    Clock64_Update();          \u002F* single writer of the 64-bit clock, must run well below every 7.8 s *\u002F\n",[836,1242,1244],{"class":838,"line":1243},47,[836,1245,1246],{},"    QfwXcpTcpRawGlue_Poll();   \u002F* qfw_xcp_poll -> transmit callback -> tcp_write, then one tcp_output *\u002F\n",[836,1248,1250],{"class":838,"line":1249},48,[836,1251,1252],{},"    QfwXcpDemo_Poll();         \u002F* every 500 ms: map tick (the 10 ms signal step + DAQ event runs in SysTick, see below) *\u002F\n",[836,1254,1256],{"class":838,"line":1255},49,[836,1257,1258],{},"    \u002F* USER CODE END WHILE *\u002F\n",[836,1260,1262],{"class":838,"line":1261},50,[836,1263,1264],{},"    \u002F* USER CODE BEGIN 3 *\u002F\n",[836,1266,1268],{"class":838,"line":1267},51,[836,1269,1191],{},[836,1271,1273],{"class":838,"line":1272},52,[836,1274,1275],{},"  \u002F* USER CODE END 3 *\u002F\n",[836,1277,1279],{"class":838,"line":1278},53,[836,1280,1051],{},[377,1282,1283,482,1286,1289,1290,1293,1294,1297,1298,1301,1302,1305,1306,532,1309,1312,1313,1315,1316,1319,1320,1323,1324,1327,1328,1330,1331,1333],{},[390,1284,1285],{},"Why this order:",[381,1287,1288],{},"QfwXcpTcpRawGlue_Init"," must run after\n",[381,1291,1292],{},"MX_LWIP_Init()"," (it creates the listening pcb) and, if you want to see\nits start-up message, after the COM port is initialized — that is why it\nis in ",[381,1295,1296],{},"USER CODE WHILE"," right before the loop and not in ",[381,1299,1300],{},"USER CODE 2",".\nInside the loop ",[381,1303,1304],{},"MX_LWIP_Process"," comes first (received commands are\nexecuted and their responses queued), then the poll transmits them in\nthe same pass. ",[381,1307,1308],{},"QfwXcpDemo_Poll",[381,1310,1311],{},"app\u002Fxcp_demo.c",") is the application's\ncyclic work: it schedules by ",[381,1314,607],{}," with wrap-safe deadlines, so a\nlate pass does not burst to catch up — copy its ",[381,1317,1318],{},"DemoDue"," pattern for\nyour own loop cycles. The fast cycle (signal step + DAQ event every\n10 ms) runs in ",[381,1321,1322],{},"QfwXcpDemo_Tick1ms"," from the SysTick interrupt\n(",[381,1325,1326],{},"USER CODE SysTick_IRQn 1"," in ",[381,1329,531],{},"), see the context model\nbelow. Two more ",[381,1332,535],{}," sections belong to the integration:",[828,1335,1337],{"className":988,"code":1336,"language":990,"meta":832,"style":832},"\u002F* Core\u002FSrc\u002Fstm32h7xx_it.c *\u002F\n\u002F* USER CODE BEGIN Includes *\u002F\n#include \"xcp_demo.h\"\n\u002F* USER CODE END Includes *\u002F\nvoid SysTick_Handler(void)\n{\n  HAL_IncTick();\n  \u002F* USER CODE BEGIN SysTick_IRQn 1 *\u002F\n  QfwXcpDemo_Tick1ms();      \u002F* every 10 ms: generators + qfw_xcp_trigger_event, in interrupt context *\u002F\n  \u002F* USER CODE END SysTick_IRQn 1 *\u002F\n}\n\n\u002F* LWIP\u002FApp\u002Flwip.c - link state to the glue *\u002F\n\u002F* USER CODE BEGIN 0 *\u002F\n#include \"xcp_tcp_raw_glue.h\"\n\u002F* USER CODE END 0 *\u002F\nstatic void ethernet_link_status_updated(struct netif *netif)\n{\n  if (netif_is_up(netif)) {\n\u002F* USER CODE BEGIN 5 *\u002F\n    QfwXcpTcpRawGlue_OnLinkChange(true);\n\u002F* USER CODE END 5 *\u002F\n  } else {\n\u002F* USER CODE BEGIN 6 *\u002F\n    QfwXcpTcpRawGlue_OnLinkChange(false);   \u002F* master unreachable: drop the connection now *\u002F\n\u002F* USER CODE END 6 *\u002F\n  }\n}\n",[381,1338,1339,1344,1348,1352,1356,1361,1365,1370,1375,1380,1385,1389,1393,1398,1402,1406,1410,1415,1419,1424,1429,1434,1439,1444,1449,1454,1459,1463],{"__ignoreMap":832},[836,1340,1341],{"class":838,"line":839},[836,1342,1343],{},"\u002F* Core\u002FSrc\u002Fstm32h7xx_it.c *\u002F\n",[836,1345,1346],{"class":838,"line":845},[836,1347,997],{},[836,1349,1350],{"class":838,"line":852},[836,1351,1017],{},[836,1353,1354],{"class":838,"line":858},[836,1355,1022],{},[836,1357,1358],{"class":838,"line":864},[836,1359,1360],{},"void SysTick_Handler(void)\n",[836,1362,1363],{"class":838,"line":870},[836,1364,1041],{},[836,1366,1367],{"class":838,"line":876},[836,1368,1369],{},"  HAL_IncTick();\n",[836,1371,1372],{"class":838,"line":882},[836,1373,1374],{},"  \u002F* USER CODE BEGIN SysTick_IRQn 1 *\u002F\n",[836,1376,1377],{"class":838,"line":888},[836,1378,1379],{},"  QfwXcpDemo_Tick1ms();      \u002F* every 10 ms: generators + qfw_xcp_trigger_event, in interrupt context *\u002F\n",[836,1381,1382],{"class":838,"line":894},[836,1383,1384],{},"  \u002F* USER CODE END SysTick_IRQn 1 *\u002F\n",[836,1386,1387],{"class":838,"line":900},[836,1388,1051],{},[836,1390,1391],{"class":838,"line":906},[836,1392,849],{"emptyLinePlaceholder":848},[836,1394,1395],{"class":838,"line":912},[836,1396,1397],{},"\u002F* LWIP\u002FApp\u002Flwip.c - link state to the glue *\u002F\n",[836,1399,1400],{"class":838,"line":918},[836,1401,1031],{},[836,1403,1404],{"class":838,"line":923},[836,1405,1012],{},[836,1407,1408],{"class":838,"line":929},[836,1409,1056],{},[836,1411,1412],{"class":838,"line":935},[836,1413,1414],{},"static void ethernet_link_status_updated(struct netif *netif)\n",[836,1416,1417],{"class":838,"line":940},[836,1418,1041],{},[836,1420,1421],{"class":838,"line":1082},[836,1422,1423],{},"  if (netif_is_up(netif)) {\n",[836,1425,1426],{"class":838,"line":1088},[836,1427,1428],{},"\u002F* USER CODE BEGIN 5 *\u002F\n",[836,1430,1431],{"class":838,"line":1094},[836,1432,1433],{},"    QfwXcpTcpRawGlue_OnLinkChange(true);\n",[836,1435,1436],{"class":838,"line":1100},[836,1437,1438],{},"\u002F* USER CODE END 5 *\u002F\n",[836,1440,1441],{"class":838,"line":1106},[836,1442,1443],{},"  } else {\n",[836,1445,1446],{"class":838,"line":1112},[836,1447,1448],{},"\u002F* USER CODE BEGIN 6 *\u002F\n",[836,1450,1451],{"class":838,"line":1117},[836,1452,1453],{},"    QfwXcpTcpRawGlue_OnLinkChange(false);   \u002F* master unreachable: drop the connection now *\u002F\n",[836,1455,1456],{"class":838,"line":1123},[836,1457,1458],{},"\u002F* USER CODE END 6 *\u002F\n",[836,1460,1461],{"class":838,"line":1129},[836,1462,1191],{},[836,1464,1465],{"class":838,"line":1135},[836,1466,1051],{},[418,1468,1470],{"id":1469},"context-model-critical-section-and-interrupts","Context model, critical section and interrupts",[377,1472,1473,1474,1476,1477,1479,1480,1483,1484,1487,1488,1491,1492,1495,1496,1499],{},"The transport runs in one context: the main loop. lwIP in ",[381,1475,396],{},"\nmode runs only inside ",[381,1478,621],{},", so the glue's ",[381,1481,1482],{},"recv"," callback\n(→ ",[381,1485,1486],{},"qfw_xcp_rx",") and ",[381,1489,1490],{},"QfwXcpTcpRawGlue_Poll"," (→ ",[381,1493,1494],{},"qfw_xcp_poll",") share\nit and the rule of the\n",[403,1497,410],{"href":1498},"\u002Fdevice-sdk\u002Fengine-contract#contexts-rx-and-poll-belong-together","\nis met by construction.",[377,1501,1502,1503,1508,1509,1513,1514,482,1516,1519,1520,1523,1524,1527,1528,1530,1531,1533],{},"Measurement comes from a second context. The glue registers a\n",[390,1504,1505,1507],{},[381,1506,505],{}," critical section"," (save PRIMASK, disable interrupts,\nrestore on the outermost leave, with a nesting counter because the\nengine nests the section — see\n",[403,1510,1512],{"href":1511},"\u002Fdevice-sdk\u002Fengine-contract#critical-section-must-be-reentrant","Critical section",").\nWith it, ",[381,1515,517],{},[390,1517,1518],{},"may be called from an interrupt"," —\nthe example triggers its ",[381,1521,1522],{},"demo10ms"," event from ",[381,1525,1526],{},"SysTick_Handler","\n(",[381,1529,1322],{},", every 10 ms), the way a control loop in a timer\nISR would: the DAQ samples and the STIM writes of that event happen\ninside the ISR, synchronously with the cycle, and the sampling period\ndoes not depend on how long a main-loop pass takes. The ISR only copies\ninto the engine queue; the bytes leave the board in the next\n",[381,1532,1490],{},".",[377,1535,1536],{},"Consequences you must keep:",[1538,1539,1540,1553,1566,1572,1590,1603],"ul",{},[595,1541,1542,482,1548,634,1550,1552],{},[390,1543,1544,1545,1547],{},"Only ",[381,1546,517],{}," from an interrupt.",[381,1549,1486],{},[381,1551,1494],{}," and every other engine call stay in the main loop.",[595,1554,1555,1558,1559,1562,1563,1533],{},[390,1556,1557],{},"Nothing of lwIP from an interrupt."," The CubeMX driver without an\nRTOS already behaves this way (the ETH ISR only clears flags); do not\nadd ",[381,1560,1561],{},"ethernetif_input"," or lwIP calls to ",[381,1564,1565],{},"HAL_ETH_RxCpltCallback",[595,1567,1568,1571],{},[390,1569,1570],{},"Keep the ISR work short."," The section disables all interrupts for\nthe duration of the queue bookkeeping and the DAQ copy of one event\n(microseconds); a trigger of a large event list inside a high-rate ISR\nadds that much interrupt latency to everything else.",[595,1573,1574,1577,1578,1581,1582,1585,1586,1589],{},[390,1575,1576],{},"Logging from the ISR is suppressed."," An engine message raised\ninside the trigger is counted, not printed (",[381,1579,1580],{},"printf"," blocks, and it\nwould run with interrupts disabled); the count is reported from the\nnext ",[381,1583,1584],{},"Poll"," as ",[381,1587,1588],{},"[XCP W] n engine log line(s) raised in interrupt context not printed",". In a measurement run that line must not appear.",[595,1591,1592,1593,514,1596,666,1599,1602],{},"The glue is written for Cortex-M (",[381,1594,1595],{},"__get_PRIMASK",[381,1597,1598],{},"__disable_irq",[381,1600,1601],{},"__set_PRIMASK"," from CMSIS). On another core replace the two functions\nby the equivalent global interrupt mask with the same nesting\nbehaviour.",[595,1604,1605,1606,1608,1609,1612,1613,1616],{},"The loop pass is the poll cadence. Long work in one pass delays\nresponses and DAQ transmission: ",[381,1607,1580],{}," at ",[381,1610,1611],{},"log_level"," 3 costs ≈ 4 ms\nper line on the ST-LINK VCP, and ",[381,1614,1615],{},"HAL_ETH_Transmit"," of the CubeMX\ndriver without an RTOS blocks until the DMA has sent the frame\n(≈ 0.12 ms per full frame at 100 Mbit\u002Fs).",[418,1618,1620],{"id":1619},"connections-what-the-glue-does-and-what-you-will-see","Connections: what the glue does and what you will see",[377,1622,1623],{},"The policy is the same as the FreeRTOS glue's, implemented on the RAW\nAPI:",[423,1625,1626,1636],{},[426,1627,1628],{},[429,1629,1630,1633],{},[432,1631,1632],{},"Situation",[432,1634,1635],{},"What happens",[439,1637,1638,1657,1691,1699,1707,1721,1741],{},[429,1639,1640,1643],{},[444,1641,1642],{},"master connects",[444,1644,1645,1648,1649,1652,1653,1656],{},[381,1646,1647],{},"accept"," callback: keepalive set (2 s \u002F 1 s \u002F 3), ",[381,1650,1651],{},"qfw_xcp_on_transport_reset()",", the pcb becomes the one connection; ",[381,1654,1655],{},"[XCP I] master connected from ip:port"," at level 3",[429,1658,1659,1666],{},[444,1660,1661,1662,1665],{},"a ",[390,1663,1664],{},"second"," client connects while a master is connected",[444,1667,1668,1669,1672,1673,1327,1676,1678,1679,1682,1683,1686,1687,1690],{},"refused ",[390,1670,1671],{},"at once"," with RST (",[381,1674,1675],{},"tcp_abort",[381,1677,1647],{},"); the running session is not disturbed. ",[381,1680,1681],{},"[XCP W] refused a second connection from ip:port (master already connected)",". A second QInsight shows ",[381,1684,1685],{},"connected"," → ",[381,1688,1689],{},"forcibly closed"," once per second and connects as soon as the first session ends",[429,1692,1693,1696],{},[444,1694,1695],{},"master closes (FIN) or dies (RST)",[444,1697,1698],{},"the glue aborts (RST) — every close is an abort, so the pcb and all queued segments are freed at once; engine reset; back to waiting for a master",[429,1700,1701,1704],{},[444,1702,1703],{},"master vanishes silently beyond the board's link (cable pulled at a switch, PC off or frozen)",[444,1705,1706],{},"keepalive aborts the connection ~5 s after the last segment received; until then a reconnecting master is refused like a second client — QInsight's driver retries every second and gets in after the timeout",[429,1708,1709,1715],{},[444,1710,1711,1712,1714],{},"the byte stream desynchronizes (",[381,1713,1486],{}," returns false)",[444,1716,1717,1718],{},"the connection is aborted (RST), ",[381,1719,1720],{},"[XCP E] XCP stream desynchronized",[429,1722,1723,1731],{},[444,1724,1725,1726,1686,1728,499],{},"the lwIP send queue or heap is full (",[381,1727,649],{},[381,1729,1730],{},"ERR_MEM",[444,1732,1733,1736,1737,1740],{},[390,1734,1735],{},"backpressure",": the transmit callback returns false, the engine keeps the segment and offers the same bytes on the next poll; ",[381,1738,1739],{},"qfw_xcp_is_backpressured()"," is true meanwhile. A master that stays alive but stops reading keeps the glue in backpressure until it reconnects",[429,1742,1743,1746],{},[444,1744,1745],{},"link down at the board (cable pulled at the board)",[444,1747,1748,1749,1327,1752,1686,1755,1758,1759,532,1761,1764,1765,1768],{},"the link callback (",[381,1750,1751],{},"ethernet_link_status_updated",[381,1753,1754],{},"lwip.c",[381,1756,1757],{},"QfwXcpTcpRawGlue_OnLinkChange(false)",") makes the glue drop the master connection in the next ",[381,1760,1584],{},[381,1762,1763],{},"[XCP I] connection closed (link down), waiting for a master"," at level 3). When the link is back the master's reconnect is accepted at once; with ",[381,1766,1767],{},"connectionTimeoutMs"," 1500 in QInsight the measurement is back about 3.5 s after the cable (link negotiation plus one timed-out attempt that started too early)",[377,1770,1771,1772,1775,1776,1533],{},"Nagle's algorithm is on (the TCP default, as in the FreeRTOS glue): a\nsmall packet may wait for the master's delayed ACK (≈ 200 ms on Windows)\n— DAQ timestamps are not affected, only the arrival of slow streams is\nbatched. ",[381,1773,1774],{},"GLUE_TCP_NODELAY"," at the top of the glue switches to\n",[381,1777,1778],{},"TCP_NODELAY",[377,1780,1781,1782,1785,1786,1533],{},"The QInsight example project for this image\n(",[381,1783,1784],{},"Qenex_TcpClient_XCP_NucleoH723_Maps_BareMetal.qproj",") is described in\n",[403,1787,1789],{"href":1788},"\u002Fexamples\u002Ftcp-client-xcp-nucleo-maps","Calibration maps over XCP on TCP",[418,1791,1793],{"id":1792},"next","Next",[377,1795,1796,1798,1799,1802],{},[403,1797,269],{"href":409}," — the rules behind\nthe glue; ",[403,1800,282],{"href":1801},"\u002Fdevice-sdk\u002Ftroubleshooting"," — the rows for\nthe integration without an RTOS in the symptom table.",[1804,1805,1806],"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":832,"searchDepth":852,"depth":852,"links":1808},[1809,1810,1811,1812,1814,1815,1816],{"id":420,"depth":845,"text":421},{"id":572,"depth":845,"text":573},{"id":810,"depth":845,"text":811},{"id":963,"depth":845,"text":1813},"main.c: init once, poll forever",{"id":1469,"depth":845,"text":1470},{"id":1619,"depth":845,"text":1620},{"id":1792,"depth":845,"text":1793},"What changes when the firmware has no FreeRTOS — a glue over the lwIP RAW API driven from the main loop, lwIP settings in NO_SYS mode (TCP_MSS, TCP_SND_BUF), the CMake wiring, Init and Poll in main.c, the single-context model without a critical section, and the connection behaviour including the refusal of a second client.","md",{},{"title":264,"description":1817},"8URYmFCugkExF24boXsOn4fGzxv5vK1_tdhzmmeW3VE",[1823,1824],{"title":259,"path":260,"stem":261,"navTitle":262,"children":-1},{"title":269,"path":270,"stem":271,"navTitle":272,"children":-1},1791554568268]