{"id":1282,"date":"2026-05-07T20:35:41","date_gmt":"2026-05-07T20:35:41","guid":{"rendered":"https:\/\/b9xelectronics.com\/?page_id=1282"},"modified":"2026-08-25T15:31:31","modified_gmt":"2026-08-25T15:31:31","slug":"workbench-c","status":"publish","type":"page","link":"https:\/\/b9xelectronics.com\/?page_id=1282","title":{"rendered":"B9X Basic"},"content":{"rendered":"\n<div data-wp-interactive=\"core\/file\" class=\"wp-block-file\"><object data-wp-bind--hidden=\"!state.hasPdfPreview\" hidden class=\"wp-block-file__embed\" data=\"https:\/\/b9xelectronics.com\/wp-content\/uploads\/2026\/08\/B9X_Basic_Developer_Module_Getting_Started_Guide.pdf\" type=\"application\/pdf\" style=\"width:100%;height:600px\" aria-label=\"Embed of B9X_Basic_Developer_Module_Getting_Started_Guide.\"><\/object><a id=\"wp-block-file--media-3a361f4a-116b-4981-8ecf-e3bae81d18db\" href=\"https:\/\/b9xelectronics.com\/wp-content\/uploads\/2026\/08\/B9X_Basic_Developer_Module_Getting_Started_Guide.pdf\">B9X_Basic_Developer_Module_Getting_Started_Guide<\/a><a href=\"https:\/\/b9xelectronics.com\/wp-content\/uploads\/2026\/08\/B9X_Basic_Developer_Module_Getting_Started_Guide.pdf\" class=\"wp-block-file__button wp-element-button\" download aria-describedby=\"wp-block-file--media-3a361f4a-116b-4981-8ecf-e3bae81d18db\">Download<\/a><\/div>\n\n\n\n<!-- B9X Basic v1.03 Language Reference\n     Paste this entire file into a WordPress Custom HTML block. -->\n<style>\n.b9x-ref{--wine:#651b2b;--wine2:#43101d;--rose:#f7edf0;--ink:#242126;--muted:#625d63;--line:#dfd4d7;--ok:#eaf6ee;max-width:1120px;margin:20px auto;color:var(--ink);font:16px\/1.65 -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Arial,sans-serif}\n.b9x-ref *{box-sizing:border-box}.b9x-ref a{color:var(--wine);font-weight:650}.b9x-ref .hero{padding:38px;border-radius:18px;background:linear-gradient(135deg,var(--wine2),var(--wine));color:#fff;box-shadow:0 12px 30px rgba(67,16,29,.18)}\n.b9x-ref .eyebrow{text-transform:uppercase;letter-spacing:.14em;font-size:.76rem;font-weight:800;opacity:.82}.b9x-ref h1{margin:.2em 0 .25em;font-size:clamp(2rem,5vw,3.4rem);line-height:1.08;color:#fff}.b9x-ref .hero p{max-width:820px;margin:.5em 0 0;font-size:1.08rem}.b9x-ref .version{display:inline-block;margin-top:18px;padding:6px 12px;border:1px solid rgba(255,255,255,.45);border-radius:999px;font-weight:750}\n.b9x-ref .toc,.b9x-ref .callout,.b9x-ref section{margin:24px 0;padding:26px;border:1px solid var(--line);border-radius:14px;background:#fff;box-shadow:0 6px 20px rgba(35,25,28,.05)}\n.b9x-ref .toc{background:var(--rose)}.b9x-ref .toc ol{columns:2;column-gap:40px;margin:12px 0 0;padding-left:24px}.b9x-ref .toc li{break-inside:avoid;margin:5px 0}.b9x-ref h2{scroll-margin-top:24px;margin:0 0 16px;color:var(--wine);font-size:1.7rem;line-height:1.2;border-bottom:3px solid var(--rose);padding-bottom:9px}.b9x-ref h3{margin:24px 0 8px;color:var(--wine2);font-size:1.22rem}.b9x-ref h4{margin:0 0 4px;color:var(--wine2);font-size:1.05rem}.b9x-ref p{margin:.55em 0}.b9x-ref ul,.b9x-ref ol{padding-left:24px}\n.b9x-ref .critical{border-left:7px solid #c79a17;background:#fff9df}.b9x-ref .voice{border-left:7px solid var(--wine);background:var(--rose)}.b9x-ref .good{border-left:7px solid #2f7a4a;background:var(--ok)}\n.b9x-ref code{font-family:Consolas,\"Courier New\",monospace}.b9x-ref :not(pre)>code{padding:2px 6px;border-radius:5px;background:#f2ecee;color:var(--wine2)}.b9x-ref pre{overflow:auto;margin:10px 0 16px;padding:16px;border-radius:9px;background:#19161a;color:#f8f4f5;font:14px\/1.55 Consolas,\"Courier New\",monospace;white-space:pre}.b9x-ref .sig{font-weight:800;color:#fff;background:var(--wine2);padding:11px 14px;border-radius:8px;overflow:auto;white-space:nowrap}\n.b9x-ref table{width:100%;border-collapse:collapse;margin:12px 0 18px}.b9x-ref th,.b9x-ref td{border:1px solid var(--line);padding:10px 12px;text-align:left;vertical-align:top}.b9x-ref th{background:var(--wine);color:#fff}.b9x-ref tbody tr:nth-child(even){background:#fbf8f9}.b9x-ref .function{margin:18px 0;padding:18px;border:1px solid var(--line);border-radius:11px;background:#fff}.b9x-ref .function .returns{margin-top:8px;padding:8px 11px;border-left:4px solid var(--wine);background:var(--rose)}.b9x-ref .tag{display:inline-block;padding:2px 8px;border-radius:999px;background:var(--rose);color:var(--wine);font-size:.78rem;font-weight:800;text-transform:uppercase;letter-spacing:.04em}.b9x-ref .top{text-align:right;font-size:.88rem}.b9x-ref .footer{text-align:center;color:var(--muted);padding:25px 10px}\n@media(max-width:720px){.b9x-ref{font-size:15px}.b9x-ref .hero,.b9x-ref section,.b9x-ref .toc,.b9x-ref .callout{padding:20px}.b9x-ref .toc ol{columns:1}.b9x-ref table,.b9x-ref thead,.b9x-ref tbody,.b9x-ref tr,.b9x-ref th,.b9x-ref td{display:block}.b9x-ref thead{display:none}.b9x-ref td{border-top:0}.b9x-ref tr{margin-bottom:12px;border-top:1px solid var(--line)}}\n<\/style>\n\n<div class=\"b9x-ref\" id=\"b9x-top\">\n  <header class=\"hero\">\n    <div class=\"eyebrow\">B9X Electronics Documentation<\/div>\n    <h1>B9X Basic Language Reference<\/h1>\n    <p>A complete guide to B9X Basic v1.03, including language syntax, variables, control flow, user functions, GPIO, storage, MQTT, audio, OpenAI services and real-time VoIP through B9X Voice Server.<\/p>\n    <span class=\"version\">Version 1.03<\/span>\n  <\/header>\n\n  <div class=\"callout critical\">\n    <h3>Required function-return syntax<\/h3>\n    <p>Every function returns a value. A numeric\/double-returning function must be used in a numeric assignment. A string-returning function must be used in a string assignment beginning with <code>LET<\/code>. Calling either type as a stand-alone statement causes a compile error.<\/p>\n<pre><code>' Correct numeric\/double return\nretval = somefunction();\n\n' Correct string return\nlet retstr$ = somefunction$();\n\n' Incorrect \u2014 return value has nowhere to go\nsomefunction();\nsomefunction$();<\/code><\/pre>\n    <p>Examples throughout this reference follow this rule, including initialization, output and stop functions that are often treated like procedures in other languages.<\/p>\n  <\/div>\n\n  <nav class=\"toc\" aria-label=\"B9X Basic reference contents\">\n    <h2>On this page<\/h2>\n    <ol>\n      <li><a href=\"#fundamentals\">Language fundamentals<\/a><\/li>\n      <li><a href=\"#values\">Values, variables and arrays<\/a><\/li>\n      <li><a href=\"#operators\">Expressions and operators<\/a><\/li>\n      <li><a href=\"#control\">Statements and control flow<\/a><\/li>\n      <li><a href=\"#user-functions\">SUB and FUNCTION<\/a><\/li>\n      <li><a href=\"#strings\">String functions<\/a><\/li>\n      <li><a href=\"#format-time\">Formatting and time<\/a><\/li>\n      <li><a href=\"#math\">Mathematics<\/a><\/li>\n      <li><a href=\"#system\">System, Wi-Fi and NVS<\/a><\/li>\n      <li><a href=\"#gpio\">GPIO, timing, ADC and temperature<\/a><\/li>\n      <li><a href=\"#display-audio\">Display, motion, WAV and local TTS<\/a><\/li>\n      <li><a href=\"#openai\">OpenAI text, transcription and TTS<\/a><\/li>\n      <li><a href=\"#voip\">B9X Voice Server VoIP<\/a><\/li>\n      <li><a href=\"#infrared\">Infrared<\/a><\/li>\n      <li><a href=\"#leds\">WS2812 LEDs<\/a><\/li>\n      <li><a href=\"#mqtt\">MQTT<\/a><\/li>\n      <li><a href=\"#files\">File logging and reset<\/a><\/li>\n      <li><a href=\"#templates\">Supplied user-function templates<\/a><\/li>\n      <li><a href=\"#keys\">Protected keys<\/a><\/li>\n      <li><a href=\"#patterns\">Complete patterns<\/a><\/li>\n      <li><a href=\"#limits\">Limits and quick reference<\/a><\/li>\n    <\/ol>\n  <\/nav>\n\n  <section id=\"fundamentals\">\n    <h2>1. Language fundamentals<\/h2>\n    <p>B9X Basic is a compact embedded language. Programs contain executable statements and optional <code>SUB<\/code> and <code>FUNCTION<\/code> definitions. Simple statements end with a semicolon. Block endings such as <code>ENDIF<\/code>, <code>WEND<\/code>, <code>NEXT<\/code>, <code>END SUB<\/code> and <code>END FUNCTION<\/code> do not.<\/p>\n<pre><code>' Minimal program\nlet greeting$ = \"Hello from B9X\";\ncounter = 3;\nprint greeting$;\nprint counter;<\/code><\/pre>\n    <table><thead><tr><th>Item<\/th><th>Rule<\/th><\/tr><\/thead><tbody>\n      <tr><td>Numeric identifier<\/td><td>Begins with a letter or underscore; remaining characters may include digits.<\/td><\/tr>\n      <tr><td>String identifier<\/td><td>Uses the same rules and ends with <code>$<\/code>.<\/td><\/tr>\n      <tr><td>Identifier length<\/td><td>31 stored characters maximum.<\/td><\/tr>\n      <tr><td>Numbers<\/td><td>Decimal integer, decimal fraction or scientific notation, such as <code>12<\/code>, <code>3.5<\/code> or <code>1.2e-3<\/code>.<\/td><\/tr>\n      <tr><td>Strings<\/td><td>Text enclosed in double quotation marks.<\/td><\/tr>\n      <tr><td>Case<\/td><td>Names are case-sensitive. Use function spelling exactly as shown.<\/td><\/tr>\n      <tr><td>Truth<\/td><td>Zero is false; any nonzero numeric value is true.<\/td><\/tr>\n    <\/tbody><\/table>\n    <h3>Comments<\/h3>\n<pre><code>' Apostrophe comment\n\/\/ C++-style comment\n\/* Block comment\n   across lines *\/<\/code><\/pre>\n  <\/section>\n\n  <section id=\"values\">\n    <h2>2. Values, variables and arrays<\/h2>\n    <p>All ordinary numeric variables and numeric function results are double-precision values. String names end in <code>$<\/code>, hold up to 512 characters and require <code>LET<\/code> when assigned.<\/p>\n<pre><code>temperature = 72.5;\nlet title$ = \"B9X Basic\";\n\ndim samples[9];       ' indices 0 through 9\nsamples[0] = 12.5;\nretval = samples[0];<\/code><\/pre>\n    <p>The declared array bound is inclusive. String arrays are not implemented. Variables created outside a function are global. Function parameters temporarily hold local argument values and are restored when the function returns. A function can still read or modify other global variables.<\/p>\n  <\/section>\n\n  <section id=\"operators\">\n    <h2>3. Expressions and operators<\/h2>\n    <table><thead><tr><th>Order<\/th><th>Operators<\/th><th>Meaning<\/th><\/tr><\/thead><tbody>\n      <tr><td>1<\/td><td><code>( )<\/code><\/td><td>Grouping and function calls<\/td><\/tr>\n      <tr><td>2<\/td><td><code>+ - NOT !<\/code><\/td><td>Unary sign and logical negation<\/td><\/tr>\n      <tr><td>3<\/td><td><code>**<\/code><\/td><td>Exponentiation, right-associative<\/td><\/tr>\n      <tr><td>4<\/td><td><code>* \/<\/code><\/td><td>Multiplication and division<\/td><\/tr>\n      <tr><td>5<\/td><td><code>+ -<\/code><\/td><td>Addition\/subtraction; <code>+<\/code> also concatenates strings<\/td><\/tr>\n      <tr><td>6<\/td><td><code>&lt; &lt;= &gt; &gt;=<\/code><\/td><td>Relational comparison<\/td><\/tr>\n      <tr><td>7<\/td><td><code>== !=<\/code><\/td><td>Equality and inequality<\/td><\/tr>\n      <tr><td>8<\/td><td><code>AND &amp;&amp;<\/code><\/td><td>Logical AND<\/td><\/tr>\n      <tr><td>9<\/td><td><code>OR ||<\/code><\/td><td>Logical OR<\/td><\/tr>\n    <\/tbody><\/table>\n<pre><code>result = 2 + 3 * 4;\npower = 2 ** 3 ** 2;\nenabled = temperature &gt;= 25 and alarm == 1;\nlet message$ = \"Value: \" + str$(result);<\/code><\/pre>\n    <p><strong>Use <code>==<\/code> for comparison.<\/strong> A single <code>=<\/code> performs assignment.<\/p>\n  <\/section>\n\n  <section id=\"control\">\n    <h2>4. Statements and control flow<\/h2>\n<pre><code>if temperature &gt; 80 then\n    print \"High\";\nelse\n    print \"Normal\";\nendif\n\ncount = 0;\nwhile count &lt; 5 do\n    print count;\n    count = count + 1;\nwend\n\nfor i = 0 to 10 step 2 do\n    print i;\nnext<\/code><\/pre>\n    <p><code>STEP<\/code> defaults to 1 and may be negative. Do not use zero. Braces may form an explicit statement block. B9X Basic does not implement line numbers, GOTO, GOSUB, INPUT, DATA\/READ, SELECT CASE, BREAK or CONTINUE.<\/p>\n  <\/section>\n\n  <section id=\"user-functions\">\n    <h2>5. Subroutines and user functions<\/h2>\n    <h3>SUB<\/h3>\n    <p>A <code>SUB<\/code> is an argument-free procedure invoked with <code>CALL<\/code>. It may use <code>RETURN;<\/code> to exit early.<\/p>\n<pre><code>sub blink()\n    retval = setHigh(2);\n    retval = wait(100);\n    retval = setLow(2);\nend sub\n\ncall blink();<\/code><\/pre>\n    <h3>Numeric FUNCTION<\/h3>\n<pre><code>function clamp(value, low, high)\n    if value &lt; low then\n        return low;\n    endif\n    if value &gt; high then\n        return high;\n    endif\n    return value;\nend function\n\nretval = clamp(120, 0, 100);<\/code><\/pre>\n    <h3>String FUNCTION<\/h3>\n<pre><code>function greeting$(name$)\n    return \"Hello, \" + name$;\nend function\n\nlet retstr$ = greeting$(\"B9X\");<\/code><\/pre>\n    <p>A user function accepts up to eight numeric or string parameters. String parameter and function names end in <code>$<\/code>. Define a function before the code that calls it.<\/p>\n  <\/section>\n\n  <section id=\"strings\">\n    <h2>6. Core string functions<\/h2>\n    <div class=\"function\"><h4>len <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>len(text$)<\/code><\/div><p>Returns the character count.<\/p><pre><code>retval = len(\"B9X\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Numeric character count.<\/div><\/div>\n    <div class=\"function\"><h4>left$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>left$(text$, count)<\/code><\/div><p>Returns up to <em>count<\/em> characters from the left. Negative counts act as zero; oversized counts are capped.<\/p><pre><code>let retstr$ = left$(\"B9X Basic\", 3);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> A string.<\/div><\/div>\n    <div class=\"function\"><h4>right$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>right$(text$, count)<\/code><\/div><p>Returns up to <em>count<\/em> characters from the right.<\/p><pre><code>let retstr$ = right$(\"B9X Basic\", 5);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> A string.<\/div><\/div>\n    <div class=\"function\"><h4>mid$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>mid$(text$, start, count)<\/code><\/div><p>Extracts characters beginning at the 1-based start position.<\/p><pre><code>let retstr$ = mid$(\"B9X Basic\", 5, 5);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> A string clipped at the source boundary.<\/div><\/div>\n    <div class=\"function\"><h4>chr$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>chr$(code)<\/code><\/div><p>Creates a one-character string from a byte value.<\/p><pre><code>let retstr$ = chr$(65);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> One character.<\/div><\/div>\n    <div class=\"function\"><h4>asc <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>asc(text$)<\/code><\/div><p>Reads the byte value of the first character.<\/p><pre><code>retval = asc(\"A\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Byte code, or 0 for an empty string.<\/div><\/div>\n    <div class=\"function\"><h4>str$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>str$(number)<\/code><\/div><p>Converts a number to compact text.<\/p><pre><code>let retstr$ = str$(12.5);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Numeric text.<\/div><\/div>\n    <div class=\"function\"><h4>val <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>val(text$)<\/code><\/div><p>Parses a leading decimal floating-point number.<\/p><pre><code>retval = val(\"12.5 volts\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Parsed number, or 0 if parsing cannot begin.<\/div><\/div>\n    <div class=\"function\"><h4>instr <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>instr(text$, find$)<\/code> or <code>instr(start, text$, find$)<\/code><\/div><p>Searches for text, optionally beginning at a 1-based position.<\/p><pre><code>retval = instr(\"B9X Basic\", \"Basic\");\nretval = instr(6, \"banana\", \"a\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 1-based match position, or 0 when not found.<\/div><\/div>\n  <\/section>\n\n  <section id=\"format-time\">\n    <h2>7. Formatting and time<\/h2>\n    <div class=\"function\"><h4>fmt$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>fmt$(number, format$)<\/code><\/div><p>Formats a number. Tokens include <code>0<\/code> required digit, <code>#<\/code> optional digit, decimal point, comma grouping, percent, sign, scientific notation and positive;negative;zero sections.<\/p><pre><code>let retstr$ = fmt$(1234.5, \"#,##0.00\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Formatted string.<\/div><\/div>\n    <table><thead><tr><th>Function<\/th><th>Example<\/th><th>Return<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>hour()<\/code><\/td><td><code>retval = hour();<\/code><\/td><td>0\u201323<\/td><\/tr>\n      <tr><td><code>minute()<\/code><\/td><td><code>retval = minute();<\/code><\/td><td>0\u201359<\/td><\/tr>\n      <tr><td><code>second()<\/code><\/td><td><code>retval = second();<\/code><\/td><td>0\u201359<\/td><\/tr>\n      <tr><td><code>month()<\/code><\/td><td><code>retval = month();<\/code><\/td><td>1\u201312<\/td><\/tr>\n      <tr><td><code>day()<\/code><\/td><td><code>retval = day();<\/code><\/td><td>Day of month<\/td><\/tr>\n      <tr><td><code>year()<\/code><\/td><td><code>retval = year();<\/code><\/td><td>Four-digit year<\/td><\/tr>\n    <\/tbody><\/table>\n  <\/section>\n\n  <section id=\"math\">\n    <h2>8. Mathematics<\/h2>\n    <p>All functions in this table return a double and therefore must be assigned.<\/p>\n    <table><thead><tr><th>Function<\/th><th>Description<\/th><th>Correct example<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>abs(x)<\/code><\/td><td>Absolute value.<\/td><td><code>retval = abs(-3.5);<\/code><\/td><\/tr>\n      <tr><td><code>min(a,b)<\/code><\/td><td>Smaller argument.<\/td><td><code>retval = min(4,9);<\/code><\/td><\/tr>\n      <tr><td><code>max(a,b)<\/code><\/td><td>Larger argument.<\/td><td><code>retval = max(4,9);<\/code><\/td><\/tr>\n      <tr><td><code>round(x)<\/code><\/td><td>Nearest integral value.<\/td><td><code>retval = round(2.6);<\/code><\/td><\/tr>\n      <tr><td><code>sqrt(x)<\/code><\/td><td>Square root.<\/td><td><code>retval = sqrt(81);<\/code><\/td><\/tr>\n      <tr><td><code>exp(x)<\/code><\/td><td><em>e<\/em> raised to x.<\/td><td><code>retval = exp(1);<\/code><\/td><\/tr>\n      <tr><td><code>log(x)<\/code><\/td><td>Natural logarithm.<\/td><td><code>retval = log(2.71828);<\/code><\/td><\/tr>\n      <tr><td><code>log10(x)<\/code><\/td><td>Base-10 logarithm.<\/td><td><code>retval = log10(1000);<\/code><\/td><\/tr>\n      <tr><td><code>sin(radians)<\/code><\/td><td>Sine.<\/td><td><code>retval = sin(0);<\/code><\/td><\/tr>\n      <tr><td><code>cos(radians)<\/code><\/td><td>Cosine.<\/td><td><code>retval = cos(0);<\/code><\/td><\/tr>\n      <tr><td><code>tan(radians)<\/code><\/td><td>Tangent.<\/td><td><code>retval = tan(0);<\/code><\/td><\/tr>\n      <tr><td><code>asin(x)<\/code><\/td><td>Inverse sine in radians.<\/td><td><code>retval = asin(1);<\/code><\/td><\/tr>\n      <tr><td><code>acos(x)<\/code><\/td><td>Inverse cosine in radians.<\/td><td><code>retval = acos(1);<\/code><\/td><\/tr>\n      <tr><td><code>atan(x)<\/code><\/td><td>Inverse tangent in radians.<\/td><td><code>retval = atan(1);<\/code><\/td><\/tr>\n      <tr><td><code>sinh(x)<\/code><\/td><td>Hyperbolic sine.<\/td><td><code>retval = sinh(0);<\/code><\/td><\/tr>\n      <tr><td><code>cosh(x)<\/code><\/td><td>Hyperbolic cosine.<\/td><td><code>retval = cosh(0);<\/code><\/td><\/tr>\n      <tr><td><code>rnd(min,max)<\/code><\/td><td>Random integer in the inclusive range.<\/td><td><code>retval = rnd(1,6);<\/code><\/td><\/tr>\n      <tr><td><code>modulo(a,b)<\/code><\/td><td>Integer remainder after truncation. Divisor cannot be zero.<\/td><td><code>retval = modulo(17,5);<\/code><\/td><\/tr>\n    <\/tbody><\/table>\n  <\/section>\n\n  <section id=\"system\">\n    <h2>9. System, Wi-Fi and nonvolatile storage<\/h2>\n    <div class=\"function\"><h4>wifiIsConnected <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>wifiIsConnected()<\/code><\/div><p>Checks the current Wi-Fi connection state.<\/p><pre><code>retval = wifiIsConnected();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Nonzero when connected; 0 when disconnected.<\/div><\/div>\n    <div class=\"function\"><h4>memx <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>memx()<\/code><\/div><p>Reads free 8-bit-capable heap memory.<\/p><pre><code>retval = memx();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Available bytes.<\/div><\/div>\n    <div class=\"function\"><h4>setNVS <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>setNVS(name$, value$)<\/code><\/div><p>Saves a string under a named key in nonvolatile flash storage.<\/p><pre><code>retval = setNVS(\"station\", \"workbench\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Storage operation result.<\/div><\/div>\n    <div class=\"function\"><h4>getNVS$ <span class=\"tag\">string<\/span><\/h4><div class=\"sig\"><code>getNVS$(name$)<\/code><\/div><p>Retrieves a previously stored NVS string.<\/p><pre><code>let retstr$ = getNVS$(\"station\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Stored text, or an empty string when unavailable.<\/div><\/div>\n  <\/section>\n\n  <section id=\"gpio\">\n    <h2>10. GPIO, timing, ADC and temperature<\/h2>\n    <table><thead><tr><th>Function<\/th><th>Description<\/th><th>Correct example<\/th><th>Return<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>wait(ms)<\/code><\/td><td>Delays the B9X program while background tasks continue.<\/td><td><code>retval = wait(250);<\/code><\/td><td>Supplied delay<\/td><\/tr>\n      <tr><td><code>getTicks(mode)<\/code><\/td><td>Mode 0 seconds, 1 milliseconds, 2 microseconds.<\/td><td><code>retval = getTicks(1);<\/code><\/td><td>Elapsed time<\/td><\/tr>\n      <tr><td><code>makeInput(gpio)<\/code><\/td><td>Input with internal pulldown.<\/td><td><code>retval = makeInput(4);<\/code><\/td><td>GPIO argument<\/td><\/tr>\n      <tr><td><code>getInput(gpio)<\/code><\/td><td>Reads a digital input.<\/td><td><code>retval = getInput(4);<\/code><\/td><td>0 or 1<\/td><\/tr>\n      <tr><td><code>makeOutput(gpio)<\/code><\/td><td>Configures a digital output.<\/td><td><code>retval = makeOutput(2);<\/code><\/td><td>GPIO argument<\/td><\/tr>\n      <tr><td><code>setHigh(gpio)<\/code><\/td><td>Sets an output high.<\/td><td><code>retval = setHigh(2);<\/code><\/td><td>GPIO argument<\/td><\/tr>\n      <tr><td><code>setLow(gpio)<\/code><\/td><td>Sets an output low.<\/td><td><code>retval = setLow(2);<\/code><\/td><td>GPIO argument<\/td><\/tr>\n      <tr><td><code>initADC()<\/code><\/td><td>Initializes the ADC.<\/td><td><code>retval = initADC();<\/code><\/td><td>1<\/td><\/tr>\n      <tr><td><code>readADCRaw(channel)<\/code><\/td><td>Reads a raw ADC conversion.<\/td><td><code>retval = readADCRaw(3);<\/code><\/td><td>Raw count<\/td><\/tr>\n      <tr><td><code>readADCMV(channel)<\/code><\/td><td>Reads calibrated millivolts.<\/td><td><code>retval = readADCMV(3);<\/code><\/td><td>Millivolts<\/td><\/tr>\n      <tr><td><code>deinitADC()<\/code><\/td><td>Releases the ADC.<\/td><td><code>retval = deinitADC();<\/code><\/td><td>1<\/td><\/tr>\n      <tr><td><code>readTemperature(gpio)<\/code><\/td><td>Reads a DS18B20 sensor.<\/td><td><code>retval = readTemperature(18);<\/code><\/td><td>Degrees Celsius<\/td><\/tr>\n    <\/tbody><\/table>\n  <\/section>\n\n  <section id=\"display-audio\">\n    <h2>11. Display, motion, WAV and local TTS<\/h2>\n    <table><thead><tr><th>Function<\/th><th>Description<\/th><th>Correct example<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>displayInit(sda,scl)<\/code><\/td><td>Initializes a 128\u00d764 SSD1306 OLED at address 0x3C.<\/td><td><code>retval = displayInit(8,9);<\/code><\/td><\/tr>\n      <tr><td><code>displayText(text$)<\/code><\/td><td>Displays text; <code>~<\/code> ends each display line.<\/td><td><code>retval = displayText(\"B9X~ready~\");<\/code><\/td><\/tr>\n      <tr><td><code>motionInit(port,tx_gpio)<\/code><\/td><td>Initializes the supported motion-distance sensor.<\/td><td><code>retval = motionInit(1,17);<\/code><\/td><\/tr>\n      <tr><td><code>motionGetDistance()<\/code><\/td><td>Reads the latest distance.<\/td><td><code>retval = motionGetDistance();<\/code><\/td><\/tr>\n      <tr><td><code>playInit(bclk,ws,data)<\/code><\/td><td>Initializes WAV output.<\/td><td><code>retval = playInit(5,4,6);<\/code><\/td><\/tr>\n      <tr><td><code>play(filename$)<\/code><\/td><td>Starts a WAV file from SPIFFS. Supply the filename relative to <code>\/spiffs\/<\/code>.<\/td><td><code>retval = play(\"alert.wav\");<\/code><\/td><\/tr>\n      <tr><td><code>isPlaying()<\/code><\/td><td>Checks WAV playback.<\/td><td><code>retval = isPlaying();<\/code><\/td><\/tr>\n      <tr><td><code>ttsInit(port,busy,tx,rx)<\/code><\/td><td>Initializes a local SYN6988 speech module.<\/td><td><code>retval = ttsInit(1,7,17,18);<\/code><\/td><\/tr>\n      <tr><td><code>ttsIsBusy()<\/code><\/td><td>Checks local speech activity.<\/td><td><code>retval = ttsIsBusy();<\/code><\/td><\/tr>\n      <tr><td><code>ttsSpeak(text$)<\/code><\/td><td>Submits text to the local speech module.<\/td><td><code>retval = ttsSpeak(\"System ready.\");<\/code><\/td><\/tr>\n    <\/tbody><\/table>\n    <p>WAV playback supports uncompressed 44.1 kHz, 16-bit stereo PCM WAV files.<\/p>\n  <\/section>\n\n  <section id=\"openai\">\n    <h2>12. OpenAI text, transcription and TTS<\/h2>\n    <div class=\"callout good\"><strong>Nonblocking operation:<\/strong> submit each request once, then poll its result with a short delay. Do not submit the request on every loop pass.<\/div>\n    <table><thead><tr><th>Function<\/th><th>Description<\/th><th>Correct example<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>oaixInit(api_key$)<\/code><\/td><td>Initializes OpenAI text questions.<\/td><td><code>retval = oaixInit(b9x_key1$);<\/code><\/td><\/tr>\n      <tr><td><code>oaixAskQuestion(id,question$)<\/code><\/td><td>Queues a question with an application-defined request ID.<\/td><td><code>retval = oaixAskQuestion(1,\"Name one moon of Mars.\");<\/code><\/td><\/tr>\n      <tr><td><code>oaixGetAnswer$()<\/code><\/td><td>Polls the next answer.<\/td><td><code>let retstr$ = oaixGetAnswer$();<\/code><\/td><\/tr>\n      <tr><td><code>vrxInit(bclk,ws,data,seconds,key$)<\/code><\/td><td>Initializes INMP441 recording and transcription.<\/td><td><code>retval = vrxInit(4,5,6,5,b9x_key1$);<\/code><\/td><\/tr>\n      <tr><td><code>vrxTranscribe(id)<\/code><\/td><td>Queues one record-and-transcribe operation.<\/td><td><code>retval = vrxTranscribe(100);<\/code><\/td><\/tr>\n      <tr><td><code>vrxGetTranscript$()<\/code><\/td><td>Polls the next completed transcript.<\/td><td><code>let retstr$ = vrxGetTranscript$();<\/code><\/td><\/tr>\n      <tr><td><code>ttsxInit(bclk,ws,data,key$,voice$,style$)<\/code><\/td><td>Initializes OpenAI speech and PCM5102 output.<\/td><td><code>retval = ttsxInit(15,16,17,b9x_key1$,\"marin\",\"Speak clearly.\");<\/code><\/td><\/tr>\n      <tr><td><code>ttsxSpeak(text$)<\/code><\/td><td>Queues up to 255 characters for synthesis and playback.<\/td><td><code>retval = ttsxSpeak(\"Hello from B9X.\");<\/code><\/td><\/tr>\n    <\/tbody><\/table>\n    <p>Answer and transcript polling functions return an empty string while no result is ready. A 401 response normally means the API key is invalid.<\/p>\n  <\/section>\n\n  <section id=\"voip\">\n    <h2>13. B9X Voice Server VoIP<\/h2>\n    <div class=\"callout voice\">\n      <p>The VoIP functions connect an ESP32-S3 with an INMP441 microphone and PCM5102 audio output to <a href=\"https:\/\/b9xelectronics.com\/?page_id=144\">B9X Voice Server<\/a>. The server provides low-latency group voice communication between embedded nodes, Windows clients and Android clients.<\/p>\n      <p>B9X Basic v1.03 uses 11,025 Hz audio, UDP port 24000 locally, encrypted audio and periodic keep-alive messages.<\/p>\n    <\/div>\n    <div class=\"function\"><h4>voipInit <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipInit(tx_bclk, tx_ws, tx_data, rx_bclk, rx_ws, rx_data)<\/code><\/div><p>Initializes PCM5102 output using the first three pins and INMP441 input using the final three pins. The INMP441 L\/R pin is expected low for the left slot.<\/p><pre><code>retval = voipInit(15, 16, 17, 4, 5, 6);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or an ESP-IDF error code.<\/div><\/div>\n    <div class=\"function\"><h4>voipConnect <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipConnect(server$, port, password$, node_name$, encryption_key$)<\/code><\/div><p>Copies the connection settings, resolves the server and begins an asynchronous connection. The encryption key must match the B9X Voice Server configuration and should contain exactly 32 characters.<\/p><pre><code>let server$ = \"192.168.1.100\";\nserverPort = 18000;\nlet password$ = \"serverPassword\";\nlet nodeName$ = \"Workshop ESP32\";\nlet encryptionKey$ = b9x_key2$;\n\nretval = voipConnect(server$, serverPort, password$, nodeName$, encryptionKey$);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 when the connection command is sent successfully; otherwise an ESP-IDF error code. Use <code>voipIsConnected()<\/code> to confirm completion.<\/div><\/div>\n    <div class=\"function\"><h4>voipIsConnected <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipIsConnected()<\/code><\/div><p>Checks whether the B9X Voice Server connection is active.<\/p><pre><code>retval = voipIsConnected();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 1 when connected; 0 otherwise.<\/div><\/div>\n    <div class=\"function\"><h4>voipStartListening <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipStartListening()<\/code><\/div><p>Starts nonblocking reception and PCM5102 playback of audio sent by other clients.<\/p><pre><code>retval = voipStartListening();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or an ESP-IDF error code.<\/div><\/div>\n    <div class=\"function\"><h4>voipHaltListening <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipHaltListening()<\/code><\/div><p>Stops received-audio playback and releases the transmit I\u00b2S channel.<\/p><pre><code>retval = voipHaltListening();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or an ESP-IDF error code.<\/div><\/div>\n    <div class=\"function\"><h4>voipStartSending <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipStartSending()<\/code><\/div><p>Starts nonblocking INMP441 capture and sends microphone audio to connected clients through the server.<\/p><pre><code>retval = voipStartSending();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or an ESP-IDF error code.<\/div><\/div>\n    <div class=\"function\"><h4>voipHaltSending <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipHaltSending()<\/code><\/div><p>Stops microphone transmission and releases the receive I\u00b2S channel.<\/p><pre><code>retval = voipHaltSending();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or an ESP-IDF error code.<\/div><\/div>\n    <div class=\"function\"><h4>voipIsSending <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipIsSending()<\/code><\/div><p>Checks whether microphone transmission is active.<\/p><pre><code>retval = voipIsSending();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 1 while sending; 0 otherwise.<\/div><\/div>\n    <div class=\"function\"><h4>voipClose <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>voipClose()<\/code><\/div><p>Sends the close command, stops both audio directions and closes the server session.<\/p><pre><code>retval = voipClose();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or an ESP-IDF error code.<\/div><\/div>\n    <h3>Complete push-to-talk pattern<\/h3>\n<pre><code>retval = voipInit(15, 16, 17, 4, 5, 6);\nretval = voipConnect(\"192.168.1.100\", 18000, \"password\", \"B9X Node\", b9x_key2$);\n\n' Wait for asynchronous connection\nconnected = 0;\nwhile connected == 0 do\n    connected = voipIsConnected();\n    retval = wait(100);\nwend\n\n' Listen initially\nretval = voipStartListening();\n\n' Begin push-to-talk\nretval = voipHaltListening();\nretval = voipStartSending();\n\n' End push-to-talk\nretval = voipHaltSending();\nretval = voipStartListening();<\/code><\/pre>\n    <div class=\"callout critical\"><strong>Audio resource rule:<\/strong> VoIP listening and OpenAI TTS both use the PCM5102\/I\u00b2S output. Stop VoIP listening before TTS playback. VoIP sending and voice recognition both use the INMP441\/I\u00b2S input. Stop VoIP sending before starting transcription. Listening and sending may be initialized together, but conflicting operations must not actively own the same I\u00b2S direction simultaneously.<\/div>\n  <\/section>\n\n  <section id=\"infrared\">\n    <h2>14. Infrared remote control<\/h2>\n    <div class=\"function\"><h4>irInit <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>irInit(gpio)<\/code><\/div><p>Starts nonblocking reception using a demodulated 38 kHz IR receiver. Common formats include Sony\/SIRC.<\/p><pre><code>retval = irInit(15);<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 1 after startup.<\/div><\/div>\n    <div class=\"function\"><h4>irGetCode <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>irGetCode()<\/code><\/div><p>Polls immediately for an event with confidence above 90.<\/p><pre><code>retval = irGetCode();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Decoded command, or -1 when none is ready.<\/div><\/div>\n  <\/section>\n\n  <section id=\"leds\">\n    <h2>15. WS2812 addressable LEDs<\/h2>\n    <table><thead><tr><th>Function<\/th><th>Description<\/th><th>Correct example<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>ws2812Init(gpio,count)<\/code><\/td><td>Creates a strip and returns its handle.<\/td><td><code>strip = ws2812Init(48,8);<\/code><\/td><\/tr>\n      <tr><td><code>ws2812Fill(handle,r,g,b)<\/code><\/td><td>Sets all pixels in the local buffer.<\/td><td><code>retval = ws2812Fill(strip,0,0,32);<\/code><\/td><\/tr>\n      <tr><td><code>ws2812SetPixel(handle,index,r,g,b)<\/code><\/td><td>Sets one zero-based pixel.<\/td><td><code>retval = ws2812SetPixel(strip,0,32,0,0);<\/code><\/td><\/tr>\n      <tr><td><code>ws2812Show(handle)<\/code><\/td><td>Transmits buffered colors.<\/td><td><code>retval = ws2812Show(strip);<\/code><\/td><\/tr>\n      <tr><td><code>ws2812Clear(handle)<\/code><\/td><td>Turns all pixels off.<\/td><td><code>retval = ws2812Clear(strip);<\/code><\/td><\/tr>\n      <tr><td><code>ws2812IsBusy(handle)<\/code><\/td><td>Checks strip transmission.<\/td><td><code>retval = ws2812IsBusy(strip);<\/code><\/td><\/tr>\n    <\/tbody><\/table>\n    <p>Color-changing functions return 0 on success or an error code. <code>ws2812IsBusy<\/code> returns nonzero while transmission is active.<\/p>\n  <\/section>\n\n  <section id=\"mqtt\">\n    <h2>16. MQTT<\/h2>\n    <table><thead><tr><th>Function<\/th><th>Description<\/th><th>Correct example<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>initMQTTClient(uri$,user$,password$)<\/code><\/td><td>Starts an MQTT client.<\/td><td><code>retval = initMQTTClient(\"mqtt:\/\/broker.local\",\"user\",\"password\");<\/code><\/td><\/tr>\n      <tr><td><code>mqttClientSubscribe(topic$)<\/code><\/td><td>Subscribes at QoS 0.<\/td><td><code>retval = mqttClientSubscribe(\"b9x\/input\");<\/code><\/td><\/tr>\n      <tr><td><code>mqttClientUnsubscribe(topic$)<\/code><\/td><td>Removes a subscription.<\/td><td><code>retval = mqttClientUnsubscribe(\"b9x\/input\");<\/code><\/td><\/tr>\n      <tr><td><code>mqttClientPublish(topic$,payload$)<\/code><\/td><td>Publishes at QoS 1, retain disabled.<\/td><td><code>retval = mqttClientPublish(\"b9x\/status\",\"ready\");<\/code><\/td><\/tr>\n      <tr><td><code>mqttClientGetMessage$()<\/code><\/td><td>Polls one queued MQTT event.<\/td><td><code>let retstr$ = mqttClientGetMessage$();<\/code><\/td><\/tr>\n    <\/tbody><\/table>\n    <p>Numeric operations return a message identifier or error value. The polling function returns an empty string when nothing is ready, otherwise <code>[TYPE][id][topic][data]<\/code>. Event types include DATA, CONNECT, DISCONNECT, SUBSCRIBED, UNSUBSCRIBED, PUBLISHED and ERROR.<\/p>\n  <\/section>\n\n  <section id=\"files\">\n    <h2>17. File logging and reset information<\/h2>\n    <div class=\"function\"><h4>logData <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>logData(filename$, text$)<\/code><\/div><p>Appends one text line to a file. Supply a filename relative to the configured filesystem root.<\/p><pre><code>retval = logData(\"data.csv\", \"72.5,Running\");<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> 0 on success or a filesystem error code.<\/div><\/div>\n    <div class=\"function\"><h4>getResetType <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>getResetType()<\/code><\/div><p>Reads the reset-type value captured when the runtime started.<\/p><pre><code>retval = getResetType();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> Numeric reset reason\/type.<\/div><\/div>\n    <div class=\"function\"><h4>restart <span class=\"tag\">double<\/span><\/h4><div class=\"sig\"><code>restart()<\/code><\/div><p>Immediately restarts the ESP32.<\/p><pre><code>retval = restart();<\/code><\/pre><div class=\"returns\"><strong>Returns:<\/strong> The function normally does not return because the device restarts.<\/div><\/div>\n  <\/section>\n\n  <section id=\"templates\">\n    <h2>18. Supplied user-function templates<\/h2>\n    <p>These functions demonstrate adding native C functions with numeric, string and mixed argument types.<\/p>\n    <table><thead><tr><th>Function<\/th><th>Correct example<\/th><th>Return<\/th><\/tr><\/thead><tbody>\n      <tr><td><code>user1(x)<\/code><\/td><td><code>retval = user1(10);<\/code><\/td><td><code>x * 2<\/code><\/td><\/tr>\n      <tr><td><code>user2(a,b)<\/code><\/td><td><code>retval = user2(10,20);<\/code><\/td><td><code>a + b<\/code><\/td><\/tr>\n      <tr><td><code>usermix(text$,number)<\/code><\/td><td><code>retval = usermix(\"ABC\",10);<\/code><\/td><td>Number plus text length<\/td><\/tr>\n      <tr><td><code>usermix$(text$,number)<\/code><\/td><td><code>let retstr$ = usermix$(\"ABC\",10);<\/code><\/td><td>Text, space and number<\/td><\/tr>\n    <\/tbody><\/table>\n  <\/section>\n\n  <section id=\"keys\">\n    <h2>19. Protected key variables<\/h2>\n    <p>B9X Basic supplies five protected string variables for passwords, API keys and encryption keys:<\/p>\n<pre><code>b9x_key1$\nb9x_key2$\nb9x_key3$\nb9x_key4$\nb9x_key5$<\/code><\/pre>\n    <p>Each holds up to 512 characters and can be passed to OpenAI, MQTT, NVS or VoIP functions. Values may be updated through the setup menu without displaying the current value. For B9X Voice Server, store the 32-character AES key in one protected variable instead of embedding it in a shared BASIC program.<\/p>\n  <\/section>\n\n  <section id=\"patterns\">\n    <h2>20. Complete programming patterns<\/h2>\n    <h3>Safe polling pattern<\/h3>\n<pre><code>retval = oaixInit(b9x_key1$);\nretval = oaixAskQuestion(1, \"Give one short electronics fact.\");\nlet answer$ = \"\";\n\nanswerLength = len(answer$);\nwhile answerLength == 0 do\n    let answer$ = oaixGetAnswer$();\n    retval = wait(50);\n    answerLength = len(answer$);\nwend\n\nprint answer$;<\/code><\/pre>\n    <h3>GPIO debounce<\/h3>\n<pre><code>retval = makeInput(4);\nlast = getInput(4);\n\nwhile 1 do\n    current = getInput(4);\n    if current != last then\n        retval = wait(20);\n        current = getInput(4);\n        if current != last then\n            print current;\n            last = current;\n        endif\n    endif\n    retval = wait(5);\nwend<\/code><\/pre>\n    <h3>Common mistakes<\/h3>\n    <table><thead><tr><th>Symptom<\/th><th>Likely cause<\/th><th>Correction<\/th><\/tr><\/thead><tbody>\n      <tr><td>Compile error at a function call<\/td><td>Return value was discarded.<\/td><td>Use <code>retval = function();<\/code> or <code>let retstr$ = function$();<\/code>.<\/td><\/tr>\n      <tr><td>String assignment error<\/td><td><code>LET<\/code> omitted.<\/td><td>Write <code>let name$ = expression;<\/code>.<\/td><\/tr>\n      <tr><td>Comparison behaves incorrectly<\/td><td>Used <code>=<\/code> instead of <code>==<\/code>.<\/td><td>Use <code>==<\/code> for equality.<\/td><\/tr>\n      <tr><td>Repeated requests or speech<\/td><td>Queue function called every loop iteration.<\/td><td>Submit once and poll separately.<\/td><\/tr>\n      <tr><td>Empty asynchronous result<\/td><td>Work has not completed.<\/td><td>Poll with a short delay.<\/td><\/tr>\n      <tr><td>I\u00b2S controller busy<\/td><td>Two features own the same audio direction.<\/td><td>Stop the current VoIP\/TTS\/VR operation before starting the conflicting feature.<\/td><\/tr>\n      <tr><td>VoIP never connects<\/td><td>Wrong server address, port, password\/key, Wi-Fi state or blocked UDP.<\/td><td>Confirm Wi-Fi, server port 18000 unless changed, matching 32-character key and firewall forwarding.<\/td><\/tr>\n    <\/tbody><\/table>\n  <\/section>\n\n  <section id=\"limits\">\n    <h2>Appendix: limits and quick reference<\/h2>\n    <table><thead><tr><th>Language item<\/th><th>Maximum<\/th><\/tr><\/thead><tbody>\n      <tr><td>String value<\/td><td>512 characters<\/td><\/tr>\n      <tr><td>Identifier<\/td><td>31 characters<\/td><\/tr>\n      <tr><td>Numeric arrays<\/td><td>64<\/td><\/tr>\n      <tr><td>Elements per numeric array<\/td><td>1024; indices 0\u20131023<\/td><\/tr>\n      <tr><td>User FUNCTION definitions<\/td><td>64<\/td><\/tr>\n      <tr><td>User FUNCTION parameters<\/td><td>8<\/td><\/tr>\n      <tr><td>OpenAI TTS message<\/td><td>255 characters per submission<\/td><\/tr>\n    <\/tbody><\/table>\n<pre><code>' Numeric assignment\nname = expression;\nlet name = expression;\n\n' String assignment\nlet name$ = string_expression;\n\n' Function results\nretval = numericFunction(arguments);\nlet retstr$ = stringFunction$(arguments);\n\n' Array\ndim values[9];\nvalues[index] = expression;\n\n' Control flow\nif expression then ... else ... endif\nwhile expression do ... wend\nfor name = start to limit step amount do ... next\n\n' Procedures and functions\nsub name() ... end sub\ncall name();\nfunction name(parameters) ... return expression; ... end function\nfunction name$(parameters) ... return string_expression; ... end function<\/code><\/pre>\n    <p class=\"top\"><a href=\"#b9x-top\">Return to top \u2191<\/a><\/p>\n  <\/section>\n\n  <div class=\"footer\">B9X Basic v1.03 Language Reference \u00b7 Copyright \u00a9 2026 B9X Electronics \u00b7 All Rights Reserved<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The information provided here by B9X Electronics (&#8216;we,&#8217; &#8216;us,&#8217; or &#8216;our&#8217;), in this document,<br>is for general informational purposes only. All information in this document<br>is provided in good faith, however, we make no representation or warranty of any kind,<br>express or implied, regarding the accuracy, adequacy, validity, reliability, availability,<br>or completeness of any information in this document. Under no circumstance shall we have any liability<br>to you for any loss or damage of any kind incurred as a result of the use of this document<br>or reliance on any information provided in this document.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>B9X Electronics Documentation B9X Basic Language Reference A complete guide to B9X Basic v1.03, including language syntax, variables, control flow, user functions, GPIO, storage, MQTT, audio, OpenAI services and real-time VoIP through B9X Voice Server. Version 1.03 Required function-return syntax Every function returns a value. A numeric\/double-returning function must be used in a numeric assignment. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1282","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=\/wp\/v2\/pages\/1282","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1282"}],"version-history":[{"count":37,"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=\/wp\/v2\/pages\/1282\/revisions"}],"predecessor-version":[{"id":1504,"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=\/wp\/v2\/pages\/1282\/revisions\/1504"}],"wp:attachment":[{"href":"https:\/\/b9xelectronics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}