Error when using Puck.eval in Web Bluetooth

Posted on
  • I have Puck.write working fine but Puck.eval is throwing an error on Chrome on Ubuntu.

    Same error no matter what command I try, even 1+1.

    <button onclick="Puck.eval('1+1;',function(x) { console.log(x); })">Get The Time</button>
    

    This is on 1v92.

    Am I missing something obvious? Thanks!

    Uncaught SyntaxError: Unexpected token U in JSON at position 0
        at JSON.parse (<anonymous>)
        at puck.js:298
        at Object.connection.cb (puck.js:235)
        at Object.ondata (puck.js:272)
        at Object.emit (puck.js:100)
        at BluetoothRemoteGATTCharacteristic.<anony­mous> (puck.js:190)
    
  • Does it work if you do Puck.eval('1+1' - without the semicolon? The idea is it's executed as an expression so a semicolon might confuse matters.

    Looks like the code was causing an exception, the U is probably the U from Uncaught .... I wonder what the best way of reporting that back to the user of the library would be?

  • Aha that's it, thanks Gordon. Working like a charm now for several different expressions. I missed the lack of a semicolon in the example.

  • Not sure what the best way to report that back to users is.

  • I'd recommend to catch the syntax error and output the input that caused the syntax error?
    In this case the targets error message.

  • I've hit that problem a few times. e.g. right now one of my Puck.write() calls is working but when I follow it with a Puck.eval(), it throws a JSON error which turns out to be due to trying to parse

    Bluetooth.println(JSON.stringify(new Date().toString()))
    

    Still trying to figure out what interaction of write() and eval() is causing that to appear as the response to eval(). Doing two eval() in a row is fine. And if I do write(), eval(), eval(), the second eval() is fine so write() is causing some issue.

    <html>
     <head>
     </head>
     <body>
      <script src="https://www.puck-js.com/puck.js"></­script>
      <script>
          var d = new Date();
          var n = Math.round(d.getTime()/1000);
          var puckCommand = "setTime(" + n + ")\\n";
          console.log(puckCommand);
      </script>
      <button onclick="Puck.write(puckCommand);">Set The Time</button>
      <button onclick="Puck.eval('new Date().toString()',function(x) { console.log(x); })">Get The Time</button>
       </body>
    </html>
    
    
  • The issue is the Puck.write call generates some output on the Puck. Then when eval is called, it receives whatever Puck.write output instead - I guess 'Puck.eval' could prefix the output with something - that would help to differentiate it from the output of write.

    One option is to temporarily turn off the console output (echo) for the line you write - try puckCommand = "\x10setTime(" + n + ")\\n" and I imagine that'll fix it (it's just sending char code 16 at the start of the line)

  • What does the char code do? Disable echo?

    I'm getting a different error now:

    Uncaught SyntaxError: Got '\' expected EOF
    
  • Yes, char code 16 right on the start of a line disables echo for just that line.

    Is it possible that you somehow ended up sending the characters \x10 and not the single character code 16? You could try String.fromCharCode(16)+ but I'd have thought the code I posted should work.

  • Still no joy. Same error which is very weird.

  • Do you have your Web Bluetooth page hosted online somewhere that I could take a look at?

    I just went to https://www.espruino.com/try.php?page=Pu­ck.js+Web+Bluetooth&n=0, clicked some buttons to get it connected, opened devtools, and then started typing.

    Puck.write('LED1.set();\n');
    Puck.write('\x10LED1.reset();\n');
    // both work
    Puck.write('LED1.set();\n');Puck.eval("B­TN.read()",function(x) { console.log(x); })
    // fails - as expected
    Puck.write('\x10LED1.set();\n');Puck.eva­l("BTN.read()",function(x) { console.log(x); })
    // works fine
    
  • Hmm. Typing that in the devtools console works for me too. I must be missing something very obvious.

    Code is on: https://conorpuckjs.now.sh/web_bluetooth­_set_time.html

  • So I can replicate the write/eval error in devtools console when \x10 is excluded. But when I include it, it works, as you predicted. So I'm clueless as to why it's not working in the code on the page.

  • Is it this bit that's not working?

    <button onclick="Puck.write('\x10setTime(1234578­9);\\n')">Set The Time with x10</button>
    

    I think it's to do with escaping in HTML, because you're in a string inside a string - note you have to do \\n for newline, not \n - maybe just doing \\x10 would fix it?

    ... and your puckCommand example wouldn't work, but for the other reason! Try changing \\n to \n in that one!

  • So the bad news is that \x10 or even \\x10 doesn't work (I've tried so many variations around that). The good news is that changing \n to \n in puckCommand solves the overall problem and eval() happily runs now after write(). Thanks for all the help!

  • In the <button line? The normal \x10 in the puckCommand line itself is totally fine though.

  • The final working code was:

    <html>
     <head>
     </head>
     <body>
      <script src="https://www.puck-js.com/puck.js"></­script>
      <script>
          var d = new Date();
          var n = Math.round(d.getTime()/1000);
          var puckCommand = String.fromCharCode(16)+"setTime(" + n + ")\n";
      </script>
       <button onclick="Puck.write(puckCommand);">Set The Time</button>
       <button onclick="Puck.eval('new Date().toString()',function(x) { console.log(x); })">Get The Time</button>
       </body>
    </html>
    

    I never got \x10 working in the code. As you said, there must be some HTML escaping going on somewhere.

  • I've now added some queueing functionality to the puck.js file at https://espruino.github.io/js/puck.js

    Please could you give it a go? You should now be able to call Puck.write and eval right after each other, and it'll queue the eval until the write has finished.

    It'll be a little slower since it waits to receive all of the data from the Puck.write command before executing whatever is next, but I think that's probably worth it. For high speed stuff you can still use Puck.connect.

  • Yup, that worked perfectly. Even with

    Puck.write(puckCommand);Puck.eval('new Date().toString()',function(x) { console.log(x); })
    

    Thanks!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Error when using Puck.eval in Web Bluetooth

Posted by Avatar for ConorONeill @ConorONeill

Actions