Shop OBEX P1 Docs P2 Docs Learn Events
A Propeller-WebTool Framework for Compiled Languages? - Page 2 — Parallax Forums

A Propeller-WebTool Framework for Compiled Languages?

2456721

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-29 12:44
    jazzed wrote:
    Since we have some feasibility, this is probably a good time to write a Product Requirements Document.
    I think it's a little early for that, Steve. There's still ample room for toying with alternate possibilities (e.g. Google ChromeApps) before fencing anyone in with Requirements.

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 12:51
    Heater, the attached openspin.js is from Dec 28 11:43AM PST or 7:43PM UTC.

    Regarding loading from Propeller SD Card: One of my original plans was to "host" all necessary files on an SD Card that shipped with Propeller and let Propeller be the server. I would still like to do that because it offers certain autonomy in the case of the XBee ActivityBot-Wifi for example and does not unnecessarily burden some central server. It makes more sense now to split some tasks. That is, "host" the compiler(s) on the PC or some remote server, and allow the Propeller or other server connected to Propeller USB to "host" the serial terminal and loader. What would be the operation of a split model?

    A split file hosting model for Wifi enabled Propeller or Network virtual serial port Propeller. This model depends on how big the loader and terminal are.

    attachment.php?attachmentid=105809&d=1388350072
    601 x 312 - 35K
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 12:58
    I think it's a little early for that, Steve. There's still ample room for toying with alternate possibilities (e.g. Google ChromeApps) before fencing anyone in with Requirements.

    -Phil

    Sorry Phil, I should have said "Preliminary" .... Please consider it a living document.

    What I wrote is for communicating ideas. I'm looking for enhancements from contributors.

    If you don't have a clue where you're going, you will never get there.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-12-29 13:04
    ChromeApps look interesting. I don't think Steve's requirements have locked into a technology or eliminated any viable web solution. HTML5, Javascript, etc. Are all going to play a part and at this point only proof of concept work and examples have been provided. A ChromeApp may be the best container and delivery method and shouldn't be ruled out. AngularJS is a very powerful enhancement to HTML.

    We still need the component pieces proven and developed in their own right: editor, compiler, loader, terminal. All these in a cross platform package.

    Plenty of experimenting to do on all fronts!

    (Time to go read about ChromeApps!)
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 13:25
    Native client (NaCl) and Pinnacle are interesting for multi-platform, but HTML/Javascript have had a very short path to success so far ....
  • Heater.Heater. Posts: 21,230
    edited 2013-12-29 13:53
    Thanks for the backup, sadly it's not the openspin.js that I hacked on but the JS inside openspin,html.

    As far as I know Chrome apps are HTML5 and JavaScript. NaCl and PNaCl are only supported in Chrome so far. Other browser vendores are not so keen on the idea.

    Meanwhile check this out to see what emscripten can do: https://www.youtube.com/watch?v=IXIkTrq3Rgg there are some amazing demos in there.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-29 14:06
    One issue I've come across with HTML-based editors is persistence in the face of closing the tab/window or exiting the browser. I have not found a way to trap the event in time to save existing changes on the server. I believe this is one thing that ChromeApps addresses, since the edited text exists independently from the browser.

    -Phil
  • Cluso99Cluso99 Posts: 18,069
    edited 2013-12-29 14:16
    WTG guys. Amazing progress in such a short time.
  • Heater.Heater. Posts: 21,230
    edited 2013-12-29 14:18
    The browser file system APIs are becoming HTML5 standard. They will be in other browsers soon. This should not stop us proceeding.
    In the mean time one could always blast the files up to wherever the app was served from occasionally.
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 14:47
    This may be the successful openspin.html. It was in my firefox browser which had dbg enabled:
    <!doctype html>
    <html lang="en-us">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Emscripten-Generated Code</title>
        <style>
          .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
          textarea.emscripten { font-family: monospace; width: 80%; }
          div.emscripten { text-align: center; }
          div.emscripten_border { border: 1px solid black; }
          /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
          canvas.emscripten { border: 0px none; }
        </style>
      </head>
      <body>
        <hr/>
        <div class="emscripten" id="status">Downloading...</div>
        <div class="emscripten">
          <progress value="0" max="100" id="progress" hidden=1></progress>  
        </div>
        <div class="emscripten_border">
          <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
        </div>
        <hr/>
        <div class="emscripten">
          <input type="checkbox" id="resize">Resize canvas
          <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
          &nbsp;&nbsp;&nbsp;
          <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
                                                                                    document.getElementById('resize').checked)">
        <input type="button" value="Run" onclick="Module.run()">
        </div>
        
        <hr/>
    <textarea class="emscripten" id="input" rows="20">
    PUB start
        repeat
    </textarea>
        <textarea class="emscripten" id="output" rows="20"></textarea>
        <hr>
        <script type='text/javascript'>
          // connect to canvas
          var Module = {
            arguments: ['-b', 'asset_dir/test.spin'],
    
    
            //noInitialRun : true,
            noExitRuntime : true,
    
    
            preRun: [function(){Module.print('preRun');}
            ],
            postRun: [
                     function(){console.log(FS.stat('asset_dir/test.spin'));},
                     function(){console.log(FS.stat('asset_dir/test.binary'));},
                     function(){
                         var stream = FS.open('asset_dir/test.binary', 'r');
                         var buf = new Uint8Array(1024);
                         var i;
                         var len;
                         var hexstr = "";
                         len = FS.read(stream, buf, 0, 1024, 0);
                         FS.close(stream);
                         for (i = 0; i < len; i += 1) {
                             hexstr = hexstr + buf[i].toString(16) + ' ';
                         }
                         Module.print('');
                         Module.print('This is the output binary:');
                         Module.print(hexstr);
                         //var source = document.getElementById('input').value);
                     }
            ],
            print: (function() {
              var element = document.getElementById('output');
              element.value = ''; // clear browser cache
              return function(text) {
                text = Array.prototype.slice.call(arguments).join(' ');
                // These replacements are necessary if you render to raw HTML
                //text = text.replace(/&/g, "&amp;");
                //text = text.replace(/</g, "&lt;");
                //text = text.replace(/>/g, "&gt;");
                //text = text.replace('\n', '<br>', 'g');
                element.value += text + "\n";
                element.scrollTop = element.scrollHeight; // focus on bottom
              };
            })(),
            printErr: function(text) {
              text = Array.prototype.slice.call(arguments).join(' ');
              if (0) { // XXX disabled for safety typeof dump == 'function') {
                dump(text + '\n'); // fast, straight to the real console
              } else {
                console.log(text);
              }
            },
            canvas: document.getElementById('canvas'),
            setStatus: function(text) {
              if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
              if (text === Module.setStatus.text) return;
              var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
              var now = Date.now();
              if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
              var statusElement = document.getElementById('status');
              var progressElement = document.getElementById('progress');
              if (m) {
                text = m[1];
                progressElement.value = parseInt(m[2])*100;
                progressElement.max = parseInt(m[4])*100;
                progressElement.hidden = false;
              } else {
                progressElement.value = null;
                progressElement.max = null;
                progressElement.hidden = true;
              }
              statusElement.innerHTML = text;
            },
            totalDependencies: 0,
            monitorRunDependencies: function(left) {
              this.totalDependencies = Math.max(this.totalDependencies, left);
              Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
            }
          };
          Module.setStatus('Downloading...');
        </script>
        <script async type="text/javascript" src="openspin.js"></script>
      </body>
    </html>
    
    
    
    <!doctype html>
    <html lang="en-us">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Emscripten-Generated Code</title>
        <style>
          .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
          textarea.emscripten { font-family: monospace; width: 80%; }
          div.emscripten { text-align: center; }
          div.emscripten_border { border: 1px solid black; }
          /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
          canvas.emscripten { border: 0px none; }
        </style>
      </head>
      <body>
        <hr/>
        <div class="emscripten" id="status">Downloading...</div>
        <div class="emscripten">
          <progress value="0" max="100" id="progress" hidden=1></progress>  
        </div>
        <div class="emscripten_border">
          <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
        </div>
        <hr/>
        <div class="emscripten">
          <input type="checkbox" id="resize">Resize canvas
          <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
          &nbsp;&nbsp;&nbsp;
          <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
                                                                                    document.getElementById('resize').checked)">
        <input type="button" value="Run" onclick="Module.run()">
        </div>
        
        <hr/>
    <textarea class="emscripten" id="input" rows="20">
    PUB start
        repeat
    </textarea>
        <textarea class="emscripten" id="output" rows="20"></textarea>
        <hr>
        <script type='text/javascript'>
          // connect to canvas
          var Module = {
            arguments: ['-b', 'asset_dir/test.spin'],
    
            //noInitialRun : true,
            noExitRuntime : true,
    
            preRun: [function(){Module.print('preRun');}
            ],
            postRun: [
                     function(){console.log(FS.stat('asset_dir/test.spin'));},
                     function(){console.log(FS.stat('asset_dir/test.binary'));},
                     function(){
                         var stream = FS.open('asset_dir/test.binary', 'r');
                         var buf = new Uint8Array(1024);
                         var i;
                         var len;
                         var hexstr = "";
                         len = FS.read(stream, buf, 0, 1024, 0);
                         FS.close(stream);
                         for (i = 0; i < len; i += 1) {
                             hexstr = hexstr + buf[i].toString(16) + ' ';
                         }
                         Module.print('');
                         Module.print('This is the output binary:');
                         Module.print(hexstr);
                         //var source = document.getElementById('input').value);
                     }
            ],
            print: (function() {
              var element = document.getElementById('output');
              element.value = ''; // clear browser cache
              return function(text) {
                text = Array.prototype.slice.call(arguments).join(' ');
                // These replacements are necessary if you render to raw HTML
                //text = text.replace(/&/g, "&amp;");
                //text = text.replace(/</g, "&lt;");
                //text = text.replace(/>/g, "&gt;");
                //text = text.replace('\n', '<br>', 'g');
                element.value += text + "\n";
                element.scrollTop = element.scrollHeight; // focus on bottom
              };
            })(),
            printErr: function(text) {
              text = Array.prototype.slice.call(arguments).join(' ');
              if (0) { // XXX disabled for safety typeof dump == 'function') {
                dump(text + '\n'); // fast, straight to the real console
              } else {
                console.log(text);
              }
            },
            canvas: document.getElementById('canvas'),
            setStatus: function(text) {
              if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
              if (text === Module.setStatus.text) return;
              var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
              var now = Date.now();
              if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
              var statusElement = document.getElementById('status');
              var progressElement = document.getElementById('progress');
              if (m) {
                text = m[1];
                progressElement.value = parseInt(m[2])*100;
                progressElement.max = parseInt(m[4])*100;
                progressElement.hidden = false;
              } else {
                progressElement.value = null;
                progressElement.max = null;
                progressElement.hidden = true;
              }
              statusElement.innerHTML = text;
            },
            totalDependencies: 0,
            monitorRunDependencies: function(left) {
              this.totalDependencies = Math.max(this.totalDependencies, left);
              Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
            }
          };
          Module.setStatus('Downloading...');
        </script>
        <script async type="text/javascript" src="openspin.js"></script>
      </body>
    </html>
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-29 15:12
    heater wrote:
    The browser file system APIs are becoming HTML5 standard.
    I don't know that that addresses the issue. In a typical editor, you have what's called a "dirty bit" that gets set whenever a change is made to the text and is cleared when the text is saved. When you attempt to exit the editor with the dirty bit set, you get a dialog box that asks if you want to save the file first. This does not appear to be possible in Javascript. onchange() triggers only when changes are committed, not for every key that's pressed, so it can't be used to set a dirty bit reliably. (It also affects the ability to maintain an undo stack.) And onunload triggers too late to do anything useful.

    -Phil
  • Heater.Heater. Posts: 21,230
    edited 2013-12-29 15:56
    Phil.

    What about this:
    window.onbeforeunload = function(e) {
    return 'You have unsaved changes.';
    };
    Which will pop up a dialog reading: "You have unsaved changes. Are you sure you want to leave this page?" together with the appropriate buttons.

    Should work on all major browsers.

    Not sure about how to set that dirty but yet but it seems it can be done with jQuery easily enough:
    http://stackoverflow.com/questions/12797700/jquery-detect-change-in-input-field
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-29 16:06
    That must be a new event. (It's not in my JS book.) But how do you set the dirty bit to begin with, since onchange() triggers only with "committed" changes, not with every keystroke?

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 16:11
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-29 16:40
    It would have to be filtered to eliminate those keys that don't change the text. But I can still think of exceptions where onkeypress() would generate a false positive for setting the dirty bit. For example,. pressing Backspace in the home position, Delete at the end, or typing, say, an "A" when there's an "A" selected.

    -Phil

    Addendum: 'Just checked these conditions in UltraEdit. It set the dirty bit on all but the Backspace test. So I guess no editor is perfect.
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 17:36
    "Worthy to note, however, is that Opera doesn’t fire the unload event when the browser refreshes the page, or uses the back/forward buttons to browse off of the page (I had no success with the fix posted in the comments on that page). What’s worse, Opera never fires the onbeforeunload event. This creates a serious problem with attempting to save page state prior to a user leaving your page." http://www.zachleat.com/web/dont-let-the-door-hit-you-onunload-and-onbeforeunload
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-29 18:36
    I used to use Opera; I don't any more. I use Firefox, but I see nothing wrong with standardizing on Chrome for this particular app, so long as it's allowed on all platforms, including Apple iDevices. IOW, it doesn't have to be anyone's favorite browser, it just needs to be ubiquitous and uniform across all platforms. I don't think it's necessary that the browser used for viewing the forum or Reddit has to be the same one used for programming Props. It's a separate app, after all.

    -Phil
  • Heater.Heater. Posts: 21,230
    edited 2013-12-29 18:39
    That article is from 2008. Recently the Opera browser switched to using the webkit engine. Same as Safari. So I would expect that to not be a problem now.
  • jazzedjazzed Posts: 11,803
    edited 2013-12-29 19:33
    I used to use Opera; I don't any more. I use Firefox, but I see nothing wrong with standardizing on Chrome for this particular app, so long as it's allowed on all platforms, including Apple iDevices. IOW, it doesn't have to be anyone's favorite browser, it just needs to be ubiquitous and uniform across all platforms. I don't think it's necessary that the browser used for viewing the forum or Reddit has to be the same one used for programming Props. It's a separate app, after all.

    -Phil
    We can say it works best on Chrome; however, it should work to some level on all browsers. Perhaps JQuery should seriously be considered as it handles cross-browser issues. It also has some wonderful shrimpz-perl-like syntax that you will love.

    Heater, thanks for pointing out the age of the article. I was just trying to understand where the problem originated.
  • Heater.Heater. Posts: 21,230
    edited 2013-12-30 00:41
    I just woke up with an idea about how to solve the editor "dirty bit" problem.
    Why not just use emscripten to compile the best editor in the world.
    Of course a quick google shows it's already been done:
    http://coolwanglu.github.io/vim.js/web/vim.html

    Now this is cool because there already exists a Spin syntax highlighting configuration for vim :)
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-12-30 04:32
    um, I can't find an escape key on my tablet's keyboard :innocent:

    I think onkeypress() solves 99.9% of the dirty bit issues.
  • Cluso99Cluso99 Posts: 18,069
    edited 2013-12-30 05:43
    FWIW I typically replace a space with a space (backspace, space) to fool editors to resave again. Therefore I don't see these types of problems asissues.
  • dgatelydgately Posts: 1,630
    edited 2013-12-30 09:07
    On onkeypress...

    What about gesture-based edits on a tablet? Will onkeypress catch edits like tapping on a word to select it, cut it, paste it elsewhere? Those gestures change the content. Are there other events that will catch those edits?


    dgately
  • Heater.Heater. Posts: 21,230
    edited 2013-12-30 09:27
    I don't care. I'd be happy to throw in the ACE editor component and get the job done. There are other choices.
    Point is I don't think any of us wants to spend hundreds of hours perfecting an editor across all platforms. There are editor geeks enough already working on that problem.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-30 09:29
    Spin programs don't typically span hundreds of thousands of bytes, and even small eAppliances have plenty of RAM, so why not do this? Every second or so, compare the current edit buffer with a previously-saved one from the top of the undo stack. If they're different, set the dirty bit, and push the current buffer onto the undo stack. It's a brute-force approach, of course, and the undo stack needn't be bottomless, but it kills two birds with one stone.

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2013-12-30 13:11
    Spin programs don't typically span hundreds of thousands of bytes, and even small eAppliances have plenty of RAM, so why not do this? Every second or so, compare the current edit buffer with a previously-saved one from the top of the undo stack. If they're different, set the dirty bit, and push the current buffer onto the undo stack. It's a brute-force approach, of course, and the undo stack needn't be bottomless, but it kills two birds with one stone.

    -Phil

    Javascript does have a timer mechanism that appears to be supported by all major browsers. I guess as long as you can trap exceptions to the source there shouldn't be any problems.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-12-30 14:09
    I've been quiet in this thread because I didn't have enough time to digest everything that has been said. I could help with the loader aspects of this project. I assume you want to be able to load propgcc xmm programs as well as lmm and cmm so you'll have to deal with the propeller-load two-stage loader mechanism. I have a Spark Core Wi-Fi module that might be useful for this project. It's a $39 module that is about the size of a BasicStamp and has an ARM chip and a Wi-Fi module. I'm sure it would be possible to program it to load a Propeller.
  • Heater.Heater. Posts: 21,230
    edited 2013-12-30 14:20
    I'm not sure either. This whole thread exists because I demonstrated it was possible to convert the open source spin compiler to Javascript and run it in the browser. That in turn is all to do with Parallax wanting a Prop dev system on iPads.

    So far C is not in the picture only Spin. I guess it might be possible to compile propgcc to JS as well but I am for sure not even going to try it.

    The issue is that browsers can't drive serial ports to program props.

    To my mind if you need a 40 dollar dongle to program the prop then that dongle could as well be a Raspberry Pi or similar. In which case the compiler could as well run on that.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-12-30 14:32
    Heater. wrote: »
    To my mind if you need a 40 dollar dongle to program the prop then that dongle could as well be a Raspberry Pi or similar. In which case the compiler could as well run on that.
    Good point. I have a RPi on order so I guess I'll have the opportunity to play with it pretty soon. :-)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-30 14:38
    heater wrote:
    The issue is that browsers can't drive serial ports to program props.
    But ChromeApps can.

    -Phil
Sign In or Register to comment.