[{"data":1,"prerenderedAt":2821},["ShallowReactive",2],{"page-\u002Fdocs\u002Fprotocol":3,"list-docs":2719},{"id":4,"title":5,"body":6,"description":2703,"extension":2704,"file":2705,"group":2706,"label":2707,"meta":2708,"minutes":2709,"navigation":2710,"order":2711,"path":2712,"section":2713,"seo":2714,"slug":733,"stem":2716,"updated":2717,"__hash__":2718},"pages\u002Fdocs\u002FBLE_PROTOCOL.md","Bluetooth LE and USB protocol",{"type":7,"value":8,"toc":2691},"minimark",[9,28,84,89,171,195,199,202,212,233,236,250,253,264,270,335,339,588,697,701,1364,1369,1519,1603,1655,1658,1664,1807,1815,1859,1886,1891,1907,2064,2076,2080,2093,2542,2658,2662,2668,2671,2687],[10,11,12,13,17,18,21,22,27],"p",{},"The web app (webapp\u002F, served from GitHub Pages) talks to the helmet with ",[14,15,16],"strong",{},"Web Bluetooth",", or over a USB cable with ",[14,19,20],{},"Web Serial",". Both carry the same JSON requests and responses (",[23,24,26],"a",{"href":25},"#requests-and-responses","below","). Any client that follows this page can control the helmet.",[29,30,31,47],"table",{},[32,33,34],"thead",{},[35,36,37,41,44],"tr",{},[38,39,40],"th",{},"Platform",[38,42,43],{},"Bluetooth",[38,45,46],{},"USB",[48,49,50,61,71],"tbody",{},[35,51,52,56,59],{},[53,54,55],"td",{},"macOS, Windows, Linux, ChromeOS",[53,57,58],{},"Chrome or Edge",[53,60,58],{},[35,62,63,66,68],{},[53,64,65],{},"Android",[53,67,58],{},[53,69,70],{},"–",[35,72,73,76,82],{},[53,74,75],{},"iPhone \u002F iPad",[53,77,78,81],{},[14,79,80],{},"Bluefy"," (Safari has no Web Bluetooth)",[53,83,70],{},[85,86,88],"h2",{"id":87},"gatt","GATT",[29,90,91,107],{},[32,92,93],{},[35,94,95,98,101,104],{},[38,96,97],{},"UUID",[38,99,100],{},"Name",[38,102,103],{},"Properties",[38,105,106],{},"Direction",[48,108,109,124,140,156],{},[35,110,111,117,120,122],{},[53,112,113],{},[114,115,116],"code",{},"a3c87500-8ed3-4bdf-8a39-a01bebede295",[53,118,119],{},"service",[53,121,70],{},[53,123,70],{},[35,125,126,131,134,137],{},[53,127,128],{},[114,129,130],{},"a3c87501-…",[53,132,133],{},"request",[53,135,136],{},"write, write without response",[53,138,139],{},"app → helmet",[35,141,142,147,150,153],{},[53,143,144],{},[114,145,146],{},"a3c87502-…",[53,148,149],{},"response",[53,151,152],{},"notify",[53,154,155],{},"helmet → app",[35,157,158,163,166,168],{},[53,159,160],{},[114,161,162],{},"a3c87503-…",[53,164,165],{},"status",[53,167,152],{},[53,169,170],{},"helmet → app: once right after the app subscribes, then every 0.5 s while running, every 2 s idle",[172,173,174,182,189,192],"ul",{},[175,176,177,178,181],"li",{},"The helmet advertises the service UUID; the name is ",[114,179,180],{},"GodHelmet-XXXX",", changeable in Helmet → Settings.",[175,183,184,185,188],{},"Up to ",[14,186,187],{},"two apps"," can be connected at once, e.g. the receiver and a telepathy sender.",[175,190,191],{},"An app gets notifications only for the characteristics it subscribed to. A response goes only to the app that sent the request (firmware before 0.4.0 notified every connected app).",[175,193,194],{},"After a disconnect the helmet advertises again at once, and checks every 2 s that it still does.",[85,196,198],{"id":197},"framing","Framing",[10,200,201],{},"A notification or write carries at most MTU − 3 bytes, so every JSON message is split into packets:",[203,204,209],"pre",{"className":205,"code":207,"language":208},[206],"language-text","[seq: u8][flags: u8][payload bytes …]     flags: bit0 FIRST, bit1 LAST\n","text",[114,210,207],{"__ignoreMap":211},"",[172,213,214,221,224,227],{},[175,215,216,217,220],{},"All packets of one message share ",[114,218,219],{},"seq",", and a FIRST packet discards any unfinished message.",[175,222,223],{},"The app writes packets of at most 180 bytes. That fits the 185-byte MTU of iOS\u002FmacOS; Android negotiates up to 517.",[175,225,226],{},"The helmet sizes its notifications to each app's own MTU, and never sends more than 512 bytes in one (the limit for an attribute value).",[175,228,229,230,232],{},"A request the helmet cannot take is answered with an error instead of silence (",[23,231,26],{"href":25},").",[10,234,235],{},"Implementations:",[172,237,238,244],{},[175,239,240,243],{},[114,241,242],{},"firmware\u002Flib\u002Fbleframe"," (C++, host-tested);",[175,245,246,249],{},[114,247,248],{},"webapp\u002Fsrc\u002Fble\u002Fframe.js"," (JS, tested against the same cases).",[85,251,46],{"id":252},"usb",[10,254,255,256,259,260,263],{},"One JSON message per line at 115200 baud (the chips' own USB ignores the baud rate). Implementations: ",[114,257,258],{},"firmware\u002Fsrc\u002Fusblink.cpp",", ",[114,261,262],{},"webapp\u002Fsrc\u002Fble\u002Fserial.js"," (tested against a fake board).",[203,265,268],{"className":266,"code":267,"language":208},[206],"→ {\"c\":1234567,\"id\":7,\"op\":\"hello\"}\\n\n← @{\"c\":1234567,\"id\":7,\"ok\":true,\"data\":{...}}\\n\n",[114,269,267],{"__ignoreMap":211},[172,271,272,282,292,305,311,329],{},[175,273,274,277,278,281],{},[14,275,276],{},"Replies"," start with ",[114,279,280],{},"@",". Every other line from the helmet is log text (the boot log, errors), so a terminal program shows both.",[175,283,284,287,288,291],{},[14,285,286],{},"Requests"," are lines that start with ",[114,289,290],{},"{",", up to 96 KB, like over Bluetooth. Other lines are ignored. A longer line, or one the board has no memory for, is answered with an error.",[175,293,294,297,298,300,301,304],{},[14,295,296],{},"No status pushes:"," the app asks with ",[114,299,165],{},", every 0.5 s while running and every 2 s idle. Each valid request counts as the app being present (status LED, ",[114,302,303],{},"keepaliveS","); other text on the line does not.",[175,306,307,310],{},[14,308,309],{},"Opening the port:"," the app turns RTS off, then DTR. Auto-reset circuits, and the chips' own USB, restart the board while RTS is on and DTR is off; this order never produces that. On boards with a USB bridge chip it does pull the BOOT pin low for a few milliseconds. BOOT is a STOP button, so the firmware takes it as STOP only when it is held for 40 ms: closing and reopening the port leaves a running session alone (firmware before 0.4.0 stopped it).",[175,312,313,316,317,320,321,324,325,232],{},[14,314,315],{},"Restarts:"," the first line after a restart is ",[114,318,319],{},"God helmet controller \u003Cversion> (\u003Cboard>, \u003Cchip>)",", the second ",[114,322,323],{},"Helmet \u003ChelmetId>, start \u003CbootId> (\u003CresetReason>)",". Seeing them means the board restarted, and any session on it has ended (",[23,326,328],{"href":327},"#when-the-connection-drops","When the connection drops",[175,330,331,334],{},[14,332,333],{},"Two USB sockets:"," on the S3, C3 and C6 both work, the chip's own USB and the bridge chip's UART.",[85,336,338],{"id":337},"requests-and-responses","Requests and responses",[203,340,344],{"className":341,"code":342,"language":343,"meta":211,"style":211},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","→ {\"c\": 1234567, \"id\": 7, \"op\": \"session.start\", \"session\": {...}, \"fieldUT\": 1.0, \"blind\": true}\n← {\"c\": 1234567, \"id\": 7, \"ok\": true, \"data\": {\"logId\": 12}}\n← {\"c\": 1234567, \"id\": 8, \"ok\": false, \"error\": \"a session is already running\"}\n","json",[114,345,346,455,526],{"__ignoreMap":211},[347,348,351,355,358,361,365,367,370,374,377,380,383,385,387,390,392,394,397,399,401,403,407,409,411,413,416,418,420,423,426,429,431,434,436,438,441,443,445,448,450,452],"span",{"class":349,"line":350},"line",1,[347,352,354],{"class":353},"sTEyZ","→ ",[347,356,290],{"class":357},"sMK4o",[347,359,360],{"class":357},"\"",[347,362,364],{"class":363},"spNyl","c",[347,366,360],{"class":357},[347,368,369],{"class":357},":",[347,371,373],{"class":372},"sbssI"," 1234567",[347,375,376],{"class":357},",",[347,378,379],{"class":357}," \"",[347,381,382],{"class":363},"id",[347,384,360],{"class":357},[347,386,369],{"class":357},[347,388,389],{"class":372}," 7",[347,391,376],{"class":357},[347,393,379],{"class":357},[347,395,396],{"class":363},"op",[347,398,360],{"class":357},[347,400,369],{"class":357},[347,402,379],{"class":357},[347,404,406],{"class":405},"sfazB","session.start",[347,408,360],{"class":357},[347,410,376],{"class":357},[347,412,379],{"class":357},[347,414,415],{"class":363},"session",[347,417,360],{"class":357},[347,419,369],{"class":357},[347,421,422],{"class":357}," {",[347,424,425],{"class":353},"...",[347,427,428],{"class":357},"},",[347,430,379],{"class":357},[347,432,433],{"class":363},"fieldUT",[347,435,360],{"class":357},[347,437,369],{"class":357},[347,439,440],{"class":372}," 1.0",[347,442,376],{"class":357},[347,444,379],{"class":357},[347,446,447],{"class":363},"blind",[347,449,360],{"class":357},[347,451,369],{"class":357},[347,453,454],{"class":357}," true}\n",[347,456,458,461,463,465,467,469,471,473,475,477,479,481,483,485,487,489,492,494,496,499,501,504,506,508,510,512,516,518,520,523],{"class":349,"line":457},2,[347,459,460],{"class":353},"← ",[347,462,290],{"class":357},[347,464,360],{"class":357},[347,466,364],{"class":363},[347,468,360],{"class":357},[347,470,369],{"class":357},[347,472,373],{"class":372},[347,474,376],{"class":357},[347,476,379],{"class":357},[347,478,382],{"class":363},[347,480,360],{"class":357},[347,482,369],{"class":357},[347,484,389],{"class":372},[347,486,376],{"class":357},[347,488,379],{"class":357},[347,490,491],{"class":363},"ok",[347,493,360],{"class":357},[347,495,369],{"class":357},[347,497,498],{"class":357}," true,",[347,500,379],{"class":357},[347,502,503],{"class":363},"data",[347,505,360],{"class":357},[347,507,369],{"class":357},[347,509,422],{"class":357},[347,511,360],{"class":357},[347,513,515],{"class":514},"sBMFI","logId",[347,517,360],{"class":357},[347,519,369],{"class":357},[347,521,522],{"class":372}," 12",[347,524,525],{"class":357},"}}\n",[347,527,529,531,533,535,537,539,541,543,545,547,549,551,553,556,558,560,562,564,566,569,571,574,576,578,580,583,585],{"class":349,"line":528},3,[347,530,460],{"class":353},[347,532,290],{"class":357},[347,534,360],{"class":357},[347,536,364],{"class":363},[347,538,360],{"class":357},[347,540,369],{"class":357},[347,542,373],{"class":372},[347,544,376],{"class":357},[347,546,379],{"class":357},[347,548,382],{"class":363},[347,550,360],{"class":357},[347,552,369],{"class":357},[347,554,555],{"class":372}," 8",[347,557,376],{"class":357},[347,559,379],{"class":357},[347,561,491],{"class":363},[347,563,360],{"class":357},[347,565,369],{"class":357},[347,567,568],{"class":357}," false,",[347,570,379],{"class":357},[347,572,573],{"class":363},"error",[347,575,360],{"class":357},[347,577,369],{"class":357},[347,579,379],{"class":357},[347,581,582],{"class":405},"a session is already running",[347,584,360],{"class":357},[347,586,587],{"class":357},"}\n",[172,589,590,595,620,623,632],{},[175,591,592,594],{},[114,593,364],{}," is a random tag per app. The helmet answers only the app that asked; firmware before 0.4.0 notified every connected app, so an app still keeps only responses with its own tag.",[175,596,597,599,600,602,603,605,606,259,609,612,613,616,617,619],{},[114,598,382],{}," matches a response to its request. The protocol has a single ",[114,601,382],{}," member: for the operations that take an ",[114,604,382],{}," parameter (",[114,607,608],{},"log.rate",[114,610,611],{},"trial.lock"," and the other ",[114,614,615],{},"trial.*"," ones), that entry's id is the request's ",[114,618,382],{},", and the response carries it. The app numbers its other requests from 1 000 000 000, so the two never meet, and matches such a response to its oldest waiting request with that id.",[175,621,622],{},"The helmet handles requests one at a time, in the order they arrive.",[175,624,625,626,628,629,631],{},"Write ",[114,627,364],{}," and ",[114,630,382],{}," as the first two members. The helmet reads them from the start of a request, so it can still say whose request it was when it has to drop one.",[175,633,634,637,638],{},[14,635,636],{},"Requests the helmet drops"," get an error response at once:",[29,639,640,651],{},[32,641,642],{},[35,643,644,648],{},[38,645,646],{},[114,647,573],{},[38,649,650],{},"When",[48,652,653,663,672,682],{},[35,654,655,660],{},[53,656,657],{},[114,658,659],{},"busy: request dropped",[53,661,662],{},"Six requests were already waiting. Sending it again is safe",[35,664,665,670],{},[53,666,667],{},[114,668,669],{},"request too large (96 KB at most)",[53,671],{},[35,673,674,679],{},[53,675,676],{},[114,677,678],{},"out of memory (program too large for this board)",[53,680,681],{},"The board has no room for a request this long, or for running it",[35,683,684,689],{},[53,685,686],{},[114,687,688],{},"request damaged: start missing",[53,690,691,692,628,694,696],{},"A packet arrived without its FIRST packet. ",[114,693,364],{},[114,695,382],{}," are then 0: the app fails its oldest waiting request. Sending it again is safe",[85,698,700],{"id":699},"operations","Operations",[29,702,703,715],{},[32,704,705],{},[35,706,707,709,712],{},[38,708,396],{},[38,710,711],{},"Parameters",[38,713,714],{},"Returns",[48,716,717,823,834,851,874,886,899,933,945,957,973,1043,1140,1158,1199,1215,1239,1257,1285,1302,1319,1341],{},[35,718,719,724,726],{},[53,720,721],{},[114,722,723],{},"hello",[53,725,70],{},[53,727,728,259,731,259,734,259,737,740,741,744,745,259,748,259,751,259,754,259,757,760,761,744,763,766,767,770,771,774,775,259,778,259,781,259,784,259,787,259,790,259,793,259,796,259,799,259,802,805,806,766,809,812,813,816,817,819,820],{},[114,729,730],{},"firmware",[114,732,733],{},"protocol",[114,735,736],{},"board",[114,738,739],{},"chip"," (e.g. ",[114,742,743],{},"ESP32-C3","), ",[114,746,747],{},"helmetId",[114,749,750],{},"bootId",[114,752,753],{},"uptimeS",[114,755,756],{},"resetReason",[114,758,759],{},"recoveredLogId"," (these five: ",[23,762,26],{"href":327},[114,764,765],{},"transports"," (",[114,768,769],{},"[\"ble\",\"usb\"]",", or ",[114,772,773],{},"[\"usb\"]"," with Bluetooth off), ",[114,776,777],{},"calibrated",[114,779,780],{},"safetyAccepted",[114,782,783],{},"maxReachableUT",[114,785,786],{},"maxFieldUT",[114,788,789],{},"defaultFieldUT",[114,791,792],{},"lastSessionEpoch",[114,794,795],{},"minIntervalS",[114,797,798],{},"freeHeap",[114,800,801],{},"fsUsed",[114,803,804],{},"fsTotal"," (measured while no session runs), ",[114,807,808],{},"links",[114,810,811],{},"ble",": connected apps, ",[114,814,815],{},"bleStatus",": those subscribed to status, ",[114,818,252],{},": ports with a request in the last 10 s), ",[114,821,822],{},"env",[35,824,825,829,831],{},[53,826,827],{},[114,828,165],{},[53,830,70],{},[53,832,833],{},"the live status (the same JSON as the Bluetooth status notification)",[35,835,836,841,846],{},[53,837,838],{},[114,839,840],{},"time.set",[53,842,843],{},[114,844,845],{},"epochMs",[53,847,848,850],{},[114,849,822],{}," (the app sends its clock on every connect)",[35,852,853,858,870],{},[53,854,855],{},[114,856,857],{},"env.set",[53,859,860,863,864,259,867],{},[114,861,862],{},"kp"," (0–9), ",[114,865,866],{},"ap",[114,868,869],{},"source",[53,871,872],{},[114,873,822],{},[35,875,876,881,883],{},[53,877,878],{},[114,879,880],{},"settings.get",[53,882,70],{},[53,884,885],{},"settings (below)",[35,887,888,893,896],{},[53,889,890],{},[114,891,892],{},"settings.set",[53,894,895],{},"any subset of the settings",[53,897,898],{},"settings; refused while a session runs",[35,900,901,905,925],{},[53,902,903],{},[114,904,406],{},[53,906,907,909,910,259,913,259,915,259,917,920,921,924],{},[114,908,415],{}," (preset JSON), ",[114,911,912],{},"presetId",[114,914,433],{},[114,916,447],{},[114,918,919],{},"token"," (optional, ",[23,922,26],{"href":923},"#starting-twice-is-starting-once",")",[53,926,927,929,930,932],{},[114,928,515],{},"; needs ",[114,931,780],{},". Refused when the log entry cannot be written",[35,934,935,940,942],{},[53,936,937],{},[114,938,939],{},"session.stop",[53,941,70],{},[53,943,944],{},"fades out over 2 s",[35,946,947,952,954],{},[53,948,949],{},[114,950,951],{},"session.skip",[53,953,70],{},[53,955,956],{},"next phase (after the last phase: stop)",[35,958,959,964,968],{},[53,960,961],{},[114,962,963],{},"session.field",[53,965,966],{},[114,967,433],{},[53,969,970,971],{},"live intensity change, clamped to ",[114,972,786],{},[35,974,975,980,1037],{},[53,976,977],{},[114,978,979],{},"test",[53,981,982,985,986,989,990,989,993,996,997,1000,1001,259,1004,1007,1008,1011,1012,259,1015,259,1018,259,1021,766,1024,989,1026,1028,1029,1031,1032,744,1034,1036],{},[114,983,984],{},"mode"," ",[114,987,988],{},"dc","\u002F",[114,991,992],{},"rotate",[114,994,995],{},"led"," (one output flashing +, pause, −, pause, for two LEDs in place of a coil)\u002F",[114,998,999],{},"leds"," (the same on AO1 to AO8 in turn, 2 s each), ",[114,1002,1003],{},"channel",[114,1005,1006],{},"mA"," (≤ 4.6), ",[114,1009,1010],{},"seconds"," (≤ 120), ",[114,1013,1014],{},"layout",[114,1016,1017],{},"dir",[114,1019,1020],{},"dwellMs",[114,1022,1023],{},"blinkHz",[114,1025,995],{},[114,1027,999],{},": flashes per second of each LED, 0.1–20, default 1; 0 = 0.5, 1, 2, 5, 10 Hz in turn, ",[114,1030,1010],{},"\u002F5 each, at least one round of AO1 to AO8 for ",[114,1033,999],{},[114,1035,919],{}," (optional)",[53,1038,1039,1042],{},[114,1040,1041],{},"logId: 0"," (not logged)",[35,1044,1045,1050,1059],{},[53,1046,1047],{},[114,1048,1049],{},"log.list",[53,1051,1052,259,1055,1058],{},[114,1053,1054],{},"offset",[114,1056,1057],{},"limit"," (≤ 10)",[53,1060,1061,259,1064,1067,1068,1071,1072,259,1074,259,1077,259,1079,259,1082,259,1084,259,1087,259,1089,259,1091,259,1094,259,1097,259,1100,259,1103,259,1106,259,1109,259,1111,259,1113,259,1116,259,1119,259,1122,259,1125,259,1128,1130,1131,259,1134,259,1137],{},[114,1062,1063],{},"total",[114,1065,1066],{},"items"," (newest first; unrated blind sessions show ",[114,1069,1070],{},"condition: \"hidden\"","). An entry: ",[114,1073,382],{},[114,1075,1076],{},"start",[114,1078,912],{},[114,1080,1081],{},"presetName",[114,1083,447],{},[114,1085,1086],{},"condition",[114,1088,979],{},[114,1090,433],{},[114,1092,1093],{},"plannedMs",[114,1095,1096],{},"elapsedMs",[114,1098,1099],{},"finished",[114,1101,1102],{},"completed",[114,1104,1105],{},"reason",[114,1107,1108],{},"kpValid",[114,1110,862],{},[114,1112,866],{},[114,1114,1115],{},"kpSource",[114,1117,1118],{},"lst",[114,1120,1121],{},"rating",[114,1123,1124],{},"notes",[114,1126,1127],{},"trialId",[114,1129,919],{},", and once it has ended ",[114,1132,1133],{},"finalFieldUT",[114,1135,1136],{},"fieldChanges",[114,1138,1139],{},"skips",[35,1141,1142,1146,1155],{},[53,1143,1144],{},[114,1145,608],{},[53,1147,1148,259,1150,1152,1153],{},[114,1149,382],{},[114,1151,1121],{}," 0–10, ",[114,1154,1124],{},[53,1156,1157],{},"the entry with its condition revealed; refused while that session is still running, and for a trial's session until the trial is revealed or aborted",[35,1159,1160,1165,1196],{},[53,1161,1162],{},[114,1163,1164],{},"trial.new",[53,1166,1167,985,1169,989,1172,259,1175,259,1178,985,1181,1184,1185,1187,1188,1187,1190,1187,1192,259,1194,1036],{},[114,1168,984],{},[114,1170,1171],{},"rv",[114,1173,1174],{},"telepathy",[114,1176,1177],{},"manifestHash",[114,1179,1180],{},"sets",[114,1182,1183],{},"[{id, size}]",", optional ",[114,1186,415],{}," + ",[114,1189,912],{},[114,1191,447],{},[114,1193,433],{},[114,1195,919],{},[53,1197,1198],{},"public trial. The trial and its log entry are on file before the session starts",[35,1200,1201,1205,1212],{},[53,1202,1203],{},[114,1204,611],{},[53,1206,1207,259,1209],{},[114,1208,382],{},[114,1210,1211],{},"responseHash",[53,1213,1214],{},"public trial (records time, Kp\u002Fap, LST)",[35,1216,1217,1222,1226],{},[53,1218,1219],{},[114,1220,1221],{},"trial.judge",[53,1223,1224],{},[114,1225,382],{},[53,1227,1228,1229,259,1232,1235,1236],{},"public trial with ",[114,1230,1231],{},"set",[114,1233,1234],{},"setSize",", shuffled ",[114,1237,1238],{},"order",[35,1240,1241,1246,1254],{},[53,1242,1243],{},[114,1244,1245],{},"trial.ranks",[53,1247,1248,259,1250,1253],{},[114,1249,382],{},[114,1251,1252],{},"ranks"," (rank per display position, a permutation of 1..N)",[53,1255,1256],{},"public trial",[35,1258,1259,1264,1268],{},[53,1260,1261],{},[114,1262,1263],{},"trial.reveal",[53,1265,1266],{},[114,1267,382],{},[53,1269,1270,1271,259,1273,259,1276,259,1279,259,1282],{},"full trial: ",[114,1272,1086],{},[114,1274,1275],{},"target",[114,1277,1278],{},"nonce",[114,1280,1281],{},"preimage",[114,1283,1284],{},"targetRank",[35,1286,1287,1292,1296],{},[53,1288,1289],{},[114,1290,1291],{},"trial.abort",[53,1293,1294],{},[114,1295,382],{},[53,1297,1298,1299,924],{},"– (the trial stays listed as ",[114,1300,1301],{},"aborted",[35,1303,1304,1309,1313],{},[53,1305,1306],{},[114,1307,1308],{},"trial.sender",[53,1310,1311],{},[114,1312,382],{},[53,1314,1315,1318],{},[114,1316,1317],{},"{set, target, manifestHash}",", only for open telepathy trials",[35,1320,1321,1330,1338],{},[53,1322,1323,1326,1327],{},[114,1324,1325],{},"trial.get"," \u002F ",[114,1328,1329],{},"trial.list",[53,1331,1332,1326,1334,259,1336],{},[114,1333,382],{},[114,1335,1054],{},[114,1337,1057],{},[53,1339,1340],{},"public trial(s)",[35,1342,1343,1348,1354],{},[53,1344,1345],{},[114,1346,1347],{},"rng.bytes",[53,1349,1350,1353],{},[114,1351,1352],{},"n"," (1–256)",[53,1355,1356,1359,1360,1363],{},[114,1357,1358],{},"{hex, source}",": hardware random bytes (",[114,1361,1362],{},"esp_fill_random","), for micro-PK tasks. A true RNG with Bluetooth on; with Bluetooth off the chip's noise source is switched on for the draw. Trials draw their target and condition the same way",[10,1365,1366],{},[14,1367,1368],{},"Settings:",[29,1370,1371,1381],{},[32,1372,1373],{},[35,1374,1375,1378],{},[38,1376,1377],{},"Key",[38,1379,1380],{},"Notes",[48,1382,1383,1393,1401,1411,1420,1429,1438,1447,1456,1464,1474,1483,1493,1502,1510],{},[35,1384,1385,1390],{},[53,1386,1387],{},[114,1388,1389],{},"uTperMA[8]",[53,1391,1392],{},"Per-coil calibration",[35,1394,1395,1399],{},[53,1396,1397],{},[114,1398,777],{},[53,1400],{},[35,1402,1403,1408],{},[53,1404,1405],{},[114,1406,1407],{},"seriesOhm",[53,1409,1410],{},"470–100000",[35,1412,1413,1418],{},[53,1414,1415],{},[114,1416,1417],{},"coilOhm",[53,1419],{},[35,1421,1422,1427],{},[53,1423,1424],{},[114,1425,1426],{},"vFullScale",[53,1428],{},[35,1430,1431,1436],{},[53,1432,1433],{},[114,1434,1435],{},"dacGain2x",[53,1437],{},[35,1439,1440,1445],{},[53,1441,1442],{},[114,1443,1444],{},"dacBufferedRef",[53,1446],{},[35,1448,1449,1453],{},[53,1450,1451],{},[114,1452,786],{},[53,1454,1455],{},"≤ 10",[35,1457,1458,1462],{},[53,1459,1460],{},[114,1461,789],{},[53,1463],{},[35,1465,1466,1471],{},[53,1467,1468],{},[114,1469,1470],{},"longitudeDeg",[53,1472,1473],{},"Used for local sidereal time",[35,1475,1476,1480],{},[53,1477,1478],{},[114,1479,303],{},[53,1481,1482],{},"Stop the session when no app has been present for this many seconds. 0 = off (the default: a session runs on without the app), otherwise 5–3600; other values are brought into that range. Present means, over Bluetooth, an app subscribed to status or sending a request; over USB, a valid request",[35,1484,1485,1490],{},[53,1486,1487],{},[114,1488,1489],{},"bleName",[53,1491,1492],{},"Applies after a restart",[35,1494,1495,1499],{},[53,1496,1497],{},[114,1498,792],{},[53,1500,1501],{},"Read-only",[35,1503,1504,1508],{},[53,1505,1506],{},[114,1507,780],{},[53,1509],{},[35,1511,1512,1517],{},[53,1513,1514],{},[114,1515,1516],{},"maxCurrentMA",[53,1518,1501],{},[10,1520,1521,985,1524,766,1527,989,1530,989,1533,744,1536,259,1539,259,1541,259,1543,259,1545,259,1548,259,1551,259,1554,259,1557,259,1560,259,1562,259,1565,259,1568,259,1571,259,1574,259,1577,259,1579,259,1582,259,1585,259,1588,259,1590,259,1592,259,1594,259,1597,259,1599,1602],{},[14,1522,1523],{},"Status notification:",[114,1525,1526],{},"state",[114,1528,1529],{},"idle",[114,1531,1532],{},"running",[114,1534,1535],{},"stopping",[114,1537,1538],{},"armed",[114,1540,447],{},[114,1542,979],{},[114,1544,515],{},[114,1546,1547],{},"sessionId",[114,1549,1550],{},"sessionName",[114,1552,1553],{},"phaseName",[114,1555,1556],{},"phase",[114,1558,1559],{},"phaseCount",[114,1561,1096],{},[114,1563,1564],{},"programMs",[114,1566,1567],{},"totalMs",[114,1569,1570],{},"phaseMs",[114,1572,1573],{},"phaseDurationMs",[114,1575,1576],{},"envelope",[114,1578,433],{},[114,1580,1581],{},"testMA",[114,1583,1584],{},"overruns",[114,1586,1587],{},"lastStopReason",[114,1589,750],{},[114,1591,919],{},[114,1593,912],{},[114,1595,1596],{},"startEpoch",[114,1598,1127],{},[114,1600,1601],{},"levels[8]",".",[172,1604,1605,1612,1625,1630],{},[175,1606,1607,1608,1611],{},"The ",[114,1609,1610],{},"levels"," field is omitted in blind sessions, since it would reveal a sham.",[175,1613,1614,259,1616,259,1618,259,1620,628,1622,1624],{},[114,1615,919],{},[114,1617,912],{},[114,1619,1596],{},[114,1621,1127],{},[114,1623,515],{}," describe the session that runs, and stay after it has ended until the next start.",[175,1626,1627,1629],{},[114,1628,1584],{}," counts output periods (0.5 ms each) that came late or were lost, measured against the clock: a stall of 5 ms adds 10. The session's own time does not fall behind.",[175,1631,1632,1634,1635,259,1637,259,1640,259,1643,259,1646,259,1649,259,1652,1602],{},[114,1633,1587],{},": ",[114,1636,1102],{},[114,1638,1639],{},"stopped from app",[114,1641,1642],{},"skipped past last phase",[114,1644,1645],{},"UI keepalive lost",[114,1647,1648],{},"STOP button",[114,1650,1651],{},"STOP button (BOOT)",[114,1653,1654],{},"STOP on screen",[85,1656,328],{"id":1657},"when-the-connection-drops",[10,1659,1660,1661,1663],{},"The helmet runs a session by itself. A dropped Bluetooth link, a pulled USB cable or a closed browser tab changes nothing on the helmet: the session runs to its end (unless ",[114,1662,303],{}," is set). What an app needs to find it again:",[29,1665,1666,1679],{},[32,1667,1668],{},[35,1669,1670,1673,1676],{},[38,1671,1672],{},"Field",[38,1674,1675],{},"Where",[38,1677,1678],{},"Meaning",[48,1680,1681,1698,1713,1726,1778,1791],{},[35,1682,1683,1687,1691],{},[53,1684,1685],{},[114,1686,747],{},[53,1688,1689],{},[114,1690,723],{},[53,1692,1693,1694,1697],{},"12 hex digits, fixed for the board (its last four are the ",[114,1695,1696],{},"XXXX"," of the default name)",[35,1699,1700,1704,1710],{},[53,1701,1702],{},[114,1703,750],{},[53,1705,1706,259,1708],{},[114,1707,723],{},[114,1709,165],{},[53,1711,1712],{},"A number that goes up by one at every start of the helmet",[35,1714,1715,1719,1723],{},[53,1716,1717],{},[114,1718,753],{},[53,1720,1721],{},[114,1722,723],{},[53,1724,1725],{},"Seconds since that start",[35,1727,1728,1732,1736],{},[53,1729,1730],{},[114,1731,756],{},[53,1733,1734],{},[114,1735,723],{},[53,1737,1738,1739,1742,1743,259,1746,259,1749,259,1752,259,1755,259,1758,259,1761,259,1764,259,1767,259,1769,259,1772,259,1775],{},"Why it started: ",[114,1740,1741],{},"power-on"," (also the reset button, which the chip cannot tell apart), ",[114,1744,1745],{},"software restart",[114,1747,1748],{},"panic",[114,1750,1751],{},"task watchdog",[114,1753,1754],{},"interrupt watchdog",[114,1756,1757],{},"watchdog",[114,1759,1760],{},"brownout",[114,1762,1763],{},"external reset",[114,1765,1766],{},"wake from sleep",[114,1768,252],{},[114,1770,1771],{},"jtag",[114,1773,1774],{},"sdio",[114,1776,1777],{},"unknown",[35,1779,1780,1784,1788],{},[53,1781,1782],{},[114,1783,759],{},[53,1785,1786],{},[114,1787,723],{},[53,1789,1790],{},"The log entry this start had to close because the helmet went down during that session; 0 = none",[35,1792,1793,1797,1802],{},[53,1794,1795],{},[114,1796,919],{},[53,1798,1799,1801],{},[114,1800,165],{},", log entry",[53,1803,1804,1805,924],{},"The token of the start request (",[23,1806,26],{"href":923},[10,1808,1809,1810,628,1812,1814],{},"After reconnecting, an app asks ",[114,1811,723],{},[114,1813,165],{}," and compares:",[172,1816,1817,1838,1851],{},[175,1818,1819,1831,1832,1834,1835,1837],{},[14,1820,1821,1822,1824,1825,259,1827,1830],{},"Same ",[114,1823,747],{},", same ",[114,1826,750],{},[114,1828,1829],{},"status.token"," is its own token:"," it is its session. ",[114,1833,1526],{}," says whether it still runs; if not, ",[114,1836,1587],{}," and the log entry say how it ended.",[175,1839,1840,1847,1848,1850],{},[14,1841,1821,1842,1844,1845,369],{},[114,1843,747],{},", another ",[114,1846,750],{}," the helmet restarted, and the session ended with it. The log entry ",[114,1849,759],{}," has the details.",[175,1852,1853,1858],{},[14,1854,1855,1856,369],{},"Another ",[114,1857,747],{}," a different helmet.",[10,1860,1861,1864,1865,1868,1869,1872,1873,1876,1877,1879,1880,1882,1883,1885],{},[14,1862,1863],{},"A restart in mid-session."," While a session runs, the helmet notes four times a second how far it has got, in memory that a crash, a watchdog or a software restart does not erase (no flash is written for it). At the next start it closes the session's log entry with the time it really ran and the reason ",[114,1866,1867],{},"restart: \u003CresetReason>",", for example ",[114,1870,1871],{},"restart: task watchdog",". A power cut erases that memory, and so does the reset button on most boards; the entry is then closed as ",[114,1874,1875],{},"power lost"," with ",[114,1878,1096],{}," 0. Either way the entry is ",[114,1881,1099],{},", not ",[114,1884,1102],{},", and can be rated as usual.",[1887,1888,1890],"h3",{"id":1889},"starting-twice-is-starting-once","Starting twice is starting once",[10,1892,1893,259,1895,628,1897,1899,1900,1902,1903,1906],{},[114,1894,406],{},[114,1896,979],{},[114,1898,1164],{}," take an optional ",[114,1901,919],{},": 1 to 24 characters from ",[114,1904,1905],{},"A-Z a-z 0-9 _ -",", a new random one for every start. When the reply to a start gets lost, the app does not know whether the session runs. It sends the same request again with the same token:",[203,1908,1910],{"className":341,"code":1909,"language":343,"meta":211,"style":211},"→ {\"c\": 1234567, \"id\": 1000000009, \"op\": \"session.start\", \"session\": {...}, \"token\": \"k3Vx81QmZt0aPw2L\"}\n← {\"c\": 1234567, \"id\": 1000000009, \"ok\": true, \"data\": {\"logId\": 12, \"already\": true}}\n",[114,1911,1912,1990],{"__ignoreMap":211},[347,1913,1914,1916,1918,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1941,1943,1945,1947,1949,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1986,1988],{"class":349,"line":350},[347,1915,354],{"class":353},[347,1917,290],{"class":357},[347,1919,360],{"class":357},[347,1921,364],{"class":363},[347,1923,360],{"class":357},[347,1925,369],{"class":357},[347,1927,373],{"class":372},[347,1929,376],{"class":357},[347,1931,379],{"class":357},[347,1933,382],{"class":363},[347,1935,360],{"class":357},[347,1937,369],{"class":357},[347,1939,1940],{"class":372}," 1000000009",[347,1942,376],{"class":357},[347,1944,379],{"class":357},[347,1946,396],{"class":363},[347,1948,360],{"class":357},[347,1950,369],{"class":357},[347,1952,379],{"class":357},[347,1954,406],{"class":405},[347,1956,360],{"class":357},[347,1958,376],{"class":357},[347,1960,379],{"class":357},[347,1962,415],{"class":363},[347,1964,360],{"class":357},[347,1966,369],{"class":357},[347,1968,422],{"class":357},[347,1970,425],{"class":353},[347,1972,428],{"class":357},[347,1974,379],{"class":357},[347,1976,919],{"class":363},[347,1978,360],{"class":357},[347,1980,369],{"class":357},[347,1982,379],{"class":357},[347,1984,1985],{"class":405},"k3Vx81QmZt0aPw2L",[347,1987,360],{"class":357},[347,1989,587],{"class":357},[347,1991,1992,1994,1996,1998,2000,2002,2004,2006,2008,2010,2012,2014,2016,2018,2020,2022,2024,2026,2028,2030,2032,2034,2036,2038,2040,2042,2044,2046,2048,2050,2052,2054,2057,2059,2061],{"class":349,"line":457},[347,1993,460],{"class":353},[347,1995,290],{"class":357},[347,1997,360],{"class":357},[347,1999,364],{"class":363},[347,2001,360],{"class":357},[347,2003,369],{"class":357},[347,2005,373],{"class":372},[347,2007,376],{"class":357},[347,2009,379],{"class":357},[347,2011,382],{"class":363},[347,2013,360],{"class":357},[347,2015,369],{"class":357},[347,2017,1940],{"class":372},[347,2019,376],{"class":357},[347,2021,379],{"class":357},[347,2023,491],{"class":363},[347,2025,360],{"class":357},[347,2027,369],{"class":357},[347,2029,498],{"class":357},[347,2031,379],{"class":357},[347,2033,503],{"class":363},[347,2035,360],{"class":357},[347,2037,369],{"class":357},[347,2039,422],{"class":357},[347,2041,360],{"class":357},[347,2043,515],{"class":514},[347,2045,360],{"class":357},[347,2047,369],{"class":357},[347,2049,522],{"class":372},[347,2051,376],{"class":357},[347,2053,379],{"class":357},[347,2055,2056],{"class":514},"already",[347,2058,360],{"class":357},[347,2060,369],{"class":357},[347,2062,2063],{"class":357}," true}}\n",[10,2065,2066,2069,2070,2072,2073,2075],{},[114,2067,2068],{},"already: true"," means nothing was started now: this is the session the first request made, whether it still runs or has ended. ",[114,2071,1164],{}," answers with the trial it made the first time, plus ",[114,2074,2068],{},". The helmet remembers the tokens of its last four starts, until it restarts. A start with another token, or with none, is refused as before while something runs.",[85,2077,2079],{"id":2078},"session-json","Session JSON",[10,2081,2082,2083,2086,2087,628,2090,369],{},"Same format as the files in ",[114,2084,2085],{},"presets\u002F",". Parsed by ",[114,2088,2089],{},"firmware\u002Flib\u002Fengine\u002Fsrc\u002Fpreset_json.cpp",[114,2091,2092],{},"webapp\u002Fsrc\u002Fengine\u002Fsession.js",[203,2094,2096],{"className":341,"code":2095,"language":343,"meta":211,"style":211},"{\n  \"id\": \"my-preset\", \"name\": \"My preset\", \"layout\": \"temporal\", \"uT\": 1.0,\n  \"fadeInS\": 10, \"fadeOutS\": 10,\n  \"phases\": [\n    {\"name\": \"Phase 1\", \"minutes\": 20, \"level\": 1.0, \"crossfade\": false,\n     \"pattern\": {\"type\": \"burst\", \"f0\": 6, \"f1\": 30, \"sweepMs\": 1500, \"gapMs\": 4000, \"pointMs\": 3},\n     \"spatial\": {\"mode\": \"rotate\", \"dir\": \"ccw\", \"dwell\": [10, 2, 20], \"weights\": [1,1,1,1,1,1,1,1]}}\n  ],\n  \"tableData\": [128, 200, 255]\n}\n",[114,2097,2098,2103,2172,2201,2216,2278,2382,2501,2507,2537],{"__ignoreMap":211},[347,2099,2100],{"class":349,"line":350},[347,2101,2102],{"class":357},"{\n",[347,2104,2105,2108,2110,2112,2114,2116,2119,2121,2123,2125,2128,2130,2132,2134,2137,2139,2141,2143,2145,2147,2149,2151,2154,2156,2158,2160,2163,2165,2167,2169],{"class":349,"line":457},[347,2106,2107],{"class":357},"  \"",[347,2109,382],{"class":363},[347,2111,360],{"class":357},[347,2113,369],{"class":357},[347,2115,379],{"class":357},[347,2117,2118],{"class":405},"my-preset",[347,2120,360],{"class":357},[347,2122,376],{"class":357},[347,2124,379],{"class":357},[347,2126,2127],{"class":363},"name",[347,2129,360],{"class":357},[347,2131,369],{"class":357},[347,2133,379],{"class":357},[347,2135,2136],{"class":405},"My preset",[347,2138,360],{"class":357},[347,2140,376],{"class":357},[347,2142,379],{"class":357},[347,2144,1014],{"class":363},[347,2146,360],{"class":357},[347,2148,369],{"class":357},[347,2150,379],{"class":357},[347,2152,2153],{"class":405},"temporal",[347,2155,360],{"class":357},[347,2157,376],{"class":357},[347,2159,379],{"class":357},[347,2161,2162],{"class":363},"uT",[347,2164,360],{"class":357},[347,2166,369],{"class":357},[347,2168,440],{"class":372},[347,2170,2171],{"class":357},",\n",[347,2173,2174,2176,2179,2181,2183,2186,2188,2190,2193,2195,2197,2199],{"class":349,"line":528},[347,2175,2107],{"class":357},[347,2177,2178],{"class":363},"fadeInS",[347,2180,360],{"class":357},[347,2182,369],{"class":357},[347,2184,2185],{"class":372}," 10",[347,2187,376],{"class":357},[347,2189,379],{"class":357},[347,2191,2192],{"class":363},"fadeOutS",[347,2194,360],{"class":357},[347,2196,369],{"class":357},[347,2198,2185],{"class":372},[347,2200,2171],{"class":357},[347,2202,2204,2206,2209,2211,2213],{"class":349,"line":2203},4,[347,2205,2107],{"class":357},[347,2207,2208],{"class":363},"phases",[347,2210,360],{"class":357},[347,2212,369],{"class":357},[347,2214,2215],{"class":357}," [\n",[347,2217,2219,2222,2224,2226,2228,2230,2232,2235,2237,2239,2241,2244,2246,2248,2251,2253,2255,2258,2260,2262,2264,2266,2268,2271,2273,2275],{"class":349,"line":2218},5,[347,2220,2221],{"class":357},"    {",[347,2223,360],{"class":357},[347,2225,2127],{"class":514},[347,2227,360],{"class":357},[347,2229,369],{"class":357},[347,2231,379],{"class":357},[347,2233,2234],{"class":405},"Phase 1",[347,2236,360],{"class":357},[347,2238,376],{"class":357},[347,2240,379],{"class":357},[347,2242,2243],{"class":514},"minutes",[347,2245,360],{"class":357},[347,2247,369],{"class":357},[347,2249,2250],{"class":372}," 20",[347,2252,376],{"class":357},[347,2254,379],{"class":357},[347,2256,2257],{"class":514},"level",[347,2259,360],{"class":357},[347,2261,369],{"class":357},[347,2263,440],{"class":372},[347,2265,376],{"class":357},[347,2267,379],{"class":357},[347,2269,2270],{"class":514},"crossfade",[347,2272,360],{"class":357},[347,2274,369],{"class":357},[347,2276,2277],{"class":357}," false,\n",[347,2279,2281,2284,2287,2289,2291,2293,2295,2298,2300,2302,2304,2307,2309,2311,2313,2316,2318,2320,2323,2325,2327,2330,2332,2334,2337,2339,2341,2344,2346,2348,2351,2353,2355,2358,2360,2362,2365,2367,2369,2372,2374,2376,2379],{"class":349,"line":2280},6,[347,2282,2283],{"class":357},"     \"",[347,2285,2286],{"class":514},"pattern",[347,2288,360],{"class":357},[347,2290,369],{"class":357},[347,2292,422],{"class":357},[347,2294,360],{"class":357},[347,2296,2297],{"class":372},"type",[347,2299,360],{"class":357},[347,2301,369],{"class":357},[347,2303,379],{"class":357},[347,2305,2306],{"class":405},"burst",[347,2308,360],{"class":357},[347,2310,376],{"class":357},[347,2312,379],{"class":357},[347,2314,2315],{"class":372},"f0",[347,2317,360],{"class":357},[347,2319,369],{"class":357},[347,2321,2322],{"class":372}," 6",[347,2324,376],{"class":357},[347,2326,379],{"class":357},[347,2328,2329],{"class":372},"f1",[347,2331,360],{"class":357},[347,2333,369],{"class":357},[347,2335,2336],{"class":372}," 30",[347,2338,376],{"class":357},[347,2340,379],{"class":357},[347,2342,2343],{"class":372},"sweepMs",[347,2345,360],{"class":357},[347,2347,369],{"class":357},[347,2349,2350],{"class":372}," 1500",[347,2352,376],{"class":357},[347,2354,379],{"class":357},[347,2356,2357],{"class":372},"gapMs",[347,2359,360],{"class":357},[347,2361,369],{"class":357},[347,2363,2364],{"class":372}," 4000",[347,2366,376],{"class":357},[347,2368,379],{"class":357},[347,2370,2371],{"class":372},"pointMs",[347,2373,360],{"class":357},[347,2375,369],{"class":357},[347,2377,2378],{"class":372}," 3",[347,2380,2381],{"class":357},"},\n",[347,2383,2385,2387,2390,2392,2394,2396,2398,2400,2402,2404,2406,2408,2410,2412,2414,2416,2418,2420,2422,2425,2427,2429,2431,2434,2436,2438,2441,2444,2446,2449,2451,2453,2456,2458,2461,2463,2465,2467,2470,2472,2474,2476,2478,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498],{"class":349,"line":2384},7,[347,2386,2283],{"class":357},[347,2388,2389],{"class":514},"spatial",[347,2391,360],{"class":357},[347,2393,369],{"class":357},[347,2395,422],{"class":357},[347,2397,360],{"class":357},[347,2399,984],{"class":372},[347,2401,360],{"class":357},[347,2403,369],{"class":357},[347,2405,379],{"class":357},[347,2407,992],{"class":405},[347,2409,360],{"class":357},[347,2411,376],{"class":357},[347,2413,379],{"class":357},[347,2415,1017],{"class":372},[347,2417,360],{"class":357},[347,2419,369],{"class":357},[347,2421,379],{"class":357},[347,2423,2424],{"class":405},"ccw",[347,2426,360],{"class":357},[347,2428,376],{"class":357},[347,2430,379],{"class":357},[347,2432,2433],{"class":372},"dwell",[347,2435,360],{"class":357},[347,2437,369],{"class":357},[347,2439,2440],{"class":357}," [",[347,2442,2443],{"class":372},"10",[347,2445,376],{"class":357},[347,2447,2448],{"class":372}," 2",[347,2450,376],{"class":357},[347,2452,2250],{"class":372},[347,2454,2455],{"class":357},"],",[347,2457,379],{"class":357},[347,2459,2460],{"class":372},"weights",[347,2462,360],{"class":357},[347,2464,369],{"class":357},[347,2466,2440],{"class":357},[347,2468,2469],{"class":372},"1",[347,2471,376],{"class":357},[347,2473,2469],{"class":372},[347,2475,376],{"class":357},[347,2477,2469],{"class":372},[347,2479,376],{"class":357},[347,2481,2469],{"class":372},[347,2483,376],{"class":357},[347,2485,2469],{"class":372},[347,2487,376],{"class":357},[347,2489,2469],{"class":372},[347,2491,376],{"class":357},[347,2493,2469],{"class":372},[347,2495,376],{"class":357},[347,2497,2469],{"class":372},[347,2499,2500],{"class":357},"]}}\n",[347,2502,2504],{"class":349,"line":2503},8,[347,2505,2506],{"class":357},"  ],\n",[347,2508,2510,2512,2515,2517,2519,2521,2524,2526,2529,2531,2534],{"class":349,"line":2509},9,[347,2511,2107],{"class":357},[347,2513,2514],{"class":363},"tableData",[347,2516,360],{"class":357},[347,2518,369],{"class":357},[347,2520,2440],{"class":357},[347,2522,2523],{"class":372},"128",[347,2525,376],{"class":357},[347,2527,2528],{"class":372}," 200",[347,2530,376],{"class":357},[347,2532,2533],{"class":372}," 255",[347,2535,2536],{"class":357},"]\n",[347,2538,2540],{"class":349,"line":2539},10,[347,2541,587],{"class":357},[29,2543,2544,2553],{},[32,2545,2546],{},[35,2547,2548,2550],{},[38,2549,1672],{},[38,2551,2552],{},"Values",[48,2554,2555,2592,2630,2645],{},[35,2556,2557,2562],{},[53,2558,2559,2560],{},"Pattern ",[114,2561,2297],{},[53,2563,2564,259,2567,259,2569,259,2572,259,2575,259,2577,259,2580,259,2583,259,2586,2588,2589,2591],{},[114,2565,2566],{},"off",[114,2568,988],{},[114,2570,2571],{},"sine",[114,2573,2574],{},"chirp",[114,2576,2306],{},[114,2578,2579],{},"thomas",[114,2581,2582],{},"pulse",[114,2584,2585],{},"semirandom",[114,2587,29],{}," (needs ",[114,2590,2514],{},", values 0–255, at most 8192)",[35,2593,2594,2599],{},[53,2595,2596,2597],{},"Spatial ",[114,2598,984],{},[53,2600,2601,259,2604,259,2607,259,2610,259,2612,2615,2616,744,2619,766,2622,744,2625,766,2628,924],{},[114,2602,2603],{},"bilateral",[114,2605,2606],{},"left",[114,2608,2609],{},"right",[114,2611,992],{},[114,2613,2614],{},"cycle"," (one ",[114,2617,2618],{},"side",[114,2620,2621],{},"alternate",[114,2623,2624],{},"alternateMs",[114,2626,2627],{},"single",[114,2629,1003],{},[35,2631,2632,2635],{},[53,2633,2634],{},"Dwell",[53,2636,2637,2640,2641,2644],{},[114,2638,2639],{},"\"dwellMs\": 20"," (fixed) or ",[114,2642,2643],{},"\"dwell\": [start, step, end]"," (ramp, repeats)",[35,2646,2647,2650],{},[53,2648,2649],{},"Duration",[53,2651,2652,2654,2655,2657],{},[114,2653,2243],{}," or ",[114,2656,1010],{}," per phase; the total must be ≤ 60 min",[85,2659,2661],{"id":2660},"trial-commitment","Trial commitment",[203,2663,2666],{"className":2664,"code":2665,"language":208},[206],"preimage   = \"godhelmet-trial|id=\u003Cid>|manifest=\u003CmanifestHash>|set=\u003Cset>|target=\u003Ck>|condition=\u003Cc>|nonce=\u003C32 hex>\"\ncommitment = SHA-256(preimage)                          published by trial.new\nmanifest   = {\"format\":\"godhelmet-pool-manifest\",\"version\":1,\"sets\":[{\"id\":…,\"images\":[\u003Csha256 of each picture>…]}…]}\nresponseHash = SHA-256(JSON.stringify({trialId, text, sketch}))   sent by trial.lock\n",[114,2667,2665],{"__ignoreMap":211},[10,2669,2670],{},"After the reveal, the app checks three things:",[172,2672,2673,2676,2682],{},[175,2674,2675],{},"the commitment matches the preimage;",[175,2677,2678,2679,2681],{},"the local pool still hashes to ",[114,2680,1177],{},";",[175,2683,2684,2685,1602],{},"the stored response still hashes to ",[114,2686,1211],{},[2688,2689,2690],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":211,"searchDepth":528,"depth":528,"links":2692},[2693,2694,2695,2696,2697,2698,2701,2702],{"id":87,"depth":457,"text":88},{"id":197,"depth":457,"text":198},{"id":252,"depth":457,"text":46},{"id":337,"depth":457,"text":338},{"id":699,"depth":457,"text":700},{"id":1657,"depth":457,"text":328,"children":2699},[2700],{"id":1889,"depth":528,"text":1890},{"id":2078,"depth":457,"text":2079},{"id":2660,"depth":457,"text":2661},"The Bluetooth service, packet framing, the USB line protocol, every operation, session JSON and the trial commitment.","md","docs\u002FBLE_PROTOCOL.md","Reference","Device protocol",{},11,true,18,"\u002Fdocs\u002Fprotocol","docs",{"title":5,"description":2715},"The web app (webapp\u002F, served from GitHub Pages) talks to the helmet with Web Bluetooth, or over a USB cable with Web Serial. Both carry the same JSON requests and responses (below). Any client that follows this page can control the helmet.","docs\u002FBLE_PROTOCOL",null,"7qTieG336EvkYRLKYaeNPI_C35IZCqUyCbpuNHQyRTU",[2720,2728,2735,2743,2750,2757,2764,2772,2781,2789,2797,2805,2812,2820],{"path":2721,"title":2722,"description":2723,"section":2713,"slug":2724,"label":2725,"group":2726,"order":2218,"minutes":2384,"updated":2717,"file":2727},"\u002Fdocs\u002Foverview","God Helmet: 8-coil weak-field headset (ESP32 + AD5328 + web app over Bluetooth or USB)","What the project is, what is in the repository, quick start and current status.","overview","Overview","Start here","README.md",{"path":2729,"title":2730,"description":2731,"section":2713,"slug":2732,"label":2730,"group":2726,"order":2280,"minutes":2733,"updated":2717,"file":2734},"\u002Fdocs\u002Fsafety","Safety","Who must not use the helmet, the rules for every session, and the safeguards built into the firmware.","safety",29,"docs\u002FSAFETY.md",{"path":2736,"title":2737,"description":2738,"section":2713,"slug":2739,"label":2740,"group":2741,"order":2384,"minutes":457,"updated":2717,"file":2742},"\u002Fdocs\u002Fparts","Bill of materials","Every part of the helmet with quantities and notes.","parts","Parts list","Build it","hardware\u002FBOM.md",{"path":2744,"title":2745,"description":2746,"section":2713,"slug":2747,"label":2745,"group":2741,"order":2503,"minutes":2748,"updated":2717,"file":2749},"\u002Fdocs\u002Fwiring","Wiring","Schematic, coil leads, pin tables for each supported board, the arming switch and cable pair mapping.","wiring",15,"docs\u002FWIRING.md",{"path":2751,"title":2752,"description":2753,"section":2713,"slug":2754,"label":2755,"group":2741,"order":2509,"minutes":2203,"updated":2717,"file":2756},"\u002Fdocs\u002Fcalibration","Bench test and calibration","Bench test of the module, wiring checks, and measuring µT per mA with a phone.","calibration","Calibration","docs\u002FCALIBRATION.md",{"path":2758,"title":2759,"description":2760,"section":2713,"slug":2761,"label":2762,"group":2741,"order":2539,"minutes":2384,"updated":2717,"file":2763},"\u002Fdocs\u002Fstandalone","Standalone display board","Running the helmet from the 2.8\" display board without phone or computer: flashing, the SD-card program pack, clock and screens.","standalone","Touchscreen board","docs\u002FSTANDALONE.md",{"path":2765,"title":2766,"description":2767,"section":2713,"slug":2768,"label":2766,"group":2769,"order":2709,"minutes":2770,"updated":2717,"file":2771},"\u002Fdocs\u002Fplacement","Coil placement","The 10-10 system, finding sites with a tape measure, the standard and program-specific layouts, depth and field per target.","placement","Use it",42,"docs\u002FPLACEMENT.md",{"path":2773,"title":2774,"description":2775,"section":2713,"slug":2776,"label":2777,"group":2769,"order":2778,"minutes":2779,"updated":2717,"file":2780},"\u002Fdocs\u002Fexperiments","Testing it honestly: blinded sessions and psi trials","Blinded real and sham sessions, remote-viewing and telepathy protocols, and the statistics behind the results table.","experiments","Experiments",12,33,"docs\u002FEXPERIMENTS.md",{"path":2782,"title":2783,"description":2784,"section":2713,"slug":2785,"label":2786,"group":2769,"order":2787,"minutes":2384,"updated":2717,"file":2788},"\u002Fdocs\u002Fguides","Guided sessions (\"Guides\")","The guided-session format, the audio engine and how guides arm the helmet.","guides","Guided sessions",13,"docs\u002FGUIDES.md",{"path":2790,"title":2791,"description":2792,"section":2713,"slug":2793,"label":2791,"group":2769,"order":2794,"minutes":2795,"updated":2717,"file":2796},"\u002Fdocs\u002Fquestionnaires","Questionnaires","The questionnaires used in guides, their sources, licences and scoring.","questionnaires",14,20,"docs\u002FQUESTIONNAIRES.md",{"path":2798,"title":2799,"description":2800,"section":2713,"slug":2801,"label":2802,"group":2706,"order":2748,"minutes":2803,"updated":2717,"file":2804},"\u002Fdocs\u002Fsignals","Signals: what the coils play and where it comes from","What the coils play: coil physics and exposure limits, the Persinger-lab signals rebuilt from primary sources, vendor signal families and clinical timings.","signals","Signals",44,"docs\u002FSIGNALS.md",{"path":2806,"title":2807,"description":2808,"section":2713,"slug":2809,"label":2807,"group":2706,"order":2810,"minutes":2503,"updated":2717,"file":2811},"\u002Fdocs\u002Fpreset-format","Program file format","The program file format, every signal and coil mode, the pulse-table generators and the preset checker.","preset-format",16,"docs\u002FPRESET_FORMAT.md",{"path":2813,"title":2814,"description":2815,"section":2713,"slug":2816,"label":2817,"group":2706,"order":2818,"minutes":2203,"updated":2717,"file":2819},"\u002Fdocs\u002Fbrain-view","Brain view: how the field map is made","How the field map on the brain is computed, how accurate it is, and the data and licences behind it.","brain-view","Brain view",17,"docs\u002FBRAIN_VIEW.md",{"path":2712,"title":5,"description":2703,"section":2713,"slug":733,"label":2707,"group":2706,"order":2711,"minutes":2709,"updated":2717,"file":2705},1794317844332]