├── .gitattributes
├── .eslintrc
├── assets
├── logo.png
└── theme
│ └── parallax.css
├── icons
├── icon16.png
├── icon48.png
└── icon128.png
├── fonts
├── ionicons.eot
├── ionicons.ttf
├── ionicons.woff
├── roboto-v15-latin-100.woff
├── roboto-v15-latin-300.woff
├── roboto-v15-latin-500.woff
├── roboto-v15-latin-700.woff
├── roboto-v15-latin-900.woff
├── roboto-v15-latin-100.woff2
├── roboto-v15-latin-300.woff2
├── roboto-v15-latin-500.woff2
├── roboto-v15-latin-700.woff2
├── roboto-v15-latin-900.woff2
├── roboto-v15-latin-italic.woff
├── roboto-v15-latin-italic.woff2
├── roboto-v15-latin-regular.woff
├── roboto-v15-latin-regular.woff2
├── roboto-v15-latin-100italic.woff
├── roboto-v15-latin-100italic.woff2
├── roboto-v15-latin-300italic.woff
├── roboto-v15-latin-300italic.woff2
├── roboto-v15-latin-500italic.woff
├── roboto-v15-latin-500italic.woff2
├── roboto-v15-latin-700italic.woff
├── roboto-v15-latin-700italic.woff2
├── roboto-v15-latin-900italic.woff
├── roboto-v15-latin-900italic.woff2
└── roboto.css
├── readme-images
├── clone-ParallaxIDE.png
├── parallaxIDE-listed.png
├── chrome-app-launcher.png
├── enable-developer-mode.png
├── parallaxIDE-launched.png
├── select-extension-folder.png
├── load-unpacked-extensions.png
└── search-chrome-app-launcher.png
├── src
├── lib
│ ├── history.js
│ ├── directive.js
│ ├── highlighter.js
│ ├── documents.js
│ ├── scroller.js
│ └── terminal.js
├── store.js
├── constants
│ ├── queued-action-types.js
│ └── action-types.js
├── creators
│ ├── rx-off.js
│ ├── tx-off.js
│ ├── echo-on.js
│ ├── connect.js
│ ├── echo-off.js
│ ├── disconnect.js
│ ├── rx-on.js
│ ├── tx-on.js
│ ├── queue-new-file.js
│ ├── reload-devices.js
│ ├── transmit.js
│ ├── rx-clear-timeout.js
│ ├── tx-clear-timeout.js
│ ├── reset-action-queue.js
│ ├── clear-transmission.js
│ ├── clear-search-status.js
│ ├── enable-auto-download.js
│ ├── receive.js
│ ├── disable-auto-download.js
│ ├── update-devices.js
│ ├── reset-download-progress.js
│ ├── update-duration.js
│ ├── queue-change-file.js
│ ├── update-search-status.js
│ ├── delete-project-confirm.js
│ ├── queue-overwrite-file.js
│ ├── update-selected-device.js
│ ├── update-download-progress.js
│ └── index.js
├── views
│ ├── appbar.js
│ ├── editor.js
│ ├── help-overlay.js
│ ├── delete-project-overlay.js
│ ├── overwrite-overlay.js
│ ├── new-version-overlay.js
│ ├── delete-file-overlay.js
│ ├── terminal.js
│ ├── layout.js
│ ├── sidebar.js
│ ├── save-overlay.js
│ ├── rxtx.js
│ ├── project-overlay.js
│ └── download-overlay.js
├── plugins
│ ├── examples.js
│ ├── notifications.js
│ └── keyboard-shortcuts.js
├── components
│ ├── file-list.js
│ ├── delete-button.js
│ ├── button.js
│ ├── overlay-title.js
│ ├── file-operation-list-item.js
│ ├── project-list-item.js
│ ├── project-list.js
│ ├── baud.js
│ ├── file-operation-list.js
│ ├── sidebar.js
│ ├── overlay-footer.js
│ ├── card.js
│ ├── top-bar.js
│ ├── progress-bar.js
│ ├── projects-button.js
│ ├── icon-button.js
│ ├── file-list-item.js
│ ├── overlay.js
│ └── transmit-pane.js
├── reducers
│ ├── delete-project-name.js
│ ├── index.js
│ ├── device-list.js
│ ├── echo.js
│ ├── download-progress.js
│ ├── next-file.js
│ ├── overlay-state.js
│ ├── next-action.js
│ ├── transmission.js
│ ├── rxtx.js
│ └── device.js
├── console-store.js
└── code-mirror.js
├── zuul.config.js
├── test
└── index.js
├── examples
├── HIGH_LOW.bs2
├── PAUSE.bs2
├── STOP.bs2
├── SLEEP.bs2
├── NAP.bs2
├── DEBUG_DEBUGIN.bs2
├── GOTO.bs2
├── RCTIME1.bs2
├── PULSOUT.bs2
├── LOOKUP.bs2
├── BRANCH.bs2
├── ON-GOTO.bs2
├── EXIT.bs2
├── TOGGLE.bs2
├── LOOKDOWN.bs2
├── ON-GOSUB.bs2
├── FOR-NEXT.bs2
├── READ.bs2
├── RETURN.bs2
├── BUTTON.bs2
├── IF-THEN.bs2
├── PWM.bs2
├── INPUT_OUTPUT.bs2
├── WRITE.bs2
├── REVERSE.bs2
├── RCTIME2.bs2
├── IF-THEN-ELSE.bs2
├── SHIFTIN.bs2
├── DO-LOOP.bs2
├── AUX_TERM.bs2
├── COUNT.bs2
├── RANDOM.bs2
├── PULSIN.bs2
├── SERIN_SEROUT1.bs2
├── SHIFTOUT.bs2
├── LCDCMD.bs2
├── LCDINIT.bs2
├── SERIN_SEROUT2.bs2
├── SELECT-CASE.bs2
├── FREQOUT.bs2
├── LCDIN.bs2
├── LCDOUT.bs2
├── GOSUB.bs2
├── I2C.bs2
├── XOUT.bs2
├── DTMFOUT.bs2
├── OWIN_OWOUT.bs2
├── STOREALL.bs2
└── DATA.bs2
├── _locales
└── en
│ └── messages.json
├── .travis.yml
├── .editorconfig
├── MakeRelease
├── .gitignore
├── manifest.json
├── background.js
├── LICENSE
├── gulpfile.babel.js
├── webpack.config.js
├── index.html
├── package.json
├── client.js
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@phated/iceddev"
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/assets/logo.png
--------------------------------------------------------------------------------
/icons/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/icons/icon16.png
--------------------------------------------------------------------------------
/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/icons/icon48.png
--------------------------------------------------------------------------------
/fonts/ionicons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/ionicons.eot
--------------------------------------------------------------------------------
/fonts/ionicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/ionicons.ttf
--------------------------------------------------------------------------------
/fonts/ionicons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/ionicons.woff
--------------------------------------------------------------------------------
/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/icons/icon128.png
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-100.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-300.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-500.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-500.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-700.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-900.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-100.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-300.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-500.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-700.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-900.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-italic.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-italic.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-regular.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-regular.woff2
--------------------------------------------------------------------------------
/readme-images/clone-ParallaxIDE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/clone-ParallaxIDE.png
--------------------------------------------------------------------------------
/readme-images/parallaxIDE-listed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/parallaxIDE-listed.png
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-100italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-100italic.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-100italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-100italic.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-300italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-300italic.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-300italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-300italic.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-500italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-500italic.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-500italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-500italic.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-700italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-700italic.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-700italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-700italic.woff2
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-900italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-900italic.woff
--------------------------------------------------------------------------------
/fonts/roboto-v15-latin-900italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/fonts/roboto-v15-latin-900italic.woff2
--------------------------------------------------------------------------------
/readme-images/chrome-app-launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/chrome-app-launcher.png
--------------------------------------------------------------------------------
/readme-images/enable-developer-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/enable-developer-mode.png
--------------------------------------------------------------------------------
/readme-images/parallaxIDE-launched.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/parallaxIDE-launched.png
--------------------------------------------------------------------------------
/readme-images/select-extension-folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/select-extension-folder.png
--------------------------------------------------------------------------------
/readme-images/load-unpacked-extensions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/load-unpacked-extensions.png
--------------------------------------------------------------------------------
/readme-images/search-chrome-app-launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/parallaxinc/Parallax-IDE/HEAD/readme-images/search-chrome-app-launcher.png
--------------------------------------------------------------------------------
/src/lib/history.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const memoryHistory = require('history/lib/createMemoryHistory')();
4 |
5 | module.exports = memoryHistory;
6 |
--------------------------------------------------------------------------------
/zuul.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | builder: 'zuul-builder-webpack',
5 | webpack: require('./webpack.config'),
6 | ui: 'mocha-bdd'
7 | };
8 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const createStore = require('@phated/redux-create-store');
4 |
5 | const reducers = require('./reducers');
6 |
7 | const store = createStore(reducers);
8 |
9 | module.exports = store;
10 |
--------------------------------------------------------------------------------
/src/constants/queued-action-types.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const queuedActionTypes = {
4 | NEW_FILE: 'NEW_FILE',
5 | CHANGE_FILE: 'CHANGE_FILE',
6 | OVERWRITE_FILE: 'OVERWRITE_FILE'
7 | };
8 |
9 | module.exports = queuedActionTypes;
10 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const expect = require('expect');
4 |
5 | describe('Parallax IDE', function(){
6 |
7 | it('has an example test', function(done){
8 | expect(true).toEqual(true);
9 | done();
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/src/creators/rx-off.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RX_OFF
5 | } = require('../constants/action-types');
6 |
7 | function rxOff(){
8 | return {
9 | type: RX_OFF,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = rxOff;
15 |
--------------------------------------------------------------------------------
/src/creators/tx-off.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | TX_OFF
5 | } = require('../constants/action-types');
6 |
7 | function txOff(){
8 | return {
9 | type: TX_OFF,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = txOff;
15 |
--------------------------------------------------------------------------------
/src/creators/echo-on.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | ECHO_ON
5 | } = require('../constants/action-types');
6 |
7 | function echoOn(){
8 | return {
9 | type: ECHO_ON,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = echoOn;
15 |
--------------------------------------------------------------------------------
/src/creators/connect.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | CONNECT
5 | } = require('../constants/action-types');
6 |
7 | function connect(){
8 | return {
9 | type: CONNECT,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = connect;
15 |
--------------------------------------------------------------------------------
/src/creators/echo-off.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | ECHO_OFF
5 | } = require('../constants/action-types');
6 |
7 | function echoOff(){
8 | return {
9 | type: ECHO_OFF,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = echoOff;
15 |
--------------------------------------------------------------------------------
/src/creators/disconnect.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | DISCONNECT
5 | } = require('../constants/action-types');
6 |
7 | function disconnect(){
8 | return {
9 | type: DISCONNECT,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = disconnect;
15 |
--------------------------------------------------------------------------------
/src/creators/rx-on.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RX_ON
5 | } = require('../constants/action-types');
6 |
7 | function rxOn(timeout){
8 | return {
9 | type: RX_ON,
10 | payload: {
11 | timeout
12 | }
13 | };
14 | }
15 |
16 | module.exports = rxOn;
17 |
--------------------------------------------------------------------------------
/src/creators/tx-on.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | TX_ON
5 | } = require('../constants/action-types');
6 |
7 | function txOn(timeout){
8 | return {
9 | type: TX_ON,
10 | payload: {
11 | timeout
12 | }
13 | };
14 | }
15 |
16 | module.exports = txOn;
17 |
--------------------------------------------------------------------------------
/src/creators/queue-new-file.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | QUEUE_NEW_FILE
5 | } = require('../constants/action-types');
6 |
7 | function queueNewFile(){
8 | return {
9 | type: QUEUE_NEW_FILE,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = queueNewFile;
15 |
--------------------------------------------------------------------------------
/src/creators/reload-devices.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RELOAD_DEVICES
5 | } = require('../constants/action-types');
6 |
7 | function reloadDevices(){
8 | return {
9 | type: RELOAD_DEVICES,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = reloadDevices;
15 |
--------------------------------------------------------------------------------
/src/creators/transmit.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | TRANSMIT
5 | } = require('../constants/action-types');
6 |
7 | function transmit(input){
8 | return {
9 | type: TRANSMIT,
10 | payload: {
11 | input
12 | }
13 | };
14 | }
15 |
16 | module.exports = transmit;
17 |
--------------------------------------------------------------------------------
/src/creators/rx-clear-timeout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RX_CLEAR_TIMEOUT
5 | } = require('../constants/action-types');
6 |
7 | function rxClearTimeout(){
8 | return {
9 | type: RX_CLEAR_TIMEOUT,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = rxClearTimeout;
15 |
--------------------------------------------------------------------------------
/src/creators/tx-clear-timeout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | TX_CLEAR_TIMEOUT
5 | } = require('../constants/action-types');
6 |
7 | function txClearTimeout(){
8 | return {
9 | type: TX_CLEAR_TIMEOUT,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = txClearTimeout;
15 |
--------------------------------------------------------------------------------
/src/creators/reset-action-queue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RESET_ACTION_QUEUE
5 | } = require('../constants/action-types');
6 |
7 | function resetFileQueue(){
8 | return {
9 | type: RESET_ACTION_QUEUE,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = resetFileQueue;
15 |
--------------------------------------------------------------------------------
/src/creators/clear-transmission.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | CLEAR_TRANSMISSION
5 | } = require('../constants/action-types');
6 |
7 | function clearTransmission(){
8 | return {
9 | type: CLEAR_TRANSMISSION,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = clearTransmission;
15 |
--------------------------------------------------------------------------------
/src/views/appbar.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const TopBar = require('../components/top-bar');
6 |
7 | class AppbarView extends React.Component {
8 | render(){
9 | return (
10 |
11 | );
12 | }
13 | }
14 |
15 | module.exports = AppbarView;
16 |
--------------------------------------------------------------------------------
/src/creators/clear-search-status.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | CLEAR_SEARCH_STATUS
5 | } = require('../constants/action-types');
6 |
7 | function clearSearchStatus(){
8 | return {
9 | type: CLEAR_SEARCH_STATUS,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = clearSearchStatus;
15 |
--------------------------------------------------------------------------------
/src/creators/enable-auto-download.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | ENABLE_AUTO_DOWNLOAD
5 | } = require('../constants/action-types');
6 |
7 | function enableAutoDownload(){
8 | return {
9 | type: ENABLE_AUTO_DOWNLOAD,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = enableAutoDownload;
15 |
--------------------------------------------------------------------------------
/src/creators/receive.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RECEIVE
5 | } = require('../constants/action-types');
6 |
7 | function receive(output, offset){
8 | return {
9 | type: RECEIVE,
10 | payload: {
11 | output,
12 | offset
13 | }
14 | };
15 | }
16 |
17 | module.exports = receive;
18 |
--------------------------------------------------------------------------------
/src/creators/disable-auto-download.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | DISABLE_AUTO_DOWNLOAD
5 | } = require('../constants/action-types');
6 |
7 | function disableAutoDownload(){
8 | return {
9 | type: DISABLE_AUTO_DOWNLOAD,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = disableAutoDownload;
15 |
--------------------------------------------------------------------------------
/src/creators/update-devices.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | UPDATE_DEVICES
5 | } = require('../constants/action-types');
6 |
7 | function updateDevices(devices){
8 | return {
9 | type: UPDATE_DEVICES,
10 | payload: {
11 | devices
12 | }
13 | };
14 | }
15 |
16 | module.exports = updateDevices;
17 |
--------------------------------------------------------------------------------
/src/plugins/examples.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function examples(app, opts, done){
4 | const { handlers } = app;
5 |
6 | handlers.ensureExampleProject(opts.examples, opts.folder || 'examples')
7 | .then(function(){
8 | return done();
9 | })
10 | .catch(done);
11 | }
12 |
13 | module.exports = examples;
14 |
--------------------------------------------------------------------------------
/src/creators/reset-download-progress.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RESET_DOWNLOAD_PROGRESS
5 | } = require('../constants/action-types');
6 |
7 | function resetDownloadProgress(){
8 | return {
9 | type: RESET_DOWNLOAD_PROGRESS,
10 | payload: {}
11 | };
12 | }
13 |
14 | module.exports = resetDownloadProgress;
15 |
--------------------------------------------------------------------------------
/src/creators/update-duration.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | UPDATE_DURATION
5 | } = require('../constants/action-types');
6 |
7 | function updateDuration(duration){
8 | return {
9 | type: UPDATE_DURATION,
10 | payload: {
11 | duration
12 | }
13 | };
14 | }
15 |
16 | module.exports = updateDuration;
17 |
--------------------------------------------------------------------------------
/src/lib/directive.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function device(type){
4 | return `'{$STAMP ${type}}`;
5 | }
6 |
7 | function pbasic(ver){
8 | return `'{$PBASIC ${ver}}`;
9 | }
10 |
11 | function directive(board, language){
12 | return `${device(board)}\n${pbasic(language)}\n\n`;
13 | }
14 |
15 | module.exports = directive;
16 |
--------------------------------------------------------------------------------
/examples/HIGH_LOW.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: HIGH_LOW
5 | 'This simple program sets I/O pin 0 high for 1/2 second and low for
6 | '1/2 second in an endless loop. Connect an LED to P0 for a simple
7 | 'blinker.
8 |
9 | Main:
10 | DO
11 | HIGH 0
12 | PAUSE 500
13 | LOW 0
14 | PAUSE 500
15 | LOOP
16 |
--------------------------------------------------------------------------------
/src/creators/queue-change-file.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | QUEUE_CHANGE_FILE
5 | } = require('../constants/action-types');
6 |
7 | function queueChangeFile(filename){
8 | return {
9 | type: QUEUE_CHANGE_FILE,
10 | payload: {
11 | filename
12 | }
13 | };
14 | }
15 |
16 | module.exports = queueChangeFile;
17 |
--------------------------------------------------------------------------------
/src/creators/update-search-status.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | UPDATE_SEARCH_STATUS
5 | } = require('../constants/action-types');
6 |
7 | function updateSearchStatus(status){
8 | return {
9 | type: UPDATE_SEARCH_STATUS,
10 | payload: {
11 | status
12 | }
13 | };
14 | }
15 |
16 | module.exports = updateSearchStatus;
17 |
--------------------------------------------------------------------------------
/src/creators/delete-project-confirm.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | DELETE_PROJECT_CONFIRM
5 | } = require('../constants/action-types');
6 |
7 | function deleteProjectConfirm(name){
8 | return {
9 | type: DELETE_PROJECT_CONFIRM,
10 | payload: {
11 | name
12 | }
13 | };
14 | }
15 |
16 | module.exports = deleteProjectConfirm;
17 |
--------------------------------------------------------------------------------
/src/creators/queue-overwrite-file.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | QUEUE_OVERWRITE_FILE
5 | } = require('../constants/action-types');
6 |
7 | function queueOverwriteFile(filename){
8 | return {
9 | type: QUEUE_OVERWRITE_FILE,
10 | payload: {
11 | filename
12 | }
13 | };
14 | }
15 |
16 | module.exports = queueOverwriteFile;
17 |
--------------------------------------------------------------------------------
/src/creators/update-selected-device.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | UPDATE_SELECTED_DEVICE
5 | } = require('../constants/action-types');
6 |
7 | function updateSelectedDevice(device){
8 | return {
9 | type: UPDATE_SELECTED_DEVICE,
10 | payload: {
11 | device
12 | }
13 | };
14 | }
15 |
16 | module.exports = updateSelectedDevice;
17 |
--------------------------------------------------------------------------------
/src/creators/update-download-progress.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | UPDATE_DOWNLOAD_PROGRESS
5 | } = require('../constants/action-types');
6 |
7 | function updateDownloadProgress(progress){
8 | return {
9 | type: UPDATE_DOWNLOAD_PROGRESS,
10 | payload: {
11 | progress
12 | }
13 | };
14 | }
15 |
16 | module.exports = updateDownloadProgress;
17 |
--------------------------------------------------------------------------------
/examples/PAUSE.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: PAUSE
5 | 'This program demonstrates the PAUSE command's time delays. Once a second,
6 | 'the program will put the message, "Paused..." on the screen.
7 |
8 | Init:
9 | PAUSE 200 'short startup-pause
10 |
11 | Main:
12 | DO
13 | DEBUG "Paused...", CR
14 | PAUSE 1000
15 | LOOP
--------------------------------------------------------------------------------
/src/components/file-list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const List = require('react-material/components/List');
5 |
6 | class FileList extends React.Component {
7 | render(){
8 | const {
9 | children
10 | } = this.props;
11 |
12 | return (
13 |
14 | {children}
15 |
16 | );
17 | }
18 | }
19 |
20 | module.exports = FileList;
21 |
--------------------------------------------------------------------------------
/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": {
3 | "message": "Parallax IDE",
4 | "description": "The name of the application"
5 | },
6 | "appDescription": {
7 | "message": "Write, compile, and download code to your Parallax Boe-Bot Robot or custom BASIC Stamp microcontroller-based electronic creations.",
8 | "description": "The description of the application"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/delete-button.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const IconButton = require('./icon-button');
6 |
7 | class DeleteButton extends React.Component {
8 | render(){
9 | const {
10 | onClick
11 | } = this.props;
12 |
13 | return (
14 |
15 | );
16 | }
17 | }
18 |
19 | module.exports = DeleteButton;
20 |
--------------------------------------------------------------------------------
/src/components/button.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const ReactStyle = require('react-style');
5 |
6 | export default class Button extends React.Component {
7 | render(){
8 | const {
9 | children,
10 | onClick,
11 | } = this.props
12 |
13 | return(
14 |
15 | )
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/reducers/delete-project-name.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | DELETE_PROJECT_CONFIRM
5 | } = require('../constants/action-types');
6 |
7 | const initial = '';
8 |
9 | function deleteProjectName(state = initial, { type, payload }){
10 | switch(type){
11 | case DELETE_PROJECT_CONFIRM:
12 | return payload.name;
13 | default:
14 | return state;
15 | }
16 | }
17 |
18 | module.exports = deleteProjectName;
19 |
--------------------------------------------------------------------------------
/src/components/overlay-title.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const styles = {
6 | overlayTitle: {
7 | margin: 0
8 | }
9 | };
10 |
11 | class OverlayTitle extends React.Component {
12 | render(){
13 | const {
14 | children
15 | } = this.props;
16 |
17 | return (
18 |
{children}
19 | );
20 | }
21 | }
22 |
23 | module.exports = OverlayTitle;
24 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const reducers = {
4 | deleteProjectName: require('./delete-project-name'),
5 | overlayState: require('./overlay-state'),
6 | transmission: require('./transmission'),
7 | device: require('./device'),
8 | deviceList: require('./device-list'),
9 | downloadProgress: require('./download-progress'),
10 | nextFile: require('./next-file'),
11 | nextAction: require('./next-action')
12 | };
13 |
14 | module.exports = reducers;
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '6'
5 | before_install:
6 | - 'export DISPLAY=:99.0'
7 | - 'sh -e /etc/init.d/xvfb start'
8 | script: npm run ci
9 | # whenever a tag is pushed, we deploy to github releases
10 | before_deploy: npm run release
11 | deploy:
12 | provider: releases
13 | api_key: $GH_TOKEN
14 | file: "dist/parallax-ide.zip"
15 | skip_cleanup: true
16 | on:
17 | tags: true
18 | node: '6'
19 | all_branches: true
20 |
--------------------------------------------------------------------------------
/examples/STOP.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: STOP
5 | 'This program is similar to END, NAP, and SLEEP except that the LED
6 | 'will not blink since the STOP command prevents the BASIC Stamp from
7 | 'entering low power mode at the end of the code. Use the circuit
8 | 'shown in the description of the SLEEP command for this example.
9 |
10 | Main:
11 | LOW 0 'turn LED on
12 | STOP 'stop program
--------------------------------------------------------------------------------
/src/reducers/device-list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RELOAD_DEVICES,
5 | UPDATE_DEVICES
6 | } = require('../constants/action-types');
7 |
8 | const initial = [];
9 |
10 | function deviceList(state = initial, { type, payload }){
11 | switch(type){
12 | case RELOAD_DEVICES:
13 | return initial;
14 | case UPDATE_DEVICES:
15 | return payload.devices;
16 | default:
17 | return state;
18 | }
19 | }
20 |
21 | module.exports = deviceList;
22 |
--------------------------------------------------------------------------------
/src/components/file-operation-list-item.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { ChildButton } = require('react-mfb-iceddev');
5 |
6 | class FileOperationListItem extends React.Component {
7 | render(){
8 | const {
9 | onClick,
10 | icon,
11 | label
12 | } = this.props;
13 |
14 | return (
15 |
16 | );
17 | }
18 | }
19 |
20 | module.exports = FileOperationListItem;
21 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/src/reducers/echo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | Don't include this in the index.js because it is used only
5 | for the console-store
6 | */
7 |
8 | const {
9 | ECHO_OFF,
10 | ECHO_ON
11 | } = require('../constants/action-types');
12 |
13 | const initial = false;
14 |
15 | function echo(state = initial, { type }){
16 | switch(type){
17 | case ECHO_OFF:
18 | return false;
19 | case ECHO_ON:
20 | return true;
21 | default:
22 | return state;
23 | }
24 | }
25 |
26 | module.exports = echo;
27 |
--------------------------------------------------------------------------------
/src/components/project-list-item.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | class Project extends React.Component {
6 | render(){
7 | const {
8 | onClick,
9 | children
10 | } = this.props;
11 |
12 | const liStyle = {
13 | listStyleType: 'none',
14 | padding: "14px 16px 15px"
15 | }
16 |
17 | return (
18 |
19 | {children}
20 |
21 | );
22 | }
23 | }
24 |
25 | module.exports = Project;
26 |
--------------------------------------------------------------------------------
/src/reducers/download-progress.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | RESET_DOWNLOAD_PROGRESS,
5 | UPDATE_DOWNLOAD_PROGRESS
6 | } = require('../constants/action-types');
7 |
8 | const initial = 0;
9 |
10 | function downloadProgress(state = initial, { type, payload }){
11 | switch(type){
12 | case RESET_DOWNLOAD_PROGRESS:
13 | return initial;
14 | case UPDATE_DOWNLOAD_PROGRESS:
15 | return payload.progress;
16 | default:
17 | return state;
18 | }
19 | }
20 |
21 | module.exports = downloadProgress;
22 |
--------------------------------------------------------------------------------
/src/console-store.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | The terminal console is causing too many renders on components
5 | throughout the application. We could implement finer-grained
6 | subscribes through lenses but for now, just create a new store.
7 | */
8 |
9 | const createStore = require('@phated/redux-create-store');
10 |
11 | const reducers = {
12 | echo: require('./reducers/echo'),
13 | rxtx: require('./reducers/rxtx')
14 | };
15 |
16 | const consoleStore = createStore(reducers);
17 |
18 | module.exports = consoleStore;
19 |
--------------------------------------------------------------------------------
/src/components/project-list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const List = require('react-material/components/List');
5 |
6 | const styles = {
7 | projectList: {
8 | flex: 1,
9 | marginTop: 10
10 | }
11 | };
12 |
13 | class ProjectsList extends React.Component {
14 | render(){
15 | const {
16 | children
17 | } = this.props;
18 |
19 | return (
20 |
21 | {children}
22 |
23 | );
24 | }
25 | }
26 |
27 | module.exports = ProjectsList;
28 |
--------------------------------------------------------------------------------
/src/components/baud.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const styles = {
6 | baud: {
7 | float: 'left',
8 | padding: '3px 0px 0px 10px',
9 | margin: 0
10 | },
11 | baudRate: {
12 | paddingLeft: 8
13 | }
14 | };
15 |
16 | class Baud extends React.Component {
17 |
18 | render() {
19 | const baudRate = 115200;
20 |
21 | return (
22 |
23 | BAUD {baudRate}
24 |
25 | );
26 | }
27 | }
28 |
29 | module.exports = Baud;
30 |
--------------------------------------------------------------------------------
/src/components/file-operation-list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { Menu, MainButton } = require('react-mfb-iceddev');
5 |
6 | class FileOperationList extends React.Component {
7 | render(){
8 | const {
9 | children
10 | } = this.props;
11 |
12 | return (
13 |
17 | );
18 | }
19 | }
20 |
21 | module.exports = FileOperationList;
22 |
--------------------------------------------------------------------------------
/src/reducers/next-file.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | QUEUE_CHANGE_FILE,
5 | QUEUE_OVERWRITE_FILE,
6 | RESET_ACTION_QUEUE
7 | } = require('../constants/action-types');
8 |
9 | const initial = '';
10 |
11 | function nextFile(state = initial, { type, payload }){
12 | switch(type){
13 | case QUEUE_CHANGE_FILE:
14 | return payload.filename;
15 | case QUEUE_OVERWRITE_FILE:
16 | return payload.filename;
17 | case RESET_ACTION_QUEUE:
18 | return initial;
19 | default:
20 | return state;
21 | }
22 | }
23 |
24 | module.exports = nextFile;
25 |
--------------------------------------------------------------------------------
/src/components/sidebar.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const Card = require('./card');
6 |
7 | const styles = {
8 | card: {
9 | margin: 0,
10 | height: '80vh',
11 | width: '100%',
12 | display: 'flex',
13 | flexDirection: 'column'
14 | }
15 | };
16 |
17 | class Sidebar extends React.Component {
18 | render(){
19 | const {
20 | children
21 | } = this.props;
22 |
23 | return (
24 |
25 | {children}
26 |
27 | );
28 | }
29 | }
30 |
31 | module.exports = Sidebar;
32 |
--------------------------------------------------------------------------------
/examples/SLEEP.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: SLEEP
5 | 'This program lights an LED and then goes to sleep. Connect an LED to pin
6 | '0 as shown in the description of SLEEP in the manual and run the program.
7 | 'The LED will turn on, then the BASIC Stamp will go to sleep. During sleep,
8 | 'the LED will remain on, but will blink at intervals of approximately 2.3
9 | 'seconds due to the watchdog timeout and reset.
10 |
11 | Main:
12 | LOW 0 'turn LED on
13 |
14 | Snooze:
15 | DO
16 | SLEEP 10 'sleep for about 10 seconds
17 | LOOP
--------------------------------------------------------------------------------
/examples/NAP.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: NAP
5 | 'This program lights an LED setting pin 0 low. This completes the circuit
6 | 'from +5V, through the LED and resistor, to ground. During the NAP interval,
7 | 'the LED stays lit, but blinks off for a fraction of a second. This blink
8 | 'is caused by the NAP wake-up mechanism. During wake-up, all pins briefly
9 | 'slip into input mode, effectively disconnecting them from loads.
10 |
11 | Setup:
12 | LOW 0 'turn LED on
13 |
14 | Snooze:
15 | DO
16 | NAP 4 'nap for fraction of a second
17 | LOOP
--------------------------------------------------------------------------------
/src/reducers/overlay-state.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | SHOW_OVERLAY,
5 | HIDE_OVERLAY
6 | } = require('../constants/action-types');
7 |
8 | const initial = '';
9 |
10 | function overlayState(state = initial, { type, payload }){
11 | switch(type){
12 | case SHOW_OVERLAY:
13 | return payload.state;
14 | case HIDE_OVERLAY:
15 | return payload.state;
16 | default:
17 | // We only want overlay to flash once, so if any action is
18 | // dispatched that isn't an action we are watching, reset
19 | // to initial
20 | return initial;
21 | }
22 | }
23 |
24 | module.exports = overlayState;
25 |
--------------------------------------------------------------------------------
/src/lib/highlighter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const cm = require('../code-mirror');
4 |
5 | function highlighter(position, length) {
6 | const doc = cm.getDoc();
7 |
8 | const anchor = doc.posFromIndex(position);
9 | const head = doc.posFromIndex(position + length);
10 |
11 | doc.setSelection(anchor, head, { scroll: false });
12 |
13 | const charRect = cm.charCoords(anchor, 'local');
14 | const halfHeight = cm.getScrollerElement().offsetHeight / 2;
15 | const halfTextHeight = Math.floor((charRect.bottom - charRect.top) / 2);
16 | cm.scrollTo(null, charRect.top - halfHeight - halfTextHeight);
17 | }
18 |
19 | module.exports = highlighter;
20 |
--------------------------------------------------------------------------------
/src/components/overlay-footer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const React = require('react');
5 |
6 | const styles = {
7 | overlayButtonContainer: {
8 | marginTop: 'auto',
9 | marginLeft: 'auto',
10 | height: '40px'
11 | }
12 | };
13 |
14 | class OverlayFooter extends React.Component {
15 | render(){
16 | const {
17 | children,
18 | style
19 | } = this.props;
20 |
21 | const footerStyle = _.assign({}, styles.overlayButtonContainer, style);
22 |
23 | return (
24 |
25 | {children}
26 |
27 | );
28 | }
29 | }
30 |
31 | module.exports = OverlayFooter;
32 |
--------------------------------------------------------------------------------
/MakeRelease:
--------------------------------------------------------------------------------
1 | echo
2 | echo ---Making Chrome App release in ./release folder---
3 | echo
4 | echo STEP 1 of 2: Clearing ./release folder
5 | echo
6 | # Clear release folder
7 | rm -R release/*
8 |
9 | echo
10 | echo STEP 2 of 2: Copying resources to ./release folder
11 | echo
12 | # Copy static resources
13 | cp -R assets release/assets
14 | cp -R examples release/examples
15 | cp -R fonts release/fonts
16 | cp -R icons release/icons
17 | cp -R _locales release/_locales
18 | cp background.js release/
19 | cp bundle.js release/
20 | cp index.html release/
21 | cp manifest.json release/
22 |
23 | echo Done!
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/components/card.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const React = require('react');
5 |
6 | const defaultStyle = {
7 | boxShadow: '0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)',
8 | backgroundColor: 'white',
9 | padding: '16px',
10 | borderRadius: '2px'
11 | };
12 |
13 | class Card extends React.Component {
14 | render(){
15 | const {
16 | style = {},
17 | children
18 | } = this.props;
19 |
20 | const styles = _.assign({}, defaultStyle, style);
21 |
22 | return (
23 |
24 | {children}
25 |
26 | );
27 | }
28 | }
29 |
30 | module.exports = Card;
31 |
--------------------------------------------------------------------------------
/src/components/top-bar.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const AppBar = require('react-material/components/AppBar');
5 |
6 | const styles = {
7 | appbar: {
8 | normalAppBarStyle: {
9 | backgroundColor: '#2c83d8'
10 | }
11 | },
12 | logo: {
13 | boxSizing: 'border-box',
14 | height: '100%',
15 | position: 'absolute',
16 | right: 0,
17 | padding: 8
18 | }
19 | };
20 |
21 | class TopBar extends React.Component {
22 | render(){
23 | return (
24 |
25 |
26 |
27 | );
28 | }
29 | }
30 |
31 | module.exports = TopBar;
32 |
--------------------------------------------------------------------------------
/examples/DEBUG_DEBUGIN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: DEBUG_DEBUGIN
5 | 'This program demonstrates the ability to accept user input from the
6 | 'Debug Terminal, and to accept numeric entry in any valid format.
7 |
8 | myNum VAR Word
9 |
10 | Init:
11 | PAUSE 200 'short startup-pause
12 |
13 | Main:
14 | DO
15 | DEBUG CLS, "Enter a any number: " 'prompt user
16 | DEBUGIN SNUM myNum 'retrieve number in any format
17 |
18 | DEBUG CRSRXY, 0, 2, 'display number in all formats
19 | SDEC ? myNum,
20 | SHEX ? myNum,
21 | SBIN ? myNum
22 | PAUSE 3000
23 | LOOP 'do it again
--------------------------------------------------------------------------------
/examples/GOTO.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: GOTO
5 | 'This program isn't practical at all, but demonstrates the use of GOTO to
6 | 'jump around the code. This code jumps between three different routines,
7 | 'each of which print something different on the screen. The routines are
8 | 'out of order for sake of example.
9 |
10 | Init:
11 | PAUSE 200 'short startup-pause
12 |
13 | Start:
14 | GOTO Routine1
15 |
16 | Routine2:
17 | DEBUG "We're in routine #2", CR
18 | PAUSE 1000
19 | GOTO Routine3
20 |
21 | Routine1:
22 | DEBUG "We're in routine #1", CR
23 | PAUSE 1000
24 | GOTO Routine2
25 |
26 | Routine3:
27 | DEBUG "We're in routine #3", CR
28 | PAUSE 1000
29 | GOTO Routine1
--------------------------------------------------------------------------------
/src/reducers/next-action.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {
4 | QUEUE_NEW_FILE,
5 | QUEUE_CHANGE_FILE,
6 | QUEUE_OVERWRITE_FILE,
7 | RESET_ACTION_QUEUE
8 | } = require('../constants/action-types');
9 |
10 | const {
11 | NEW_FILE,
12 | CHANGE_FILE,
13 | OVERWRITE_FILE
14 | } = require('../constants/queued-action-types');
15 |
16 | const initial = '';
17 |
18 | function nextAction(state = initial, { type }){
19 | switch(type){
20 | case QUEUE_NEW_FILE:
21 | return NEW_FILE;
22 | case QUEUE_CHANGE_FILE:
23 | return CHANGE_FILE;
24 | case QUEUE_OVERWRITE_FILE:
25 | return OVERWRITE_FILE;
26 | case RESET_ACTION_QUEUE:
27 | return initial;
28 | default:
29 | return state;
30 | }
31 | }
32 |
33 | module.exports = nextAction;
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | node_modules
26 |
27 | # Users Environment Variables
28 | .lock-wscript
29 |
30 | .DS_Store
31 |
32 | # Generated files
33 | /bundle.js
34 | /bundle.js.map
35 | /dist/
36 | /release/
37 |
--------------------------------------------------------------------------------
/src/components/progress-bar.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const React = require('react');
5 |
6 | const styles = {
7 | progressContainerStyle: {
8 | width: '100%',
9 | height: '8px',
10 | backgroundColor: '#b0d0ef',
11 | marginTop: 'auto'
12 | },
13 | progressBarStyle: {
14 | height: '100%',
15 | backgroundColor: '#3a81f0'
16 | }
17 | };
18 |
19 | class ProgressBar extends React.Component {
20 |
21 | render(){
22 | const {
23 | percent
24 | } = this.props;
25 |
26 | const style = _.assign({}, styles.progressBarStyle, { width: `${percent}%` });
27 |
28 | return (
29 |
32 | );
33 | }
34 | }
35 |
36 | module.exports = ProgressBar;
37 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "__MSG_appName__",
3 | "description": "__MSG_appDescription__",
4 | "version": "0.14.4",
5 | "manifest_version": 2,
6 | "default_locale": "en",
7 | "permissions": [
8 | "serial",
9 | "unlimitedStorage",
10 | "syncFileSystem",
11 | "storage",
12 | "usb",
13 | {
14 | "usbDevices": [
15 | {
16 | "vendorId": 1027,
17 | "productId": 24577
18 | },
19 | {
20 | "vendorId": 1027,
21 | "productId": 24597
22 | }
23 | ]
24 | }
25 | ],
26 | "icons": {
27 | "16": "icons/icon16.png",
28 | "48": "icons/icon48.png",
29 | "128": "icons/icon128.png"
30 | },
31 | "app": {
32 | "background": {
33 | "scripts": [
34 | "background.js"
35 | ]
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/RCTIME1.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: RCTIME1
5 | 'This program shows the standard use of the RCTIME command measuring an
6 | 'RC charge/discharge time. Use the circuit in the RCTIME description
7 | '(in the manual) with R = 10K pot and C = 0.1 uF. Connect the circuit to
8 | 'pin 7 and run the program. Adjust the pot and watch the value change in
9 | 'the Debug Terminal.
10 |
11 | RC PIN 7
12 |
13 | result VAR Word
14 |
15 | Init:
16 | PAUSE 200 'short startup-pause
17 |
18 | Main:
19 | DO
20 | HIGH RC 'charge the cap
21 | PAUSE 1 ' for 1 ms
22 | RCTIME RC, 1, result 'measure RC discharge time
23 | DEBUG HOME, DEC result 'display value
24 | PAUSE 50
25 | LOOP
--------------------------------------------------------------------------------
/src/components/projects-button.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { MainButton } = require('react-mfb-iceddev');
5 |
6 | const styles = {
7 | changeFolderButton: {
8 | position: 'absolute',
9 | top: 28,
10 | margin: 0,
11 | left: 140,
12 | transform: 'none'
13 | }
14 | };
15 |
16 | class ProjectsButton extends React.Component {
17 | render(){
18 | const {
19 | onClick
20 | } = this.props;
21 |
22 | return (
23 |
24 |
29 |
30 | );
31 | }
32 | }
33 |
34 | module.exports = ProjectsButton;
35 |
--------------------------------------------------------------------------------
/examples/PULSOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: PULSOUT
5 | 'This program blinks an LED on for 25 ms at 1-second intervals. Connect an
6 | 'LED (active-low) to I/O pin 0.
7 |
8 | #SELECT $STAMP 'Set Scale according to module type
9 | #CASE BS2, BS2E, BS2PE
10 | Scale CON 500 'to ms for 2 us per unit
11 | #CASE BS2SX, BS2P, BS2PX
12 | Scale CON 1250 'to ms for 0.8 us per unit
13 | #ENDSELECT
14 |
15 | Flash CON 25 * Scale '25 milliseconds
16 |
17 | Setup:
18 | PAUSE 200 'short startup-pause
19 | HIGH 0 'make P0 high (LED off)
20 |
21 | Main:
22 | DO
23 | PULSOUT 0, Flash 'flash LED
24 | PAUSE 1000 'one second delay
25 | LOOP
--------------------------------------------------------------------------------
/examples/LOOKUP.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: LOOKUP
5 | 'This program uses LOOKUP to create a Debug Terminal animation of a spinning
6 | 'propeller. The animation consists of the four ASCII characters | / - \
7 | 'which, when printed rapidly in order at a fixed location, appears to spin.
8 | 'A little imagination helps a lot here....
9 |
10 | idx VAR Nib
11 | frame VAR Byte
12 |
13 | Init:
14 | PAUSE 200 'short startup-pause
15 |
16 | Spinner:
17 | DO
18 | LOOKUP idx, ["|/-\"], frame 'lookup current frame character
19 | DEBUG HOME, "Spinner: ", frame 'display
20 | PAUSE 150 'pause between frames
21 | idx = idx + 1 // 4 'update frame index (0..3)
22 | LOOP 'loop forever
23 |
--------------------------------------------------------------------------------
/examples/BRANCH.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: BRANCH
5 | 'This program shows how the value of an index variable (idx) controls the
6 | 'destination of the BRANCH instruction.
7 |
8 | idx VAR Byte
9 |
10 | Init:
11 | PAUSE 200 'short startup-pause
12 |
13 | Main:
14 | DEBUG "idx: ", DEC idx, " "
15 | BRANCH idx, [Task_0, Task_1, Task_2] 'branch to task
16 | DEBUG "BRANCH target error...", CR, CR '... unless out of range
17 |
18 | Next_Task:
19 | idx = idx + 1 // 4 'force idx to be 0..3
20 | PAUSE 250
21 | GOTO Main
22 |
23 | Task_0:
24 | DEBUG "BRANCHed to Task_0", CR
25 | GOTO Next_Task
26 |
27 | Task_1:
28 | DEBUG "BRANCHed to Task_1", CR
29 | GOTO Next_Task
30 |
31 | Task_2:
32 | DEBUG "BRANCHed to Task_2", CR
33 | GOTO Next_Task
--------------------------------------------------------------------------------
/examples/ON-GOTO.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: ON-GOTO
5 | 'This program shows how the value of an index variable (idx) controls the
6 | 'destination of the ON...GOTO instruction.
7 |
8 | idx VAR Byte
9 |
10 | Init:
11 | PAUSE 200 'short startup-pause
12 |
13 | Main:
14 | DEBUG "idx: ", DEC idx, " "
15 | ON idx GOTO Case_0, Case_1, Case_2 'if idx = 0..2 goto label
16 | DEBUG "ON..GOTO target error.", CR 'message if idx is out of range
17 |
18 | Update:
19 | idx = idx + 1 // 4 'force idx to be 0..3
20 | PAUSE 1000
21 | GOTO Main
22 |
23 | Case_0:
24 | DEBUG "Running Case_0 routine", CR
25 | GOTO Update
26 |
27 | Case_1:
28 | DEBUG "Running Case_1 routine", CR
29 | GOTO Update
30 |
31 | Case_2:
32 | DEBUG "Running Case_2 routine", CR
33 | GOTO Update
--------------------------------------------------------------------------------
/src/components/icon-button.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const Icon = require('react-material/components/Icon');
5 |
6 | const styles = {
7 | deleteButton: {
8 | border: 0,
9 | background: 'none',
10 | padding: 0,
11 | float: 'right',
12 | position: 'relative',
13 | zIndex: 7
14 | },
15 | buttonIcon: {
16 | display: 'inline-block',
17 | padding: 0,
18 | width: '30px',
19 | verticalAlign: 'middle',
20 | pointerEvents: 'none'
21 | }
22 | };
23 |
24 | class IconButton extends React.Component {
25 | render(){
26 | const {
27 | onClick,
28 | icon
29 | } = this.props;
30 |
31 | return (
32 |
35 | );
36 | }
37 | }
38 |
39 | module.exports = IconButton;
40 |
--------------------------------------------------------------------------------
/examples/EXIT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: EXIT
5 | 'This program demonstrates the early termination of DO...LOOP and
6 | 'FOR..NEXT loop structures. IF...THEN is used to test a condition,
7 | 'and when true, EXIT will terminate the loop.
8 |
9 | col VAR Nib
10 | row VAR Nib
11 |
12 | Setup:
13 | PAUSE 200 'short startup-pause
14 | col = 0
15 |
16 | Main:
17 | DO WHILE (col < 10) 'attempt 10 iterations
18 | FOR row = 0 TO 15 'attempt 16 iterations
19 | IF (row > 9) THEN EXIT 'terminate when row > 9
20 | DEBUG CRSRXY, (col * 8), row, 'print col/row at location
21 | DEC col, "/", DEC row, CR
22 | NEXT
23 | col = col + 1 'update column
24 | IF (col = 3) THEN EXIT 'terminate when col = 3
25 | LOOP
26 | END
--------------------------------------------------------------------------------
/src/code-mirror.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const CodeMirror = require('codemirror');
4 | require('codemirror/mode/javascript/javascript');
5 | require('codemirror/addon/search/searchcursor');
6 | require('codemirror/addon/dialog/dialog');
7 | require('codemirror/addon/dialog/dialog.css');
8 | require('codemirror/addon/search/search');
9 | require('codemirror/addon/selection/mark-selection');
10 | require('codemirror/lib/codemirror.css');
11 | require('../assets/theme/parallax.css');
12 | require('./lib/pbasic')(CodeMirror);
13 |
14 | const cm = new CodeMirror(null, {
15 | mode: 'pbasic',
16 | theme: 'parallax',
17 | lineNumbers: true
18 | });
19 |
20 | cm.setOption('styleSelectedText', true);
21 | cm.setOption('tabSize', 2);
22 | cm.setOption('extraKeys', {
23 | 'Ctrl-Up': false,
24 | 'Ctrl-Down': false,
25 | 'Tab': false,
26 | 'Shift-Tab': false,
27 | 'Ctrl-T': false
28 | });
29 |
30 | module.exports = cm;
31 |
--------------------------------------------------------------------------------
/examples/TOGGLE.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: TOGGLE
5 | 'Connect LEDs to pins 0 through 3 as shown in the TOGGLE command description
6 | 'and run this program. The TOGGLE command will treat you to a light show.
7 | 'You may also run the demo without LEDs; the Debug Terminal will show you the
8 | 'states of pins 0 through 3.
9 |
10 | thePin VAR Nib 'pin 0 - 3
11 |
12 | Setup:
13 | PAUSE 200 'short startup-pause
14 | DIRA = %1111 'make LEDs output, low
15 |
16 | Main:
17 | DEBUG "LED States: "
18 | DO
19 | FOR thePin = 0 TO 3 'loop through pins
20 | TOGGLE thePin 'toggle current pin
21 | DEBUG CRSRXY, 12, 0, BIN4 OUTA 'show on Debug Terminal
22 | PAUSE 250 'short delay
23 | NEXT
24 | LOOP 'repeat forever
--------------------------------------------------------------------------------
/src/views/editor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const cm = require('../code-mirror');
6 |
7 | class Editor extends React.Component {
8 |
9 | componentDidMount(){
10 | const container = React.findDOMNode(this);
11 | const { handleInput } = this.props.handlers;
12 | container.style.display = 'flex';
13 | container.style.flex = '1';
14 | container.style.flexDirection = 'column';
15 | container.setAttribute('id', 'editorContainer');
16 |
17 | container.appendChild(cm.getWrapperElement());
18 |
19 | cm.on('change', handleInput);
20 | }
21 |
22 | componentWillUnmount(){
23 | const container = React.findDOMNode(this);
24 | container.removeAll();
25 | }
26 |
27 |
28 | shouldComponentUpdate(){
29 | return false;
30 | }
31 |
32 | render(){
33 |
34 | return (
35 |
36 | );
37 | }
38 |
39 | }
40 |
41 | module.exports = Editor;
42 |
--------------------------------------------------------------------------------
/examples/LOOKDOWN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: LOOKDOWN
5 | 'This program uses LOOKDOWN to determine the number of decimal digits in
6 | 'a number. Since LOOKDOWN uses a zero-indexed table, the output will be
7 | 'the number of digits minus one, so the DEBUG statement corrects for this.
8 |
9 | aNum VAR Word 'random number
10 | stpSz VAR Word 'FOR-NEXT step size
11 | numDig VAR Nib 'digits in aNum
12 |
13 | Setup:
14 | PAUSE 200 'short startup-pause
15 | stpSz = 2
16 |
17 | Main:
18 | FOR aNum = 0 TO 15000 STEP stpSz
19 | LOOKDOWN aNum, <[0, 10, 100, 1000, 10000, 65535], numDig
20 | 'right-justify output
21 | DEBUG "aNum = ", REP " "\(5-numDig), DEC aNum, TAB,
22 | "Digits = ", DEC numDig, CR
23 | PAUSE 150
24 | LOOKUP numDig, [2, 2, 5, 25, 250, 500, 1000], stpSz
25 | NEXT
26 | END
--------------------------------------------------------------------------------
/examples/ON-GOSUB.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: ON-GOSUB
5 | 'This program demonstrates a simple task manager that can be used in
6 | 'a variety of applications. It is particularly useful in robotics and
7 | 'industrial applications. The advantage of this design is that task
8 | 'code routines may be called from other places in the program, including
9 | 'other tasks, and the overal program flow is maintained.
10 |
11 | task VAR Nib
12 |
13 | Init:
14 | PAUSE 200 'short startup-pause
15 |
16 | Main:
17 | DO
18 | ON task GOSUB Task_0, Task_1, Task_2 'run current task
19 | task = task + 1 // 3 'update task pointer
20 | PAUSE 1000
21 | LOOP
22 |
23 | Task_0:
24 | DEBUG "Running Task 0", CR
25 | RETURN
26 |
27 | Task_1:
28 | DEBUG "Running Task 1", CR
29 | RETURN
30 |
31 | Task_2:
32 | DEBUG "Running Task 2", CR
33 | RETURN
--------------------------------------------------------------------------------
/src/reducers/transmission.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 |
5 | const {
6 | RECEIVE,
7 | TRANSMIT,
8 | CLEAR_TRANSMISSION,
9 | CONNECT
10 | } = require('../constants/action-types');
11 |
12 | const initial = {
13 | input: '',
14 | // output is an array of lines
15 | output: [],
16 | // offset is number of lines cleared from console buffer
17 | offset: 0
18 | };
19 |
20 | function transmission(state = initial, { type, payload }){
21 | switch(type){
22 | case CONNECT:
23 | return _.assign({}, state, { input: '' });
24 | case RECEIVE:
25 | return _.assign({}, state, { output: payload.output, offset: payload.offset });
26 | case TRANSMIT:
27 | return _.assign({}, state, { input: payload.input });
28 | case CLEAR_TRANSMISSION:
29 | return _.assign({}, state, { input: '', output: '' });
30 | default:
31 | return state;
32 | }
33 | }
34 |
35 | module.exports = transmission;
36 |
--------------------------------------------------------------------------------
/examples/FOR-NEXT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: FOR-NEXT
5 | 'This example uses a FOR...NEXT loop to churn out a series of sequential
6 | 'squares (numbers 1, 2, 3, 4... raised to the second power) by using a
7 | 'variable to set the FOR...NEXT's StepValue parameter, and incrementing
8 | 'StepValue within the loop. Sir Isaac Newton is generally credited with
9 | 'the discovery of this technique.
10 |
11 | square VAR Byte 'FOR/NEXT counter
12 | stepSize VAR Byte 'step size, increase by 2 each loop
13 |
14 | Setup:
15 | PAUSE 200 'short startup-pause
16 | stepSize = 1
17 | square = 1
18 |
19 | Main:
20 | FOR square = 1 TO 250 STEP stepSize 'show squares up to 250
21 | DEBUG DEC ? square 'display on screen
22 | stepSize = stepSize + 2 'add 2 to stepSize
23 | NEXT 'loop until square > 250
24 | END
--------------------------------------------------------------------------------
/examples/READ.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: READ
5 | 'This program reads a string of data stored in EEPROM. The EEPROM data is
6 | 'downloaded to the BS2 at compile-time and remains there (even with the
7 | 'power off) until overwritten. Put ASCII characters into EEPROM, followed
8 | 'by 0, which will serve as the end-of-message marker.
9 |
10 | strAddr VAR Word
11 | char VAR Byte
12 |
13 | Msg1 DATA "BS2", CR, "EEPROM Storage!", 0
14 |
15 | Init:
16 | PAUSE 200 'short startup-pause
17 |
18 | Main:
19 | strAddr = Msg1 'set to start of message
20 | GOSUB String_Out
21 | END
22 |
23 | String_Out:
24 | DO
25 | READ strAddr, char 'read byte from EEPROM
26 | strAddr = strAddr + 1 'point to next character
27 | IF (char = 0) THEN EXIT 'if 0, exit routine
28 | DEBUG char 'otherwise print char
29 | LOOP
30 | RETURN
--------------------------------------------------------------------------------
/background.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function noop(){}
4 |
5 | function closeSerialPorts(){
6 | chrome.serial.getConnections(function(connections){
7 | connections.forEach(function(connection){
8 | chrome.serial.disconnect(connection.connectionId, noop);
9 | });
10 | });
11 | }
12 |
13 | // Listens for the app launching then creates the window
14 | chrome.app.runtime.onLaunched.addListener(function() {
15 | var width = 1000;
16 | var height = 500;
17 |
18 | var windowOpts = {
19 | id: 'main',
20 | state: 'maximized',
21 | bounds: {
22 | width: width,
23 | height: height,
24 | left: Math.round((screen.availWidth - width) / 2),
25 | top: Math.round((screen.availHeight - height) / 2)
26 | }
27 | };
28 |
29 | chrome.app.window.create('index.html', windowOpts, function(win){
30 | win.onClosed.addListener(closeSerialPorts);
31 | });
32 | });
33 |
34 | chrome.runtime.onInstalled.addListener(function(evt){
35 | chrome.storage.local.set({newVersion: 'newVersion'});
36 | });
37 |
--------------------------------------------------------------------------------
/src/components/file-list-item.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const red = '#da2100';
6 | const green = '#159600';
7 | const styles = {
8 | fileTempIndicator: {
9 | backgroundColor: green,
10 | height: 10,
11 | width: 10,
12 | borderRadius: '100%',
13 | marginRight: 5,
14 | display: 'inline-block'
15 | },
16 | fileHasTemp: {
17 | backgroundColor: red
18 | }
19 | };
20 |
21 | class FileListItem extends React.Component {
22 | render(){
23 | const {
24 | filename,
25 | temp,
26 | onClick
27 | } = this.props;
28 |
29 | const liStyle = {
30 | listStyleType: 'none',
31 | padding: "14px 16px 15px"
32 | }
33 |
34 | const tempStyles = [styles.fileTempIndicator];
35 | if(temp){
36 | tempStyles.push(styles.fileHasTemp);
37 | }
38 |
39 | return (
40 |
41 | {filename}
42 |
43 | );
44 | }
45 | }
46 |
47 | module.exports = FileListItem;
48 |
--------------------------------------------------------------------------------
/examples/RETURN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: RETURN
5 | 'This program demonstrates a potential bug caused by allowing a program
6 | 'to "fall into" a subroutine. The program was intented to indicate that it
7 | 'is "Starting...", then "Executing Subroutine,", then "Returned..." from
8 | 'the subroutine and then stop. Since we left out the END command (indicated
9 | 'in the comments), the program then falls into the subroutine, displays the
10 | 'message "Executing..." again and then RETURNs to the start of the program and
11 | 'runs continuously in an endless loop.
12 |
13 | Init:
14 | PAUSE 200 'short startup-pause
15 |
16 | Reset:
17 | DEBUG "Starting Program", CR 'show start-up
18 |
19 | Main:
20 | PAUSE 1000
21 | GOSUB Demo_Sub 'call the subroutine
22 | PAUSE 1000
23 | DEBUG "Returned from Subroutine", CR 'show that we're back
24 | PAUSE 1000
25 | '<-- Forgot to put END here
26 |
27 | Demo_Sub:
28 | DEBUG " Executing Subroutine", CR 'show subroutine activity
29 | RETURN
--------------------------------------------------------------------------------
/examples/BUTTON.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: BUTTON
5 | 'Connect an active-low circuit (shown in the BUTTON command description) to pin P0
6 | 'of the BASIC Stamp. When you press the button, the BUTTON command will detect the
7 | 'low signal and then the DEBUG command will execute to display an asterisk (*) on
8 | 'the Debug Terminal. After the first button press, then BUTTON command will delay
9 | 'approximately one second (200 x 5 ms) before auto-repeating at a rate of
10 | 'approximately 100 ms (20 x 5 ms).
11 |
12 | Btn PIN 0
13 | btnWrk VAR Byte
14 |
15 | Init:
16 | PAUSE 200 'short startup-pause
17 |
18 | Main:
19 | 'Try changing the Delay parameter (3rd value) in BUTTON to see the effect:
20 | '0 = no delay; 1-254 = varying delays before auto-repeat; 255 = no auto-repeat
21 | '(only one action per button press)
22 | '
23 | 'The BUTTON instruction makes the program branch to No_Press unless P0 = 0
24 |
25 | PAUSE 5
26 | BUTTON Btn, 0, 200, 20, btnWrk, 0, No_Press
27 | DEBUG "*"
28 |
29 | No_Press:
30 | GOTO Main
--------------------------------------------------------------------------------
/src/views/help-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const Button = require('../components/button');
5 |
6 | const Overlay = require('../components/overlay');
7 | const OverlayTitle = require('../components/overlay-title');
8 | const OverlayFooter = require('../components/overlay-footer');
9 |
10 | const helpStyle = {
11 | position: 'relative',
12 | marginTop: '25px'
13 | };
14 |
15 | const helpLink = 'http://www.parallax.com/go/PBASICHelp';
16 |
17 | class HelpOverlay extends React.Component {
18 |
19 |
20 | render(){
21 | const {
22 | handlers
23 | } = this.props;
24 |
25 | const {
26 | hideOverlay
27 | } = handlers;
28 |
29 | return (
30 |
31 | Help
32 |
33 | For help with PBASIC go here:
{helpLink}
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
43 | module.exports = HelpOverlay;
44 |
--------------------------------------------------------------------------------
/src/lib/documents.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const CodeMirror = require('codemirror');
4 |
5 | class Documents {
6 | constructor(editor){
7 | this._editor = editor;
8 |
9 | this._filename = null;
10 | this._documents = {};
11 | }
12 |
13 | focus(){
14 | this._editor.focus();
15 | }
16 |
17 | update(text){
18 | if(!this._filename){
19 | return;
20 | }
21 |
22 | return this.create(this._filename, text);
23 | }
24 |
25 | create(filename, text){
26 | const mode = 'pbasic';
27 |
28 | this._documents[filename] = CodeMirror.Doc(text, mode);
29 |
30 | return this.swap(filename);
31 | }
32 |
33 | remove(filename){
34 | // TODO: remove something?
35 | delete this._documents[filename];
36 | }
37 |
38 | swap(filename) {
39 | this._filename = filename;
40 |
41 | const doc = this._documents[filename];
42 |
43 | if(!doc){
44 | return;
45 | }
46 |
47 | this._editor.swapDoc(doc);
48 | return doc;
49 | }
50 |
51 | replace(filename){
52 | this._documents[filename] = this._editor.getDoc();
53 | }
54 | }
55 |
56 | module.exports = Documents;
57 |
--------------------------------------------------------------------------------
/src/components/overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const React = require('react');
5 |
6 | const Card = require('./card');
7 |
8 | const styles = {
9 | overlay: {
10 | width: 400,
11 | height: 200,
12 | margin: '100px auto 0',
13 | display: 'flex',
14 | flexDirection: 'column'
15 | },
16 | overlayLarge: {
17 | height: 400
18 | },
19 | backdrop:{
20 | display: 'flex',
21 | position: 'fixed',
22 | top: 0,
23 | bottom: 0,
24 | left: 0,
25 | right: 0,
26 | backgroundColor: 'rgba(0,0,0,0.5)',
27 | zIndex: 10
28 | }
29 | };
30 |
31 | class Overlay extends React.Component {
32 | render(){
33 | const {
34 | large,
35 | children,
36 | style
37 | } = this.props;
38 |
39 | const cardStyle = _.assign({}, styles.overlay, style);
40 | if(large){
41 | _.assign(cardStyle, styles.overlayLarge);
42 | }
43 |
44 | return (
45 |
46 |
47 | {children}
48 |
49 |
50 | );
51 | }
52 | }
53 |
54 | module.exports = Overlay;
55 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Parallax Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/examples/IF-THEN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: IF-THEN
5 | 'The program below generates a series of 16-bit random numbers and tests
6 | 'each to determine whether they're evenly divisible by 3. If a number is
7 | 'evenly divisible by 3, then it is printed, otherwise, the program generates
8 | 'another random number. The program quits when it's printed 10 numbers.
9 |
10 | sample VAR Word 'Random number to be tested
11 | samps VAR Nib 'Number of samples taken
12 | temp VAR Nib 'Temporary workspace
13 |
14 |
15 | Setup:
16 | PAUSE 200 'short startup-pause
17 | sample = 11500
18 |
19 | Mult3:
20 | RANDOM sample 'Put a random number into sample
21 | temp = sample // 3
22 | IF temp <> 0 THEN Mult3 'Not multiple of 3? -- try again
23 | DEBUG DEC5 sample, " divides by 3", CR
24 | samps = samps + 1 'Count multiples of 3
25 | IF samps = 10 THEN Done 'Quit with 10 samples
26 | GOTO Mult3 'keep checking
27 |
28 | Done:
29 | DEBUG CR, "All done."
30 | END
--------------------------------------------------------------------------------
/examples/PWM.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: PWM
5 | 'Connect a voltmeter (such as a digital multimeter set to its voltage
6 | 'range) to the output of the circuit shown in the figure for the PWM
7 | 'command. Run the program and observe the readings on the meter. They
8 | 'should come very close to 1.96V, then decrease slightly as the capacitor
9 | 'discharges. Try varying the interval between PWM bursts (by changing the
10 | 'PAUSE value) and the number of PWM cycles to see their effect.
11 |
12 | #SELECT $stamp 'Set CycAdj according to module type
13 | #CASE BS2, BS2E
14 | CycAdj CON $100 'x 1.0, cycle adjustment (for ms)
15 | #CASE BS2SX
16 | CycAdj CON $280 'x 2.5
17 | #CASE BS2P
18 | CycAdj CON $187 'x 1.53
19 | #CASE BS2PE
20 | CycAdj CON $09E 'x 0.62
21 | #CASE BS2PX
22 | CycAdj CON $280 'x 2.5
23 | #ENDSELECT
24 |
25 | Cycles CON 50
26 |
27 | Main:
28 | DO
29 | PWM 0, 100, (Cycles */ CycAdj) 'PWM at 100/255 duty (~50 ms)
30 | PAUSE 1000 'wait one second
31 | LOOP
--------------------------------------------------------------------------------
/examples/INPUT_OUTPUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: INPUT_OUTPUT
5 | 'This program demonstrates how the input/output direction of a pin is
6 | 'determined by the corresponding bit of DIRS. It also shows that the
7 | 'state of the pin itself (as reflected by the corresponding bit of INx)
8 | 'is determined by the outside world when the pin is an input, and by the
9 | 'corresponding bit of INx when it's an output. To set up the demo,
10 | 'connect a 10k resistor from +5V to P7 on the BASIC Stamp. The resistor
11 | 'to +5V puts a high (1) on the pin when it's an input. The BASIC Stamp
12 | 'can override this state by writing a low (0) to bit 7 of OUTS and
13 | 'changing the pin to output.
14 |
15 | Init:
16 | PAUSE 200 'short startup-pause
17 |
18 | Main:
19 | INPUT 7 'Make P7 an input
20 | DEBUG "State of P7: ",
21 | BIN1 IN7, CR
22 |
23 | OUT7 = 0 'Write 0 to output latch
24 | DEBUG "After 0 written to OUT7: ",
25 | BIN1 IN7, CR
26 |
27 | OUTPUT 7 'Make P7 an output
28 | DEBUG "After P7 changed to output: ",
29 | BIN1 IN7
30 | END
--------------------------------------------------------------------------------
/examples/WRITE.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: WRITE
5 | 'This program writes some data to EEPROM and then reads them back out
6 | 'and displays the data in the Debug Terminal. It also demonstrates
7 | 'writing both bytes and words, and the results of reading values as
8 | 'bytes or words.
9 |
10 | idx VAR Byte 'loop control
11 | value VAR Word(3) 'value(s)
12 |
13 | Init:
14 | PAUSE 200 'short startup-pause
15 |
16 | Main:
17 | WRITE 0, 100 'single byte
18 | WRITE 1, Word 1250 'single word
19 | WRITE 3, 45, 90, Word 725 'multi-value write
20 |
21 | Read_EE:
22 | 'read values as bytes only
23 | DEBUG "Values as bytes:", CR
24 | FOR idx = 0 TO 6
25 | READ idx, value
26 | DEBUG DEC1 idx, " : ", DEC value, CR
27 | NEXT
28 | DEBUG CR
29 |
30 | 'read values as stored
31 | DEBUG "Values as written:", CR
32 | READ 0, value
33 | DEBUG DEC value, CR
34 | READ 1, Word value
35 | DEBUG DEC value, CR
36 | READ 3, value(0), value(1), Word value(2)
37 | FOR idx = 0 TO 2
38 | DEBUG DEC value(idx), CR
39 | NEXT
40 | END
--------------------------------------------------------------------------------
/examples/REVERSE.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: REVERSE
5 | 'Connect the circuit shown in the REVERSE command description to I/O pin
6 | '0 and run this program. The LED will alternate between two states, dim
7 | 'and bright. The BASIC Stamp is using the REVERSE command to toggle I/O
8 | 'pin 0 between input and output states. When pin 0 is an input, current
9 | 'flows through R1, through the LED, through R2 to ground. Pin 0 is
10 | 'effectively disconnected and doesn't play a part in the circuit. The total
11 | 'resistance encountered by current flowing through the LED is R1 + R2 = 1220
12 | 'ohms. When pin 0 is reversed to an output, current flows through R1, through
13 | 'the LED, and into pin 0 to ground (because of the 0 written to OUT0). The
14 | 'total resistance encountered by current flowing through the LED is R1,
15 | '220 ohms. With only 20% of the resistance, the LED glows brighter.
16 |
17 | Setup:
18 | OUT0 = 0 'Put a low in the pin 0
19 | ' output driver
20 | Main:
21 | DO
22 | PAUSE 250 '1/4th second pause
23 | REVERSE 0 'reverse pin 0 I/O direction
24 | LOOP 'do forever
--------------------------------------------------------------------------------
/src/constants/action-types.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const actionTypes = {
4 | SHOW_OVERLAY: 'SHOW_OVERLAY',
5 | HIDE_OVERLAY: 'HIDE_OVERLAY',
6 | DELETE_PROJECT_CONFIRM: 'DELETE_PROJECT_CONFIRM',
7 | ECHO_ON: 'ECHO_ON',
8 | ECHO_OFF: 'ECHO_OFF',
9 | RX_ON: 'RX_ON',
10 | RX_OFF: 'RX_OFF',
11 | RX_CLEAR_TIMEOUT: 'RX_CLEAR_TIMEOUT',
12 | TX_ON: 'TX_ON',
13 | TX_OFF: 'TX_OFF',
14 | TX_CLEAR_TIMEOUT: 'TX_CLEAR_TIMEOUT',
15 | RECEIVE: 'RECEIVE',
16 | TRANSMIT: 'TRANSMIT',
17 | UPDATE_DURATION: 'UPDATE_DURATION',
18 | CLEAR_TRANSMISSION: 'CLEAR_TRANSMISSION',
19 | CONNECT: 'CONNECT',
20 | DISCONNECT: 'DISCONNECT',
21 | RELOAD_DEVICES: 'RELOAD_DEVICES',
22 | UPDATE_DEVICES: 'UPDATE_DEVICES',
23 | ENABLE_AUTO_DOWNLOAD: 'ENABLE_AUTO_DOWNLOAD',
24 | DISABLE_AUTO_DOWNLOAD: 'DISABLE_AUTO_DOWNLOAD',
25 | UPDATE_SEARCH_STATUS: 'UPDATE_SEARCH_STATUS',
26 | CLEAR_SEARCH_STATUS: 'CLEAR_SEARCH_STATUS',
27 | UPDATE_SELECTED_DEVICE: 'UPDATE_SELECTED_DEVICE',
28 | RESET_DOWNLOAD_PROGRESS: 'RESET_DOWNLOAD_PROGRESS',
29 | UPDATE_DOWNLOAD_PROGRESS: 'UPDATE_DOWNLOAD_PROGRESS',
30 | QUEUE_NEW_FILE: 'QUEUE_NEW_FILE',
31 | QUEUE_CHANGE_FILE: 'QUEUE_CHANGE_FILE',
32 | QUEUE_OVERWRITE_FILE: 'QUEUE_OVERWRITE_FILE',
33 | RESET_ACTION_QUEUE: 'RESET_ACTION_QUEUE'
34 | };
35 |
36 | module.exports = actionTypes;
37 |
--------------------------------------------------------------------------------
/src/plugins/notifications.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const red = '#da2100';
4 | const green = '#159600';
5 |
6 | const styles = {
7 | errorToast: {
8 | backgroundColor: red
9 | },
10 | successToast: {
11 | backgroundColor: green
12 | }
13 | };
14 |
15 | function notifications({ workspace, toast }, opts, done){
16 |
17 | const {
18 | SAVE_FILE_SUCCESS,
19 | SAVE_FILE_FAILURE,
20 | DELETE_FILE_SUCCESS,
21 | DELETE_FILE_FAILURE,
22 | CHANGE_FILE_FAILURE,
23 | DELETE_DIRECTORY_SUCCESS,
24 | DELETE_DIRECTORY_FAILURE,
25 | CHANGE_DIRECTORY_FAILURE
26 | } = workspace.STATUS_CONSTANTS;
27 |
28 | workspace.subscribe(() => {
29 | const { status, notification } = workspace.getState();
30 |
31 | switch(status){
32 | case SAVE_FILE_SUCCESS:
33 | case DELETE_FILE_SUCCESS:
34 | case DELETE_DIRECTORY_SUCCESS:
35 | toast.show(notification, { style: styles.successToast, timeout: 5000 });
36 | break;
37 | case SAVE_FILE_FAILURE:
38 | case DELETE_FILE_FAILURE:
39 | case CHANGE_FILE_FAILURE:
40 | case DELETE_DIRECTORY_FAILURE:
41 | case CHANGE_DIRECTORY_FAILURE:
42 | toast.show(notification, { style: styles.errorToast });
43 | break;
44 | }
45 | });
46 |
47 | done();
48 | }
49 |
50 | module.exports = notifications;
51 |
--------------------------------------------------------------------------------
/src/views/delete-project-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { createContainer } = require('sovereign');
5 | const Button = require('../components/button');
6 |
7 | const Overlay = require('../components/overlay');
8 | const OverlayTitle = require('../components/overlay-title');
9 | const OverlayFooter = require('../components/overlay-footer');
10 | const history = require('../lib/history');
11 |
12 | class DeleteProjectOverlay extends React.Component {
13 | render(){
14 | const {
15 | name,
16 | handlers
17 | } = this.props;
18 |
19 | const {
20 | deleteProject
21 | } = handlers;
22 |
23 | return (
24 |
25 | Are you sure you want to delete {name}?
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 | }
34 |
35 | module.exports = createContainer(DeleteProjectOverlay, {
36 | getStores({ store }){
37 | return {
38 | store
39 | };
40 | },
41 |
42 | getPropsFromStores({ store }){
43 | const { deleteProjectName } = store.getState();
44 |
45 | return {
46 | name: deleteProjectName
47 | };
48 | }
49 | });
50 |
--------------------------------------------------------------------------------
/src/views/overwrite-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { createContainer } = require('sovereign');
5 | const Button = require('../components/button');
6 |
7 | const Overlay = require('../components/overlay');
8 | const OverlayTitle = require('../components/overlay-title');
9 | const OverlayFooter = require('../components/overlay-footer');
10 | const history = require('../lib/history');
11 |
12 | class OverwriteOverlay extends React.Component {
13 |
14 | render(){
15 | const {
16 | filename,
17 | handlers
18 | } = this.props;
19 |
20 | const {
21 | overwriteFile,
22 | cancelOverwriteFile
23 | } = handlers;
24 |
25 | return (
26 |
27 | File '{filename}' already exists. Overwrite anyway?
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | module.exports = createContainer(OverwriteOverlay, {
38 | getStores({ store }){
39 | return {
40 | store
41 | };
42 | },
43 |
44 | getPropsFromStores({ store }){
45 | const { nextFile } = store.getState();
46 |
47 | return {
48 | filename: nextFile
49 | };
50 | }
51 | });
52 |
--------------------------------------------------------------------------------
/src/reducers/rxtx.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | Don't include this in the index.js because it is used only
5 | for the console-store
6 | */
7 |
8 | const _ = require('lodash');
9 |
10 | const {
11 | RX_ON,
12 | RX_OFF,
13 | RX_CLEAR_TIMEOUT,
14 | TX_ON,
15 | TX_OFF,
16 | TX_CLEAR_TIMEOUT,
17 | UPDATE_DURATION
18 | } = require('../constants/action-types');
19 |
20 | const initial = {
21 | flashRx: false,
22 | rxTimeout: null,
23 | flashTx: false,
24 | txTimeout: null,
25 | duration: 100,
26 | offDuration: 50
27 | };
28 |
29 | function rxtx(state = initial, { type, payload }){
30 | switch(type){
31 | case RX_ON:
32 | return _.assign({}, state, { flashRx: true, rxTimeout: payload.timeout });
33 | case RX_OFF:
34 | return _.assign({}, state, { flashRx: false });
35 | case RX_CLEAR_TIMEOUT:
36 | return _.assign({}, state, { flashRx: false, rxTimeout: null });
37 | case TX_ON:
38 | return _.assign({}, state, { flashTx: true, txTimeout: payload.timeout });
39 | case TX_OFF:
40 | return _.assign({}, state, { flashTx: false });
41 | case TX_CLEAR_TIMEOUT:
42 | return _.assign({}, state, { flashTx: false, txTimeout: null });
43 | case UPDATE_DURATION:
44 | return _.assign({}, state, { duration: payload.duration });
45 | default:
46 | return state;
47 | }
48 | }
49 |
50 | module.exports = rxtx;
51 |
--------------------------------------------------------------------------------
/examples/RCTIME2.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: RCTIME2
5 | 'This program illustrates the use of RCTIME as a fast stopwatch. The
6 | 'program energizes a relay coil, then measures how long it takes for the
7 | 'relay contacts to close. Use the circuit found in the RCTIME description.
8 | 'Note that RCTIME doesn't start timing instantly -- as with all PBASIC
9 | 'commands, it must be fetched from the program's EEPROM before executeing.
10 |
11 | Coil PIN 6
12 | RC PIN 7
13 |
14 | #SELECT $STAMP 'Set Adjust according to module type
15 | #CASE BS2, BS2E, BS2PE
16 | Adjust CON $200 'x 2 us per unit
17 | #CASE BS2SX
18 | Adjust CON $0CC 'x 0.8 us per unit
19 | #CASE BS2P, BS2PX
20 | Adjust CON $0C0 'x 0.75 us per unit
21 | #ENDSELECT
22 |
23 | result VAR Word
24 |
25 | Init:
26 | PAUSE 200 'short startup-pause
27 |
28 | Main:
29 | DO
30 | LOW Coil 'energize relay coil
31 | RCTIME RC, 1, result 'measure time to contact closure
32 | result = result */ Adjust 'adjust for device
33 | DEBUG "Time to close: ", DEC Result, CR
34 | HIGH Coil 'release relay
35 | PAUSE 1000 'wait one second
36 | LOOP
--------------------------------------------------------------------------------
/examples/IF-THEN-ELSE.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: IF-THEN-ELSE
5 | 'This program is an expansion on IF-THEN. It generates a series of 16-bit
6 | 'random numbers and tests each to determine whether they're evenly divisible
7 | 'by 3. If a number is evenly divisible by 3, then it is printed, otherwise,
8 | 'the program generates another random number. The program quits when it's
9 | 'printed 10 numbers. It also displays the tallied up Hits, Misses, and Samples.
10 |
11 | sample VAR Word 'Random number to be tested
12 | hits VAR Nib 'Number of hits
13 | misses VAR Word 'Number of misses
14 |
15 | Setup:
16 | PAUSE 200 'short startup-pause
17 | sample = 11500
18 |
19 | Main:
20 | DO
21 | RANDOM sample 'Put a random number into sample
22 | IF ((sample // 3) = 0) THEN 'divisible by 3?
23 | DEBUG DEC5 sample, '- yes, print value and message
24 | " is divisible by 3", CR
25 | hits = hits + 1 'count hits (divisble by 3)
26 | ELSE
27 | misses = misses + 1 'count misses
28 | ENDIF
29 | LOOP UNTIL (hits = 10) 'quit after 10 hits
30 |
31 | DEBUG CR,
32 | "All done.", CR, CR, 'display results
33 | "Hits: ", DEC hits, CR,
34 | "Misses: ", DEC misses, CR,
35 | "Samples: ", DEC (hits + misses)
36 | END
--------------------------------------------------------------------------------
/examples/SHIFTIN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: SHIFTIN
5 | 'This program uses the SHIFTIN instruction to interface with the ADC0831
6 | '8-bit analog-to-digital converter from National Semiconductor.
7 |
8 | CS PIN 0 'chip select
9 | AData PIN 1 'data pin
10 | Clk PIN 2 'clock pin
11 |
12 | adcRes VAR Byte 'ADC result
13 |
14 | Setup:
15 | PAUSE 200 'short startup-pause
16 | HIGH CS 'deselect ADC
17 |
18 | 'In the loop below, just three lines of code are required to read the
19 | 'ADC0831. The SHIFTIN command does most of the work. The mode argument in
20 | 'the SHIFTIN command specifies MSB or LSB-first and whether to sample data
21 | 'before or after the clock. In this case, we chose MSB-first, post-clock.
22 | 'The ADC0831 precedes its data output with a dummy bit, which we take care
23 | 'of by specifying 9 bits of data instead of 8.
24 |
25 | Main:
26 | DO
27 | LOW CS 'activate the ADC0831
28 | SHIFTIN AData, Clk, MSBPOST, [adcRes\9] 'shift in the data
29 | HIGH CS 'deactivate ADC0831
30 | DEBUG ? adcRes 'show conversion result
31 | PAUSE 1000 'wait one second
32 | LOOP 'repeat
--------------------------------------------------------------------------------
/examples/DO-LOOP.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: DO-LOOP
5 | 'This program creates a little guessing game. It starts by creating
6 | 'a (psuedo) random number between 1 and 10. The inner loop will run
7 | 'until the answer is guessed or 3 tries have been attempted. The
8 | 'outer loop has no condition and will cause the inner loop code to
9 | 'run until the BASIC Stamp is reprogrammed.
10 |
11 | rVal VAR Word 'random value
12 | answer VAR Byte 'game answer
13 | guess VAR Byte 'player guess
14 | tries VAR Nib 'number of tries
15 |
16 | Init:
17 | PAUSE 200 'short startup-pause
18 |
19 | Main:
20 | DO
21 | RANDOM rVal
22 | answer = rVal.LOWBYTE */ 10 + 1 'create 1 - 10 answer
23 | tries = 0
24 |
25 | DO 'get answer until out of tries
26 | DEBUG CLS, "Guess a number (1 - 10). ", CLREOL
27 | DEBUGIN DEC guess 'get new guess
28 | tries = tries + 1 'update tries count
29 | IF (guess <> answer) THEN
30 | DEBUG CR, "Wrong."
31 | PAUSE 500
32 | ENDIF
33 | LOOP UNTIL ((tries = 3) OR (guess = answer))
34 |
35 | IF (guess = answer) THEN ' test reason for loop end
36 | DEBUG CR, "You got it!"
37 | ELSE
38 | DEBUG CR, "Sorry ... the answer was ", DEC answer, "."
39 | ENDIF
40 | PAUSE 1000
41 | LOOP ' run again
--------------------------------------------------------------------------------
/examples/AUX_TERM.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: AUX_MAIN_TERM
5 | 'This program demonstrates the use of the AUXIO, MAINIO and IOTERM
6 | 'commands to affect I/O pins in the auxiliary and main I/O groups.
7 |
8 | Init:
9 | PAUSE 200 'short startup-pause
10 |
11 | #SELECT $STAMP 'Notify of module requirements
12 | #CASE BS2, BS2E, BS2SX
13 | #ERROR "Program requires BS2p40"
14 | #CASE BS2P, BS2PE, BS2PX
15 | DEBUG "Note: This program is designed for the BS2p40.", CR
16 | #ENDSELECT
17 |
18 | port VAR Bit
19 |
20 | Main:
21 | DO
22 | MAINIO 'Switch to main I/O pins
23 | TOGGLE 0 'Toggle state of I/O pin P0
24 | PWM 1, 100, 40 'Generate PWM on I/O pin P1
25 |
26 | AUXIO 'Switch to auxiliary I/O pins
27 | TOGGLE 0 'Toggle state of I/O pin X0
28 | PULSOUT 1, 1000 'Generate a pulse on I/O pin X1
29 | PWM 2, 100, 40 'Generate PWM on I/O pin X2
30 |
31 | IOTERM port 'Switch to main or aux I/Os
32 | '-- depending on port
33 | TOGGLE 3 'Toggle state of I/O pin 3
34 | '-- on main and aux, alternately
35 | port = ~port 'Invert port
36 | PAUSE 1000 '1 second delay
37 | LOOP
38 |
--------------------------------------------------------------------------------
/gulpfile.babel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 |
5 | const del = require('del');
6 | const gulp = require('gulp');
7 | const chalk = require('chalk');
8 | const zip = require('gulp-zip');
9 | const gutil = require('gulp-util');
10 | const webpack = require('webpack');
11 |
12 | const webpackConfig = require('./webpack.config');
13 |
14 | const files = {
15 | release: [
16 | 'manifest.json',
17 | 'index.html',
18 | 'bundle.js',
19 | 'background.js',
20 | '_locales/**',
21 | 'icons/**',
22 | 'fonts/**',
23 | 'assets/**'
24 | ]
25 | };
26 |
27 | function js(cb){
28 | webpack(webpackConfig, function(err){
29 | gutil.log(chalk.green('Webpack - JS Rebuilt'));
30 | cb(err);
31 | });
32 | }
33 |
34 | function release(){
35 | return gulp.src(files.release, { base: __dirname })
36 | .pipe(zip('parallax-ide.zip'))
37 | .pipe(gulp.dest('dist'));
38 | }
39 |
40 | function postinstall(cb){
41 | // .pem files cause Chrome to show a bunch of warnings
42 | // so we remove them on postinstall
43 | del('node_modules/**/*.pem', cb);
44 | }
45 |
46 | function version(cb){
47 | const pkg = require('./package.json');
48 | const manifest = require('./manifest.json');
49 | manifest.version = pkg.version;
50 | const content = `${JSON.stringify(manifest, null, 2)}\n`;
51 | fs.writeFile('./manifest.json', content, cb);
52 | }
53 |
54 | gulp.task(version);
55 | gulp.task(release);
56 | gulp.task(postinstall);
57 |
58 | gulp.task('gh-release', gulp.series(js, release));
59 | gulp.task('default', gulp.parallel(js));
60 |
--------------------------------------------------------------------------------
/src/views/new-version-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const Button = require('../components/button');
5 |
6 | const Overlay = require('../components/overlay');
7 | const OverlayTitle = require('../components/overlay-title');
8 | const OverlayFooter = require('../components/overlay-footer');
9 |
10 | const contentStyle = {
11 | position: 'relative',
12 | marginTop: '25px'
13 | };
14 |
15 | const releaseNotesLink = 'https://github.com/parallaxinc/Parallax-IDE/releases';
16 | const installationNotesLink = 'https://www.parallax.com/package/parallax-ide-for-chrome/';
17 |
18 | class NewVersionOverlay extends React.Component {
19 |
20 | render(){
21 |
22 | const {
23 | handlers
24 | } = this.props;
25 |
26 | const {
27 | hideOverlay
28 | } = handlers;
29 |
30 | const {
31 | name,
32 | version
33 | } = chrome.runtime.getManifest();
34 |
35 | return (
36 |
37 | {name} Automatically Updated to v{version}
38 |
39 | You are now running a new release of {name}!
40 |
41 |
44 |
45 |
46 |
47 |
48 | );
49 | }
50 | }
51 |
52 | module.exports = NewVersionOverlay;
53 |
--------------------------------------------------------------------------------
/src/creators/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const creators = {
4 | // overlay creators
5 | deleteProjectConfirm: require('./delete-project-confirm'),
6 | // terminal creators
7 | rxOn: require('./rx-on'),
8 | rxOff: require('./rx-off'),
9 | rxClearTimeout: require('./rx-clear-timeout'),
10 | txOn: require('./tx-on'),
11 | txOff: require('./tx-off'),
12 | txClearTimeout: require('./tx-clear-timeout'),
13 | receive: require('./receive'),
14 | transmit: require('./transmit'),
15 | updateDuration: require('./update-duration'),
16 | clearTransmission: require('./clear-transmission'),
17 | echoOn: require('./echo-on'),
18 | echoOff: require('./echo-off'),
19 | // device creators
20 | connect: require('./connect'),
21 | disconnect: require('./disconnect'),
22 | reloadDevices: require('./reload-devices'),
23 | updateDevices: require('./update-devices'),
24 | enableAutoDownload: require('./enable-auto-download'),
25 | disableAutoDownload: require('./disable-auto-download'),
26 | updateSearchStatus: require('./update-search-status'),
27 | clearSearchStatus: require('./clear-search-status'),
28 | updateSelectedDevice: require('./update-selected-device'),
29 | resetDownloadProgress: require('./reset-download-progress'),
30 | updateDownloadProgress: require('./update-download-progress'),
31 | // action queue creators
32 | queueNewFile: require('./queue-new-file'),
33 | queueChangeFile: require('./queue-change-file'),
34 | queueOverwriteFile: require('./queue-overwrite-file'),
35 | resetActionQueue: require('./reset-action-queue')
36 | };
37 |
38 | module.exports = creators;
39 |
--------------------------------------------------------------------------------
/examples/COUNT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: COUNT
5 | 'Connect an active-low button (shown in the BUTTON command description) to pin P0
6 | 'of the BASIC Stamp. The Debug Terminal will prompt you to press the button as
7 | 'quickly as possible for a 1-second period. When the count is done, the screen
8 | 'will display your "score," the total number of cycles registered by COUNT. Note
9 | 'that this score will almost always be greater than the actual number of presses
10 | 'because of mechanical switch contact bounce.
11 |
12 | PushBtn PIN 0 'Button on P0
13 |
14 | Capture CON 1000 '1 second
15 |
16 | #SELECT $STAMP 'Set DurAdj according to module type
17 | #CASE BS2, BS2E
18 | DurAdj CON $100 '/ 1
19 | #CASE BS2SX
20 | DurAdj CON $280 '/ 0.400
21 | #CASE BS2P, BS2PX
22 | DurAdj CON $37B '/ 0.287
23 | #CASE BS2PE
24 | DurAdj CON $163 '/ 0.720
25 | #ENDSELECT
26 |
27 | cycles VAR Word 'counted cycles
28 |
29 | Init:
30 | PAUSE 200 'short startup-pause
31 |
32 | Main:
33 | DO
34 | DEBUG CLS, "How many times can you press the button in 1 second?", CR
35 | PAUSE 1000
36 | DEBUG "Ready, set... "
37 | PAUSE 500
38 | DEBUG "GO!", CR
39 | COUNT PushBtn, (Capture */ DurAdj), cycles
40 | DEBUG CR, "Your score: ", DEC cycles, CR
41 | PAUSE 3000
42 | DEBUG "Press button to go again."
43 | DO : LOOP UNTIL (PushBtn = 0) 'wait for button press
44 | LOOP
--------------------------------------------------------------------------------
/examples/RANDOM.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: RANDOM
5 | 'This program uses RANDOM to simulate a coin toss. After 100 trials, it reports
6 | 'the total number of heads and tails thrown. Connect a button to I/O pin 7 as
7 | 'shown in the RANDOM command description and run this program.
8 |
9 | Btn PIN 7 'button input
10 |
11 | flip VAR Word 'a random number
12 | coin VAR flip.BIT0 'Bit0 of the random number
13 | trials VAR Byte 'number of flips
14 | heads VAR Byte 'throws that come up heads
15 | tails VAR Byte 'throws that come up tails
16 | btnWrk VAR Byte 'workspace for BUTTON
17 |
18 | Init:
19 | PAUSE 200 'short startup-pause
20 |
21 | Start:
22 | DEBUG CLS, "Press button to start"
23 |
24 | Main:
25 | FOR trials = 1 TO 100 'flip coin 100 times
26 |
27 | Hold:
28 | RANDOM flip 'randomize while waiting
29 | BUTTON Btn, 0, 250, 100, btnWrk, 0, Hold 'wait for button press
30 | IF (coin = 0) THEN '0 = heads, 1 = tails
31 | DEBUG CR, "Heads!"
32 | heads = heads + 1 'increment heads counter
33 | ELSE
34 | DEBUG CR, "Tails..."
35 | tails = tails + 1 'increment tails counter
36 | ENDIF
37 | NEXT
38 |
39 | Done:
40 | DEBUG CR, CR, "Heads: ", DEC heads, " Tails: ", DEC tails
41 | END
--------------------------------------------------------------------------------
/src/views/delete-file-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { createContainer } = require('sovereign');
5 | const Button = require('../components/button');
6 |
7 | const Overlay = require('../components/overlay');
8 | const OverlayTitle = require('../components/overlay-title');
9 | const OverlayFooter = require('../components/overlay-footer');
10 |
11 | class DeleteFileOverlay extends React.Component {
12 |
13 | constructor(...args){
14 | super(...args);
15 |
16 | this.delete = this.delete.bind(this);
17 | }
18 |
19 | delete(){
20 | const {
21 | filename,
22 | handlers
23 | } = this.props;
24 |
25 | const {
26 | deleteFile,
27 | hideOverlay
28 | } = handlers;
29 |
30 | deleteFile(filename);
31 | hideOverlay();
32 | }
33 |
34 | render(){
35 | const {
36 | filename,
37 | handlers
38 | } = this.props;
39 |
40 | const {
41 | hideOverlay
42 | } = handlers;
43 |
44 | return (
45 |
46 | Are you sure you want to delete {filename}?
47 |
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | module.exports = createContainer(DeleteFileOverlay, {
57 | getStores({ workspace }){
58 | return {
59 | workspace
60 | };
61 | },
62 |
63 | getPropsFromStores({ workspace }){
64 | const { filename } = workspace.getState();
65 |
66 | return {
67 | filename
68 | };
69 | }
70 | });
71 |
--------------------------------------------------------------------------------
/examples/PULSIN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: PULSIN
5 | 'This program uses PULSIN to measure a pulse generated by discharging a
6 | '0.1 uF capacitor through a 1K resistor. Pressing the switch generates
7 | 'the pulse, which should ideally be approximately 120 us (60 PULSIN units
8 | 'of 2 us) long (for BS2 and BS2e). Variations in component values may
9 | 'produce results that are up to 10 units off from this value. For more
10 | 'information on calculating resistor-capacitor timing, see the RCTIME
11 | 'command.
12 |
13 | Pulse PIN 7 'pulse input pin
14 |
15 | #SELECT $STAMP 'Set Scale according to module type
16 | #CASE BS2, BS2E, BS2PE
17 | Scale CON $200 '2.0 us per unit
18 | #CASE BS2SX
19 | Scale CON $0CC '0.8 us per unit
20 | #CASE BS2P
21 | Scale CON $0C0 '0.75 us per unit
22 | #CASE BS2PX
23 | Scale CON $0CF '0.81 us per unit
24 | #ENDSELECT
25 |
26 | time VAR Word
27 |
28 | Init:
29 | PAUSE 200 'short startup-pause
30 |
31 | Main:
32 | DO
33 | PULSIN Pulse, 1, time 'measure positive pulse
34 | IF (time > 0) THEN 'if not 0
35 | DEBUG HOME, DEC time, " units ", CLREOL 'display raw input
36 | time = time */ Scale 'adjust for Stamp
37 | DEBUG CR, DEC time, " us " 'display microseconds
38 | ELSE
39 | DEBUG CLS, "Out of Range" 'else error message
40 | ENDIF
41 | PAUSE 200
42 | LOOP
43 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 |
6 | var webpack = require('webpack');
7 |
8 | var shouldWatch = (process.argv.indexOf('--watch') !== -1);
9 |
10 | var examplesDir = './examples';
11 | var examples = fs.readdirSync(examplesDir);
12 |
13 | module.exports = {
14 | devtool: 'source-map',
15 | entry: './client.js',
16 | output: {
17 | path: __dirname,
18 | filename: 'bundle.js'
19 | },
20 | module: {
21 | noParse: [
22 | /pbasic/i
23 | ],
24 | loaders: [
25 | {
26 | test: /\.css$/,
27 | loader: 'style-loader!css-loader'
28 | },
29 | {
30 | test: /\.html$/,
31 | loader: 'html-loader'
32 | },
33 | {
34 | test: /\.json$/,
35 | loader: 'json-loader'
36 | },
37 | {
38 | test: /\.bs2$/,
39 | loader: 'raw-loader'
40 | },
41 | {
42 | test: /\.js$/,
43 | exclude: [
44 | /node_modules/,
45 | /pbasic/i
46 | ],
47 | loaders: [
48 | 'babel-loader?optional=runtime'
49 | ]
50 | }
51 | ]
52 | },
53 | plugins: [
54 | new webpack.optimize.DedupePlugin(),
55 | new webpack.DefinePlugin({
56 | EXAMPLES_LIST: JSON.stringify(examples)
57 | })
58 | ],
59 | resolveLoader: {
60 | // this is a workaround for loaders being applied
61 | // to linked modules
62 | root: path.join(__dirname, 'node_modules')
63 | },
64 | resolve: {
65 | // this is a workaround for aliasing a top level dependency
66 | // inside a symlinked subdependency
67 | root: path.join(__dirname, 'node_modules'),
68 | alias: {
69 | memdown: 'level-js'
70 | }
71 | },
72 | bail: true,
73 | watch: shouldWatch
74 | };
75 |
--------------------------------------------------------------------------------
/examples/SERIN_SEROUT1.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: SERIN_SEROUT1
5 | 'Using two BS2-IC's, connect the circuit shown in the SERIN command
6 | 'description and run this program on the BASIC Stamp designated as the
7 | 'Sender. This program demonstrates the use of Flow Control (FPin).
8 | 'Without flow control, the sender would transmit the whole word "Hello!"
9 | 'in about 1.5 ms. The receiver would catch the first byte at most; by the
10 | 'time it got back from the first 1-second PAUSE, the rest of the data
11 | 'would be long gone. With flow control, communication is flawless since
12 | 'the sender waits for the receiver to catch up.
13 |
14 | SO PIN 1 'serial output
15 | FC PIN 0 'flow control pin
16 |
17 | #SELECT $STAMP 'Set values according to module type
18 | #CASE BS2, BS2E, BS2PE
19 | T1200 CON 813
20 | T2400 CON 396
21 | T9600 CON 84
22 | T19K2 CON 32
23 | T38K4 CON 6
24 | #CASE BS2SX, BS2P
25 | T1200 CON 2063
26 | T2400 CON 1021
27 | T9600 CON 240
28 | T19K2 CON 110
29 | T38K4 CON 45
30 | #CASE BS2PX
31 | T1200 CON 3313
32 | T2400 CON 1646
33 | T9600 CON 396
34 | T19K2 CON 188
35 | T38K4 CON 84
36 | #ENDSELECT
37 |
38 | Inverted CON $4000
39 | Open CON $8000
40 | Baud CON T9600 + Inverted
41 |
42 | Init:
43 | PAUSE 200 'short startup-pause
44 |
45 | Main:
46 | DO
47 | SEROUT SO\FC, Baud, ["Hello!", CR] 'send the greeting
48 | PAUSE 2500 'wait 2.5 seconds
49 | LOOP 'repeat forever
--------------------------------------------------------------------------------
/src/reducers/device.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 |
5 | const {
6 | CONNECT,
7 | DISCONNECT,
8 | RELOAD_DEVICES,
9 | UPDATE_DEVICES,
10 | ENABLE_AUTO_DOWNLOAD,
11 | DISABLE_AUTO_DOWNLOAD,
12 | UPDATE_SEARCH_STATUS,
13 | CLEAR_SEARCH_STATUS,
14 | UPDATE_SELECTED_DEVICE
15 | } = require('../constants/action-types');
16 |
17 | const initial = {
18 | path: null,
19 | selected: null,
20 | searching: true,
21 | connected: false,
22 | // TODO: not sure if this should be here
23 | autoDownload: true,
24 | // TODO: I don't think search status should be in here
25 | searchStatus: null
26 | };
27 |
28 | function device(state = initial, { type, payload }){
29 | switch(type){
30 | case CONNECT:
31 | return _.assign({}, state, { connected: true });
32 | case DISCONNECT:
33 | return _.assign({}, state, { connected: false });
34 | case RELOAD_DEVICES:
35 | return _.assign({}, state, { path: null, searching: true, searchStatus: null });
36 | case UPDATE_DEVICES:
37 | return _.assign({}, state, { searching: false });
38 | case ENABLE_AUTO_DOWNLOAD:
39 | return _.assign({}, state, { autoDownload: true });
40 | case DISABLE_AUTO_DOWNLOAD:
41 | return _.assign({}, state, { autoDownload: false });
42 | case UPDATE_SEARCH_STATUS:
43 | return _.assign({}, state, { searchStatus: payload.status });
44 | case CLEAR_SEARCH_STATUS:
45 | return _.assign({}, state, { searchStatus: payload.status });
46 | case UPDATE_SELECTED_DEVICE:
47 | // TODO: not sure if it is better to set searchStatus
48 | // to null when we update or dispatch a clear separately
49 | return _.assign({}, state, { selected: payload.device, path: payload.device.path, searchStatus: null });
50 | default:
51 | return state;
52 | }
53 | }
54 |
55 | module.exports = device;
56 |
--------------------------------------------------------------------------------
/examples/SHIFTOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: SHIFTOUT
5 | 'This program uses the SHIFTOUT command to interface to the 74HC595 shift
6 | 'register as an 8-bit output port. The 74HC595 requires a minimum of three
7 | 'inputs: data, clock, and latch. See the figure in the SHIFTOUT command
8 | 'description for wiring information. SHIFTOUT automatically handles the data
9 | 'and clock, pulsing the clock to shift data bits into the 74HC595. An extra
10 | 'step (pulsing the latch input) is required to move the shifted bits in
11 | 'parallel onto the 74HC595's output pins. Note: this code does not control
12 | 'the output-enable or reset lines of the 74HC595. This means that before the
13 | 'BASIC Stamp first sends, the 74HC595's output latches are turned on and may
14 | 'contain random data. In critical applications, you should hold output-enable
15 | 'high (disabled) until the BASIC Stamp can take control.
16 |
17 | Dpin PIN 0 'data pin to 74HC595
18 | Clk PIN 1 'shift clock to 74HC595
19 | Latch PIN 2 'latch 74HC595 outputs
20 |
21 | counter VAR Byte
22 |
23 | Setup:
24 | LOW Latch 'initialize latch output
25 |
26 | 'This loop moves the 8-bit value 'counter' onto the output lines of the
27 | '74HC595, pauses, then increments counter and repeats. The data is shifted
28 | 'msb first so that the msb appears on pin QH and the lsb on QA. Changing
29 | 'MSBFIRST to LSBFIRST causes the data to appear backwards on the outputs.
30 |
31 | Main:
32 | DO
33 | SHIFTOUT Dpin, Clk, MSBFIRST, [counter] 'send the bits
34 | PULSOUT Latch, 1 'transfer to outputs
35 | PAUSE 100 'Wait 0.1 seconds
36 | counter = counter + 1 'increment counter
37 | LOOP
--------------------------------------------------------------------------------
/examples/LCDCMD.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: LCDCMD
5 | 'This program demonstrates initialization and printing on a 2 x 16
6 | 'character LCD display. The set of "LCD constants", below, are provided
7 | 'as pre-defined and useful LCD commands, though not all are actually
8 | 'used in this program.
9 |
10 | #IF ($stamp < BS2P) #THEN 'Notify of module requirements
11 | #ERROR "Program requires BS2p, BS2pe, or BS2px."
12 | #ENDIF
13 |
14 | Lcd PIN 0
15 |
16 | LcdCls CON $01 'clear the LCD
17 | LcdHome CON $02 'move cursor home
18 | LcdCrsrL CON $10 'move cursor left
19 | LcdCrsrR CON $14 'move cursor right
20 | LcdDispL CON $18 'shift chars left
21 | LcdDispR CON $1C 'shift chars right
22 | LcdDDRam CON $80 'Display Data RAM
23 | LcdCGRam CON $40 'Character Generator RAM
24 | LcdLine1 CON $80 'DDRAM address of line 1
25 | LcdLine2 CON $C0 'DDRAM address of line 2
26 |
27 |
28 | Init_LCD:
29 | PAUSE 1000 'allow LCD to self-initialize first
30 | LCDCMD Lcd, %00110000 'send wakeup sequence to LCD
31 | PAUSE 5 'pause required by LCD specs
32 | LCDCMD Lcd, %00110000
33 | PAUSE 0 'pause required by LCD specs
34 | LCDCMD Lcd, %00110000
35 | PAUSE 0 'pause required by LCD specs
36 | LCDCMD Lcd, %00100000 'set data bus to 4-bit mode
37 | LCDCMD Lcd, %00101000 'set to 2-line mode with 5x8 font
38 | LCDCMD Lcd, %00001100 'display on without cursor
39 | LCDCMD Lcd, %00000110 'auto-increment cursor
40 |
41 | Main:
42 | DO
43 | LCDOUT Lcd, LcdCls, ["Hello, World!"]
44 | LCDOUT Lcd, LcdLine2, ["How are you?"]
45 | PAUSE 3000
46 | LCDCMD Lcd, LcdCls
47 | PAUSE 500
48 | LOOP
--------------------------------------------------------------------------------
/examples/LCDINIT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: LCDINIT
5 | 'This program demonstrates initialization and printing on a 2 x 16
6 | 'character LCD display. The set of "LCD constants", below, are provided
7 | 'as pre-defined and useful LCD commands, though not all are actually
8 | 'used in this program.
9 |
10 | #IF ($STAMP < BS2P) #THEN 'Notify of module requirements
11 | #ERROR "Program requires BS2p, BS2pe or BS2px."
12 | #ENDIF
13 |
14 | Lcd PIN 0
15 |
16 | LcdCls CON $01 'clear the LCD
17 | LcdHome CON $02 'move cursor home
18 | LcdCrsrL CON $10 'move cursor left
19 | LcdCrsrR CON $14 'move cursor right
20 | LcdDispL CON $18 'shift chars left
21 | LcdDispR CON $1C 'shift chars right
22 | LcdDDRam CON $80 'Display Data RAM
23 | LcdCGRam CON $40 'Character Generator RAM
24 | LcdLine1 CON $80 'DDRAM address of line 1
25 | LcdLine2 CON $C0 'DDRAM address of line 2
26 |
27 |
28 | Init_LCD:
29 | PAUSE 1000 'allow LCD to self-initialize first
30 | LCDCMD Lcd, %00110000 'send wakeup sequence to LCD
31 | PAUSE 5 'pause required by LCD specs
32 | LCDCMD Lcd, %00110000
33 | PAUSE 0 'pause required by LCD specs
34 | LCDCMD Lcd, %00110000
35 | PAUSE 0 'pause required by LCD specs
36 | LCDCMD Lcd, %00100000 'set data bus to 4-bit mode
37 | LCDCMD Lcd, %00101000 'set to 2-line mode with 5x8 font
38 | LCDCMD Lcd, %00001100 'display on without cursor
39 | LCDCMD Lcd, %00000110 'auto-increment cursor
40 |
41 | Main:
42 | DO
43 | LCDOUT Lcd, LcdCls, ["Hello, World!"]
44 | LCDOUT Lcd, LcdLine2, ["How are you?"]
45 | PAUSE 3000
46 | LCDCMD Lcd, LcdCls
47 | PAUSE 500
48 | LOOP
--------------------------------------------------------------------------------
/examples/SERIN_SEROUT2.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: SERIN_SEROUT2
5 | 'Using two BS2-IC's, connect the circuit shown in the SERIN command
6 | 'description and run this program on the BASIC Stamp designated as the
7 | 'Receiver. This program demonstrates the use of Flow Control (FPin).
8 | 'Without flow control, the sender would transmit the whole word "Hello!"
9 | 'in about 1.5 ms. The receiver would catch the first byte at most; by the
10 | 'time it got back from the first 1-second PAUSE, the rest of the data
11 | 'would be long gone. With flow control, communication is flawless since
12 | 'the sender waits for the receiver to catch up.
13 |
14 | SI PIN 1 'serial input
15 | FC PIN 0 'flow control pin
16 |
17 | #SELECT $STAMP 'Set values according to module type
18 | #CASE BS2, BS2E, BS2PE
19 | T1200 CON 813
20 | T2400 CON 396
21 | T9600 CON 84
22 | T19K2 CON 32
23 | T38K4 CON 6
24 | #CASE BS2SX, BS2P
25 | T1200 CON 2063
26 | T2400 CON 1021
27 | T9600 CON 240
28 | T19K2 CON 110
29 | T38K4 CON 45
30 | #CASE BS2PX
31 | T1200 CON 3313
32 | T2400 CON 1646
33 | T9600 CON 396
34 | T19K2 CON 188
35 | T38K4 CON 84
36 | #ENDSELECT
37 |
38 | Inverted CON $4000
39 | Open CON $8000
40 | Baud CON T9600 + Inverted
41 |
42 | letter VAR Byte
43 |
44 | Init:
45 | PAUSE 200 'short startup-pause
46 |
47 | Main:
48 | DO
49 | SERIN SI\FC, Baud, [letter] 'receive one byte
50 | DEBUG letter 'display on screen
51 | PAUSE 1000 'wait one second
52 | LOOP 'repeat forever
--------------------------------------------------------------------------------
/examples/SELECT-CASE.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: SELECT-CASE
5 | 'This program generates a series of 16-bit random numbers and tests each
6 | 'to determine odd or even, and where it falls in the possible range:
7 | 'lower third, middle third, or upper third. The program is useful for
8 | 'testing various seed values for RANDOM.
9 |
10 | test VAR Byte 'counter for tests
11 | sample VAR Word 'random number to be tested
12 | odd VAR Byte 'odd throws
13 | even VAR Byte 'even throws
14 | isLo VAR Byte 'sample in lower third
15 | isMid VAR Byte ' in middle thrid
16 | isHi VAR Byte ' in upper third
17 |
18 | Init:
19 | PAUSE 200 'short startup-pause
20 |
21 | Main:
22 | sample = 11000 'initialize seed
23 | FOR test = 1 TO 100 '"throw" 100 times
24 | RANDOM sample 'randomize
25 |
26 | IF (sample.BIT0) THEN 'check odd/even bit
27 | odd = odd + 1 'increment odd count
28 | ELSE
29 | even = even + 1 'increment even count
30 | ENDIF
31 |
32 | SELECT sample
33 | CASE <= 21845 'test lower third
34 | isLo = isLo + 1
35 |
36 | CASE 21846 TO 43691 'test middle third
37 | isMid = isMid + 1
38 |
39 | CASE ELSE 'otherwise upper third
40 | isHi = isHi + 1
41 | ENDSELECT
42 | NEXT
43 |
44 | Show_Results:
45 | DEBUG CLS,
46 | "Odd Throws.... ", DEC odd, "%", CR,
47 | "Even Throws... ", DEC even, "%", CR,
48 | "Low........... ", DEC isLo, "%", CR,
49 | "Mid........... ", DEC isMid, "%", CR,
50 | "High.......... ", DEC isHi, "%", CR
51 | END
--------------------------------------------------------------------------------
/examples/FREQOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: FREQOUT
5 | 'This program demonstrates sound-effects generation by the BASIC Stamp.
6 | 'Conditional compilation sets timing and frequency adjustment factors so
7 | 'that the output will sound the same on any BS2 model.
8 |
9 | Spkr PIN 10 'output pin for FREQOUT
10 |
11 | #SELECT $STAMP 'Set TmAdj and FrAdj according to module type
12 | #CASE BS2, BS2E
13 | TmAdj CON $100 'x 1.0 (time adjust)
14 | FrAdj CON $100 'x 1.0 (freq adjust)
15 | #CASE BS2SX
16 | TmAdj CON $280 'x 2.5
17 | FrAdj CON $066 'x 0.4
18 | #CASE BS2P
19 | TmAdj CON $3C5 'x 3.77
20 | FrAdj CON $044 'x 0.265
21 | #CASE BS2PE
22 | TmAdj CON $100 'x 1.0
23 | FrAdj CON $0A9 'x 0.662
24 | #CASE BS2PX
25 | TmAdj CON $607 'x 6.03
26 | FrAdj CON $2A 'x 0.166
27 | #ENDSELECT
28 |
29 | Init:
30 | PAUSE 200 'short startup-pause
31 |
32 | Main:
33 | DEBUG "Let's make a call...", CR
34 | 'combine 350 Hz & 440 Hz
35 | FREQOUT Spkr, 2000 */ TmAdj, 350 */ FrAdj, 440 */ FrAdj
36 | 'dial number (digits 150 ms on, 25 ms off)
37 | DTMFOUT Spkr, 150 */ TmAdj, 25, [5, 5, 5, 1, 2, 1, 2]
38 | PAUSE 500
39 |
40 | 'bad connection (SIT sequence)
41 | FREQOUT Spkr, 375 */ TmAdj, 985 */ FrAdj
42 | FREQOUT Spkr, 375 */ TmAdj, 1371 */ FrAdj
43 | FREQOUT Spkr, 375 */ TmAdj, 1777 */ FrAdj
44 |
45 | DEBUG "Oops! -- try again...", CR
46 | PAUSE 1000
47 | DTMFOUT Spkr, 150 */ TmAdj, 25, [5, 5, 5, 2, 2, 2, 2]
48 | DEBUG "Ringing"
49 | FREQOUT Spkr, 2000 */ TmAdj, 440 */ FrAdj, 480 */ FrAdj
50 | PAUSE 4000
51 | FREQOUT Spkr, 2000 */ TmAdj, 440 */ FrAdj, 480 */ FrAdj
52 | INPUT Spkr
53 | END
54 |
--------------------------------------------------------------------------------
/examples/LCDIN.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: LCDIN
5 | 'This program demonstrates initialization, printing and reading
6 | 'from a 2 x 16 character LCD display.
7 |
8 | #IF ($STAMP < BS2P) #THEN 'Notify of module requirements
9 | #ERROR "Program requires BS2p, BS2pe or BS2px."
10 | #ENDIF
11 |
12 | Lcd PIN 0
13 |
14 | LcdCls CON $01 'clear the LCD
15 | LcdHome CON $02 'move cursor home
16 | LcdCrsrL CON $10 'move cursor left
17 | LcdCrsrR CON $14 'move cursor right
18 | LcdDispL CON $18 'shift chars left
19 | LcdDispR CON $1C 'shift chars right
20 | LcdDDRam CON $80 'Display Data RAM
21 | LcdCGRam CON $40 'Character Generator RAM
22 | LcdLine1 CON $80 'DDRAM address of line 1
23 | LcdLine2 CON $C0 'DDRAM address of line 2
24 |
25 | char VAR Byte(16)
26 |
27 | Init_LCD:
28 | PAUSE 1000 'allow LCD to self-initialize first
29 | LCDCMD Lcd, %00110000 'send wakeup sequence to LCD
30 | PAUSE 5 'pause required by LCD specs
31 | LCDCMD Lcd, %00110000
32 | PAUSE 0 'pause required by LCD specs
33 | LCDCMD Lcd, %00110000
34 | PAUSE 0 'pause required by LCD specs
35 | LCDCMD Lcd, %00100000 'set data bus to 4-bit mode
36 | LCDCMD Lcd, %00101000 'set to 2-line mode with 5x8 font
37 | LCDCMD Lcd, %00001100 'display on without cursor
38 | LCDCMD Lcd, %00000110 'auto-increment cursor
39 |
40 | Main:
41 | DO
42 | LCDOUT Lcd, LcdCls, ["Hello!"]
43 | GOSUB Read_LCD_Screen
44 | PAUSE 3000
45 | LCDOUT Lcd, LcdCls, ["I'm a 2x16 LCD!"]
46 | GOSUB Read_LCD_Screen
47 | PAUSE 3000
48 | LOOP
49 |
50 | Read_LCD_Screen:
51 | DEBUG "LCD now says: "
52 | LCDIN Lcd, LcdLine1, [STR char\16]
53 | DEBUG STR char\16, CR
54 | RETURN
--------------------------------------------------------------------------------
/examples/LCDOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: LCDOUT
5 | 'This program demonstrates initialization and printing on a 2x16
6 | 'character LCD display.
7 |
8 | #IF ($STAMP < BS2P) #THEN 'Notify of module requirements
9 | #ERROR "Program requires BS2p, BS2pe or BS2px."
10 | #ENDIF
11 |
12 | Lcd PIN 0
13 |
14 | LcdCls CON $01 'clear the LCD
15 | LcdHome CON $02 'move cursor home
16 | LcdCrsrL CON $10 'move cursor left
17 | LcdCrsrR CON $14 'move cursor right
18 | LcdDispL CON $18 'shift chars left
19 | LcdDispR CON $1C 'shift chars right
20 | LcdDDRam CON $80 'Display Data RAM
21 | LcdCGRam CON $40 'Character Generator RAM
22 | LcdLine1 CON $80 'DDRAM address of line 1
23 | LcdLine2 CON $C0 'DDRAM address of line 2
24 |
25 |
26 | Init_LCD:
27 | PAUSE 1000 'allow LCD to self-initialize first
28 | LCDCMD Lcd, %00110000 'send wakeup sequence to LCD
29 | PAUSE 5 'pause required by LCD specs
30 | LCDCMD Lcd, %00110000
31 | PAUSE 0 'pause required by LCD specs
32 | LCDCMD Lcd, %00110000
33 | PAUSE 0 'pause required by LCD specs
34 | LCDCMD Lcd, %00100000 'set data bus to 4-bit mode
35 | LCDCMD Lcd, %00101000 'set to 2-line mode with 5x8 font
36 | LCDCMD Lcd, %00001100 'display on without cursor
37 | LCDCMD Lcd, %00000110 'auto-increment cursor
38 |
39 | LCDOUT Lcd, LcdCGRam, 'load custom character map
40 | [$00, $0A, $0A, $00, $11, $0E, $06, $00]
41 |
42 | Main:
43 | DO
44 | LCDOUT Lcd, LcdCls, ["Hello my friend."]
45 | PAUSE 750
46 | LCDOUT Lcd, LcdLine2, ["How are you?"]
47 | PAUSE 1500
48 | LCDCMD Lcd, LcdCls
49 | LCDOUT Lcd, LcdLine1 + 1, ["I'm doing just"]
50 | LCDOUT Lcd, LcdLine2 + 4, ["fine! ", 0]
51 | PAUSE 2000
52 | LOOP
--------------------------------------------------------------------------------
/examples/GOSUB.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: GOSUB
5 | 'This program is a guessing game that generates a random number in a
6 | 'subroutine called Pick_A_Number. It is written to stop after three
7 | 'guesses. To see a common bug associated with GOSUB, delete or comment
8 | 'out the line beginning with END after the FOR-NEXT loop. This means
9 | 'that after the loop is finished, the program will wander into the
10 | 'Pick_A_Number subroutine. When the RETURN at the source's end executes,
11 | 'the program will go back to the beginning. This will cause the program
12 | 'to execute endlessly. Make sure that your programs can't accidentally
13 | 'execute subroutines!
14 |
15 | rounds VAR Byte 'number of reps
16 | numGen VAR Word 'random number holder
17 | myNum VAR Byte 'random number, 1-10
18 |
19 | Setup:
20 | PAUSE 200 'short startup-pause
21 | numGen = 11500 'initialize random "seed"
22 |
23 | Main:
24 | FOR rounds = 1 TO 3
25 | DEBUG CLS, "Think of a number from 1 to 10", CR
26 | GOSUB Pick_A_Number
27 | PAUSE 2000 'dramatic pause
28 | DEBUG "My number was: ", DEC myNum 'show the number
29 | PAUSE 1000 'another pause.
30 | NEXT
31 | DEBUG CLS, "Done"
32 | END 'end program
33 |
34 | 'Random-number subroutine. A subroutine is just a piece of code with
35 | 'the RETURN instruction at the end. Always make sure your program enters
36 | 'subroutines with a GOSUB. If you don't, the RETURN won't have the
37 | 'correct address, and your program will have a bug!
38 |
39 | Pick_A_Number:
40 | RANDOM numGen 'stir up the bits of NumGen.
41 | DEBUG " (random value = ", DEC numGen, ")", CR, CR
42 | myNum = numGen / 6550 MIN 1 'scale to fit 1-10 range.
43 | RETURN 'go back to instruction after
44 | 'the GOSUB that got us here
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Parallax IDE
6 |
7 |
8 |
9 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/examples/I2C.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: I2C
5 | 'This program demonstrates writing and reading every location in a 24LC16B
6 | 'EEPROM using the BS2p/BS2pe's I2C commands. Connect the BS2p, BS2pe, or
7 | 'BS2px to the 24LC16B DIP EEPROM as shown in the diagram in the I2CIN OR
8 | 'I2COUT command description.
9 |
10 | #IF ($STAMP < BS2P) #THEN 'Notify of module requirements
11 | #ERROR "Program requires BS2p, BS2pe, or BS2px."
12 | #ENDIF
13 |
14 | SDA PIN 0 'I2C SDA pin
15 | SCL PIN SDA + 1
16 |
17 | addr VAR Word 'internal address
18 | block VAR Nib 'block address in 24LC16
19 | value VAR Byte 'value to write
20 | check VAR Nib 'for checking retuned values
21 | result VAR Byte(16) 'array for returned value
22 |
23 | Init:
24 | PAUSE 200 'short startup-pause
25 |
26 | Write_To_EEPROM:
27 | DEBUG "Writing...", CR
28 | PAUSE 2000
29 | FOR addr = 0 TO 2047 STEP 16 'loop through all addresses
30 | block = addr.NIB2 << 1 'calculate block address
31 | value = addr >> 4 'create value from upper 8 bits
32 | 'write 16 bytes
33 | I2COUT SDA, $A0 | block, addr, [REP value\16]
34 | PAUSE 5
35 | DEBUG "Addr: ", DEC4 addr, "-", DEC4 addr + 15, " ",
36 | "Value: ", DEC3 value, CR
37 | NEXT
38 | PAUSE 2000
39 |
40 | Read_From_EEPROM:
41 | DEBUG CR, "Reading...", CR
42 | PAUSE 2000
43 | FOR addr = 0 TO 2047 STEP 16
44 | block = addr.NIB2 << 1
45 | value = addr >> 4
46 | I2CIN SDA, $A1 | block, addr, [STR result\16]
47 | FOR check = 0 TO 15
48 | IF (result(check) <> value) THEN Error
49 | NEXT
50 | DEBUG "Addr: ", DEC4 addr, "-", DEC4 addr + 15, " ",
51 | "Value: ", DEC3 result, CR
52 | NEXT
53 | PAUSE 100
54 | DEBUG CR, "All locations passed"
55 | END
56 |
57 | Error:
58 | DEBUG "Error at location: ", DEC4 addr + check, CR,
59 | "Found: ", DEC3 result(check), ", Expected: ", DEC3 value
--------------------------------------------------------------------------------
/examples/XOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: XOUT
5 | 'This program--really two program fragments--demonstrates the syntax and
6 | 'use of the XOUT command. XOUT works like pressing the buttons on an X-10
7 | 'control box; first you press one of 16 keys to identify the unit you want
8 | 'to control, then you press the key for the action you want that unit to
9 | 'take (turn ON, OFF, Bright, or Dim). There are also two group-action keys,
10 | 'Lights ON and All OFF. Lights ON turns all lamp modules on without
11 | 'affecting appliance modules. All OFF turns off all modules, both lamp and
12 | 'appliance types. Connect the BASIC Stamp to a power-line interface as
13 | 'shown in the XOUT command description in the manual.
14 |
15 | Mpin PIN 1 'modulation pin
16 | Zpin PIN 0 'zero-cross input
17 |
18 | HouseA CON 0 'House code A = 0
19 | Unit1 CON 0 'Unit code 1 = 0
20 | Unit2 CON 1 'Unit code 2 = 1
21 |
22 | 'This first example turns a standard (appliance or non-dimmer lamp) module
23 | 'ON, then OFF. Note that once the Unit code is sent, it need not be repeated
24 | '--subsequent instructions are understood to be addressed to that unit.
25 |
26 | Main:
27 | XOUT Mpin, Zpin, [HouseA\Unit1\2] 'select Unit1 (appliance module)
28 | XOUT Mpin, Zpin, [HouseA\UNITON] 'turn it on
29 |
30 | PAUSE 1000 'wait one second
31 |
32 | XOUT Mpin, Zpin, [HouseA\UNITOFF] 'then turn it off
33 |
34 | 'The next example talks to a lamp module using the dimmer feature. Dimmers
35 | 'go from full ON to dimmed OFF in 19 steps. Because dimming is relative to
36 | 'the current state of the lamp, the only guaranteed way to set a predefined
37 | 'brightness level is to turn the dimmer fully OFF, then ON, then dim to the
38 | 'desired level.
39 |
40 | XOUT Mpin, Zpin, [HouseA\Unit2\2] 'select Unit2 (lamp module)
41 |
42 | 'This example shows the use of the optional Cycles argument. Here we DIM
43 | 'for 10 cycles.
44 |
45 | XOUT Mpin, Zpin, [HouseA\UNITOFF\2, HouseA\DIM\10]
46 | STOP
--------------------------------------------------------------------------------
/src/views/terminal.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { createContainer } = require('sovereign');
5 |
6 | const Scroller = require('../lib/scroller');
7 |
8 | const TransmitPane = require('../components/transmit-pane');
9 |
10 | const styles = {
11 | outputConsole: {
12 | height: '200px',
13 | boxShadow: 'inset 0 5px 10px -5px rgba(0, 0, 0, 0.26)',
14 | backgroundColor: 'white',
15 | padding: '10px',
16 | margin: '0',
17 | overflow: 'auto',
18 | whiteSpace: 'pre'
19 | }
20 | };
21 |
22 | class TermnialView extends React.Component {
23 |
24 | componentWillReceiveProps(nextProps){
25 | const { output, offset } = nextProps;
26 | this.scroller.setLines(output, offset);
27 | this.scroller.requestRefresh();
28 | }
29 |
30 | componentDidMount() {
31 | const outputElement = React.findDOMNode(this.outputConsole);
32 | this.scroller = new Scroller(outputElement);
33 | outputElement.addEventListener('scroll', this.scroller.scroll, false);
34 | }
35 |
36 | componentWillUnmount() {
37 | const outputElement = React.findDOMNode(this.outputConsole);
38 | outputElement.removeEventListener('scroll', this.scroller.scroll, false);
39 | }
40 |
41 | shouldComponentUpdate(nextProps){
42 | const { connected, input } = this.props;
43 | return (connected !== nextProps.connected || input !== nextProps.input);
44 | }
45 |
46 | render(){
47 | const {
48 | handlers,
49 | connected,
50 | input
51 | } = this.props;
52 |
53 | const {
54 | transmitInput
55 | } = handlers;
56 |
57 | return (
58 |
59 |
60 |
this.outputConsole = ref} style={styles.outputConsole} />
61 |
62 | );
63 | }
64 | }
65 |
66 | module.exports = createContainer(TermnialView, {
67 | getStores({ store }){
68 | return {
69 | store
70 | };
71 | },
72 |
73 | getPropsFromStores({ store }){
74 | const { transmission, device } = store.getState();
75 | const { input, output, offset } = transmission;
76 | const { connected } = device;
77 |
78 | return {
79 | connected,
80 | input,
81 | output,
82 | offset
83 | };
84 | }
85 | });
86 |
--------------------------------------------------------------------------------
/examples/DTMFOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: DTMFOUT
5 | 'This demo program is a rudimentary memory dialer. Since DTMF digits fit
6 | 'within a nibble (four bits), the program below packs two DTMF digits into
7 | 'each byte of three EEPROM data tables. The end of phone number is marked
8 | 'by the nibble $F, since this is not a valid phone-dialing digit.
9 | 'Conditional compilation sets the timing adjustment factor so that the
10 | 'output will sound the same on any BS2 model.
11 |
12 | Spkr PIN 10 'DTMF output on pin 10
13 |
14 | #SELECT $STAMP 'Set TmAdj according to module type
15 | #CASE BS2, BS2E, BS2PE
16 | TmAdj CON $100 'x 1.0 (time adjust)
17 | #CASE BS2SX
18 | TmAdj CON $280 'x 2.5
19 | #CASE BS2P
20 | TmAdj CON $3C5 'x 3.77
21 | #CASE BS2PX
22 | TmAdj CON $607 'x 6.03
23 | #ENDSELECT
24 |
25 | eeLoc VAR Byte 'EEPROM address of stored number
26 | eeByte VAR Byte 'Byte containing two DTMF digits
27 | dtDig VAR eeByte.NIB1 'Digit to dial
28 | phone VAR Nib 'Pick a phone #
29 | hiLo VAR Bit 'Bit to select upper and lower nib
30 |
31 | Parallax DATA $19,$16,$62,$48,$33,$3F 'Phone: 1-916-624-8333
32 | ParallaxFax DATA $19,$16,$62,$48,$00,$3F 'Phone: 1-916-624-8003
33 | Information DATA $15,$20,$55,$51,$21,$2F 'Phone: 1-520-555-1212
34 |
35 | Main:
36 | FOR phone = 0 TO 2
37 | 'retrieve address
38 | LOOKUP phone, [Parallax, ParallaxFax, Information], eeLoc
39 | GOSUB Dial_Number
40 | PAUSE 2000
41 | NEXT
42 | END
43 |
44 | Dial_Number:
45 | DO
46 | READ eeLoc, eeByte 'Retrieve byte from EEPROM
47 | eeLoc = eeLoc + 1 'point to next pair of digits
48 | FOR hiLo = 0 TO 1 'Dial upper and lower digits
49 | IF (dtDig = $F) THEN EXIT 'Hex $F is end-of-number flag
50 | DTMFOUT Spkr, 'dial digit
51 | 150 */ TmAdj, 25, [dtDig] '150 ms on, 25 ms off
52 | eeByte = eeByte << 4 'Shift in next digit
53 | NEXT
54 | LOOP UNTIL (dtDig = $F)
55 | RETURN
56 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "parallax-ide",
3 | "version": "0.14.4",
4 | "description": "Write, compile, and download code to your Parallax Boe-Bot Robot or custom BASIC Stamp microcontroller-based electronic creations.",
5 | "main": "index.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "dependencies": {
10 | "@phated/redux-create-store": "^0.3.0",
11 | "acorn": "^6.4.2",
12 | "bs2-serial": "^0.15.0",
13 | "codemirror": "^4.13.0",
14 | "express": "^3.21.2",
15 | "frylord": "^0.7.4",
16 | "history": "^1.12.5",
17 | "iggins": "^0.4.0",
18 | "invariant": "^2.1.1",
19 | "irken": "^0.9.0",
20 | "lodash": "^4.17.19",
21 | "raw-loader": "^0.5.1",
22 | "react": "^0.13.1",
23 | "react-loader": "^1.2.0",
24 | "react-material": "git://github.com/PropGit/react-material#0.14",
25 | "react-mfb-iceddev": "^0.1.0",
26 | "react-router": "^1.0.0-rc1",
27 | "react-style": "^0.4.0",
28 | "skrim": "0.0.3",
29 | "snacks": "^0.3.1",
30 | "sovereign": "^0.3.0",
31 | "when": "^3.7.2"
32 | },
33 | "devDependencies": {
34 | "@phated/eslint-config-iceddev": "^0.2.1",
35 | "babel-core": "^4.5.1",
36 | "babel-loader": "^4.0.0",
37 | "babel-runtime": "^4.7.16",
38 | "chalk": "^1.0.0",
39 | "css-loader": "^0.9.1",
40 | "del": "^1.1.1",
41 | "electron-prebuilt": "^0.30.2",
42 | "eslint": "^1.2.1",
43 | "eslint-plugin-mocha": "^0.5.1",
44 | "eslint-plugin-react": "^3.2.3",
45 | "expect": "^1.8.0",
46 | "gulp": "^4.0.1",
47 | "gulp-util": "^3.0.4",
48 | "gulp-zip": "^2.0.3",
49 | "html-loader": "^0.2.3",
50 | "json-loader": "^0.5.1",
51 | "level-js": "^2.1.6",
52 | "style-loader": "^0.8.3",
53 | "webpack": "^1.7.2",
54 | "webpack-dev-server": "^1.7.0",
55 | "zuul": "^3.2.0",
56 | "zuul-builder-webpack": "^1.1.0"
57 | },
58 | "scripts": {
59 | "test": "zuul test/*.js --local --open",
60 | "ci": "zuul test/*.js --electron",
61 | "build": "gulp",
62 | "version": "gulp version && git add manifest.json",
63 | "release": "gulp gh-release",
64 | "postinstall": "gulp postinstall",
65 | "serve": "webpack-dev-server"
66 | },
67 | "repository": {
68 | "type": "git",
69 | "url": "https://github.com/parallaxinc/Parallax-IDE"
70 | },
71 | "license": "MIT",
72 | "bugs": {
73 | "url": "https://github.com/parallaxinc/Parallax-IDE/issues"
74 | },
75 | "homepage": "https://github.com/parallaxinc/Parallax-IDE"
76 | }
77 |
--------------------------------------------------------------------------------
/examples/OWIN_OWOUT.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: OWIN_OWOUT
5 | 'This program demonstrates interfacing to a Dallas Semiconductor DS1822
6 | '1-Wire Digital Thermometer chip using the BS2p's 1-Wire commands. Connect
7 | 'the BS2p, BS2pe, or BS2px to the DS1822 as shown in the diagram in the
8 | 'OWIN or OWOUT command description. This program uses a simplified
9 | 'approach that ignores the fractional portion of the temperature.
10 |
11 | #IF ($STAMP < BS2P) #THEN 'Notify of module requirements
12 | #ERROR "Program requires BS2p, BS2pe or BS2px."
13 | #ENDIF
14 |
15 | DQ PIN 0 '1-Wire buss pin
16 |
17 | RdROM CON $33 'read serial number
18 | MatchROM CON $55 'match SN -- for multiple devices
19 | SkipROM CON $CC 'ignore SN -- use for one device
20 | CvrtTmp CON $44 'start temperature conversion
21 | RdSP CON $BE 'read DS1822 scratch pad
22 |
23 | tempIn VAR Word 'raw temperature
24 | sign VAR tempIn.BIT11 '1 = negative temperature
25 | tLo VAR tempIn.BYTE0
26 | tHi VAR tempIn.BYTE1
27 | tSign VAR Bit 'saved sign bit
28 | tempC VAR Word 'final Celsius temp
29 | tempF VAR Word 'final Fahrenheit temp
30 |
31 | Init:
32 | PAUSE 200 'short startup-pause
33 |
34 | Main:
35 | DO
36 | GOSUB Get_Temperature 'read temperature from DS1822
37 | DEBUG HOME, 'display
38 | "DS1822", CR,
39 | "------", CR,
40 | SDEC tempC, " C ", CR,
41 | SDEC tempF, " F "
42 | PAUSE 1000
43 | LOOP
44 | END
45 |
46 | Get_Temperature:
47 | OWOUT DQ, 1, [SkipROM, CvrtTmp] 'send convert temperature command
48 | DO 'wait on conversion
49 | PAUSE 25 'small loop pad
50 | OWIN DQ, 4, [tempIn] 'check status (bit transfer)
51 | LOOP UNTIL (tempIn) '1 when complete
52 | OWOUT DQ, 1, [SkipROM, RdSP] 'read DS1822 scratch pad
53 | OWIN DQ, 2, [tLo, tHi] 'get raw temp data
54 | tSign = sign 'save sign bit
55 | tempC = tempIn >> 4 'round to whole degrees
56 | tempC.BYTE1 = $FF * tSign 'correct twos complement bits
57 | tempF = (ABS tempC) * 9 / 5 'start F conversion
58 | IF (tSign) THEN 'finish F conversion
59 | tempF = 32 - tempF 'C was negative
60 | ELSE
61 | tempF = tempF + 32 'C was positive
62 | ENDIF
63 | RETURN
--------------------------------------------------------------------------------
/src/components/transmit-pane.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 |
5 | const styles = {
6 | transmit: {
7 | margin: 0,
8 | height: '32px',
9 | backgroundColor: 'white',
10 | boxShadow: 'inset 0px 5px 10px -5px rgba(0, 0, 0, 0.26)'
11 | },
12 | transmitInput: {
13 | border: '0px',
14 | backgroundColor: 'transparent',
15 | outline: 'none',
16 | resize: 'none',
17 | width: '100%',
18 | padding: '5px 10px',
19 | fontSize: 'inherit',
20 | fontFamily: 'inherit',
21 | boxSizing: 'border-box'
22 | }
23 | };
24 |
25 | const ignore = [16, 17, 18, 20];
26 |
27 | class TransmitPane extends React.Component {
28 |
29 | constructor(...args){
30 | super(...args);
31 |
32 | this.handleKeyDown = this.handleKeyDown.bind(this);
33 | this.handleKeyPress = this.handleKeyPress.bind(this);
34 | this.handlePaste = this.handlePaste.bind(this);
35 | }
36 |
37 | handleKeyDown(event) {
38 | const { onChange } = this.props;
39 |
40 | const { keyCode } = event.nativeEvent;
41 |
42 | if (ignore.indexOf(keyCode) > -1) {
43 | return;
44 | }
45 |
46 | if (keyCode < 32 || (keyCode > 127 && keyCode < 160)) {
47 | // TODO: pass the whole event?
48 | onChange(keyCode);
49 | }
50 | }
51 |
52 | handleKeyPress(event) {
53 | const { onChange } = this.props;
54 |
55 | const { keyCode } = event.nativeEvent;
56 |
57 | if ((keyCode >= 32 && keyCode <= 127) ||
58 | (keyCode >= 160 && keyCode <= 255)) {
59 | // TODO: pass the whole event?
60 | onChange(keyCode);
61 | }
62 | }
63 |
64 | handlePaste(event) {
65 | const { onChange } = this.props;
66 |
67 | const { clipboardData } = event;
68 | const data = clipboardData.getData('text/plain');
69 |
70 | onChange(data);
71 | }
72 |
73 | shouldComponentUpdate(nextProps){
74 | const { connected, text } = this.props;
75 | return (connected !== nextProps.connected || text !== nextProps.text);
76 | }
77 |
78 | render() {
79 | const { connected, text } = this.props;
80 | return (
81 |
82 |
91 |
92 |
93 | );
94 | }
95 | }
96 |
97 | TransmitPane.propTypes = {
98 | connected: React.PropTypes.bool.isRequired,
99 | text: React.PropTypes.string.isRequired
100 | };
101 |
102 | module.exports = TransmitPane;
103 |
--------------------------------------------------------------------------------
/src/views/layout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const invariant = require('invariant');
5 |
6 | const store = require('../store');
7 |
8 | const AppBar = require('./appbar');
9 | const SideBar = require('./sidebar');
10 | const Editor = require('./editor');
11 | const Terminal = require('./terminal');
12 | const RxTx = require('./rxtx');
13 |
14 | const styles = {
15 | container: {
16 | display: 'flex',
17 | flexDirection: 'column',
18 | height: '100vh'
19 | },
20 | appbar: {
21 | flex: '0 0 56px'
22 | },
23 | view: {
24 | display: 'flex',
25 | flexDirection: 'row',
26 | height: '100%'
27 | },
28 | sidebar: {
29 | display: 'flex',
30 | flex: '0 0 content'
31 | },
32 | main: {
33 | display: 'flex',
34 | flexDirection: 'column',
35 | width: '100%',
36 | justifyContent: 'flex-end'
37 | },
38 | editor: {
39 | flexGrow: 1,
40 | overflow: 'auto'
41 | },
42 | debug: {
43 | flexBasis: '16em'
44 | },
45 | debugstate: {
46 | flexBasis: '2em'
47 | },
48 | overlay: {
49 | position: 'fixed',
50 | width: 0,
51 | zIndex: 9999
52 | }
53 | };
54 |
55 | class Layout extends React.Component {
56 | componentDidMount(){
57 | const add = this.props.addMountpoint;
58 | invariant(add, 'Layout requires addMountpoint during componentDidMount.');
59 | add('overlay', React.findDOMNode(this._overlay));
60 | }
61 |
62 | componentWillUnmount(){
63 | const remove = this.props.removeMountpoint;
64 | invariant(remove, 'Layout requires removeMountpoint during componentWillUnmount.');
65 | remove('overlay');
66 | }
67 |
68 | render(){
69 | const { workspace, handlers } = this.props.app;
70 | return (
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
this._overlay = ref} style={styles.overlay}>
88 |
{this.props.children}
89 |
90 | );
91 | }
92 | }
93 |
94 | Layout.propTypes = {
95 | addMountpoint: React.PropTypes.func.isRequired,
96 | removeMountpoint: React.PropTypes.func.isRequired
97 | };
98 |
99 | module.exports = Layout;
100 |
--------------------------------------------------------------------------------
/examples/STOREALL.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2p}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: STOREALL
5 | 'This program demonstrates the STORE command and how it can be used to
6 | '"flatten" the EEPROM space for applications requiring a lot of storage.
7 | 'This program writes to EEPROM locations within program slots 1 though 7
8 | 'on the BS2p and BS2px, and 1 through 15 on the BS2pe, thus, has access to
9 | '14 or 30 kBytes of space.
10 |
11 | #SELECT $STAMP 'Notify of module requirements
12 | #CASE BS2, BS2E, BS2SX
13 | #ERROR "Program requires BS2p, BS2pe or BS2px."
14 | #CASE BS2P, BS2PX
15 | HiSlot CON 7
16 | #CASE BS2PE
17 | HiSlot CON 15
18 | #ENDSELECT
19 |
20 | LoSlot CON 1 'first slot for "flat" EE
21 | MemSize CON HiSlot - LoSlot + 1 * 2048
22 |
23 | eeAddr VAR Word 'address pointer
24 | value VAR Word 'cell value
25 | slot VAR Byte 'current R/W slot
26 |
27 | Init:
28 | PAUSE 200 'short startup-pause
29 |
30 | Main:
31 | DEBUG "Flat Memory", CR,
32 | "---------------------", CR,
33 | "First Slot..... ", DEC LoSlot, CR,
34 | "Last Slot...... ", DEC HiSlot, CR,
35 | "Flat EE Size... ", DEC MemSize, CR, CR
36 |
37 | PAUSE 2000
38 | DEBUG "Writing to flat Memory...", CR
39 | PAUSE 1000
40 | FOR eeAddr = 0 TO (MemSize - 1) STEP 128 'step through "flat" EE
41 | value = eeAddr * 2 'generate value
42 | GOSUB Write_Word 'write it
43 | GET 127, slot 'get R/W slot
44 | DEBUG "--> Location: ", DEC5 eeAddr, " ", 'show "flat" address
45 | "Value: ", DEC5 value, " ", 'show value
46 | "(", DEC slot.NIB1, ")", CR 'show slot
47 | NEXT
48 | DEBUG CR
49 |
50 | DEBUG "Reading from flat Memory...", CR
51 | PAUSE 1000
52 | FOR eeAddr = 0 TO (MemSize - 1) STEP 128
53 | GOSUB Read_Word 'read value from EE
54 | GET 127, slot 'get W/R slot
55 | DEBUG "<-- Location: ", DEC5 eeAddr, " ",
56 | "Value: ", DEC5 value, " ",
57 | "(", DEC slot.NIB1, ") "
58 | IF (value <> (2 * eeAddr)) THEN 'verify location
59 | DEBUG "- Error"
60 | ENDIF
61 | DEBUG CR
62 | NEXT
63 | END
64 |
65 | Write_Word:
66 | 'NOTE: only use even-byte eeAddr with this routine
67 | STORE (eeAddr >> 11) + LoSlot 'set slot
68 | WRITE eeAddr, Word value 'write value
69 | RETURN
70 |
71 | Read_Word:
72 | 'NOTE: only use even-byte eeAddr with this routine
73 | STORE (eeAddr >> 11) + LoSlot 'set slot
74 | READ eeAddr, Word value 'read value
75 | RETURN
--------------------------------------------------------------------------------
/assets/theme/parallax.css:
--------------------------------------------------------------------------------
1 | /* PBASIC Full Syntax theme for codemirror */
2 |
3 | /* Color scheme */
4 |
5 | .cm-s-parallax.CodeMirror {
6 | background-color:#ffffff;
7 | color:#000000;
8 | line-height:1.4375;
9 | }
10 | .cm-s-parallax .cm-comment {color:#008000}
11 | .cm-s-parallax .cm-keyword, .cm-s-parallax .cm-property {color:#000000}
12 | .cm-s-parallax .cm-atom,.cm-s-parallax .cm-number {color:#000000}
13 | .cm-s-parallax .cm-node,.cm-s-parallax .cm-tag {color:#000000}
14 | .cm-s-parallax .cm-string {color:#ff0000}
15 | .cm-s-parallax .cm-variable,.cm-s-parallax .cm-qualifier {color:#000000}
16 |
17 | .cm-etDirective {color: #008080}
18 | .cm-etTargetModule {color: #008080}
19 | .cm-etIOFormatter {color: #000080}
20 | .cm-etVariable {color: #800080}
21 | .cm-etConstant {color: #800080}
22 | .cm-etCCDirective {color: #808080}
23 | .cm-etInstruction {color: #0000ff}
24 |
25 | .CodeMirror-selectedtext {color: #ffffff !important;}
26 | .CodeMirror-selected {background: #000080 !important;}
27 | .cm-searching {
28 | color: #ffff00 !important;
29 | background-color: #000000 !important;
30 | }
31 |
32 | @keyframes searching {
33 | from { padding: 5px 0px; }
34 | to { padding: 3px 0px; }
35 | }
36 | .cm-searching.CodeMirror-selectedtext {
37 | animation-name: searching;
38 | animation-duration: 0.2s;
39 | animation-timing-function: ease;
40 | padding: 3px 0px
41 | }
42 |
43 | /* Editor styling */
44 |
45 | .cm-s-parallax pre {
46 | padding: 0px 8px 0px 0px;
47 | }
48 |
49 | .cm-s-parallax .CodeMirror-gutter-wrapper {
50 | margin-left: 4px;
51 | }
52 |
53 | .cm-s-parallax .CodeMirror-gutters {
54 | border:none;
55 | border-right:10px solid transparent;
56 | background-color:transparent;
57 | }
58 |
59 | .cm-s-parallax .CodeMirror-linenumber {
60 | padding:0;
61 | color:#e0e2e5;
62 | }
63 |
64 | .cm-s-parallax .CodeMirror-guttermarker { color: #1d75b3; }
65 | .cm-s-parallax .CodeMirror-guttermarker-subtle { color: #e0e2e5; }
66 |
67 | .cm-s-parallax div.CodeMirror-cursor {
68 | width: auto;
69 | border: 0;
70 | background: rgba(155,157,162,0.37);
71 | z-index: 1;
72 | }
73 |
74 | .parallax-button{
75 | background: white;
76 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);
77 | border: none;
78 | border-radius: 2px;
79 | color: #000;
80 | position: relative;
81 | height: 36px;
82 | margin: 0 5px 0;
83 | min-width: 80px;
84 | padding: 0 16px;
85 | display: inline-block;
86 | font-family: "Roboto","Helvetica","Arial",sans-serif;
87 | font-size: 14px;
88 | font-weight: 500;
89 | text-transform: uppercase;
90 | letter-spacing: 0;
91 | overflow: hidden;
92 | will-change: box-shadow;
93 | transition: box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1);
94 | outline: none;
95 | cursor: pointer;
96 | text-decoration: none;
97 | text-align: center;
98 | line-height: 36px;
99 | vertical-align: middle;
100 | }
101 |
--------------------------------------------------------------------------------
/src/views/sidebar.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('react-mfb-iceddev/mfb.css');
4 |
5 | const _ = require('lodash');
6 | const React = require('react');
7 | const { createContainer } = require('sovereign');
8 | const ListItem = require('react-material/components/ListItem');
9 |
10 | const Sidebar = require('../components/sidebar');
11 | const FileList = require('../components/file-list');
12 | const FileListItem = require('../components/file-list-item');
13 | const ProjectsButton = require('../components/projects-button');
14 | const FileOperationList = require('../components/file-operation-list');
15 | const FileOperationListItem = require('../components/file-operation-list-item');
16 |
17 | class SidebarView extends React.Component {
18 |
19 | constructor(...args){
20 | super(...args);
21 |
22 | this.download = this.download.bind(this);
23 | this.componentizeFile = this.componentizeFile.bind(this);
24 | }
25 |
26 | componentDidMount(){
27 | const { workspace } = this.props;
28 | // TODO: move into frylord?
29 | if(typeof chrome !== 'undefined' && typeof chrome.syncFileSystem !== 'undefined'){
30 | chrome.syncFileSystem.onFileStatusChanged.addListener(function(detail){
31 | if(detail.direction === 'remote_to_local'){
32 | workspace.refreshDirectory();
33 | }
34 | });
35 | chrome.syncFileSystem.onServiceStatusChanged.addListener(function(){
36 | workspace.refreshDirectory();
37 | });
38 | }
39 | }
40 |
41 | download(){
42 | const {
43 | enableAutoDownload,
44 | showDownloadOverlay
45 | } = this.props.handlers;
46 |
47 | enableAutoDownload();
48 | showDownloadOverlay();
49 | }
50 |
51 | componentizeFile({ name, temp }){
52 | const { changeFile } = this.props.handlers;
53 |
54 | return (
55 | changeFile(name)} />
56 | );
57 | }
58 |
59 | render(){
60 | const {
61 | cwd,
62 | directory,
63 | handlers
64 | } = this.props;
65 |
66 | const {
67 | newFile,
68 | saveFile,
69 | showProjectsOverlay,
70 | showDeleteFileOverlay
71 | } = handlers;
72 |
73 | return (
74 |
75 |
76 |
77 | {cwd}
78 | {_.map(directory, this.componentizeFile)}
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | );
88 | }
89 | }
90 |
91 | module.exports = createContainer(SidebarView, {
92 | getStores({ workspace }){
93 | return {
94 | workspace
95 | };
96 | },
97 |
98 | getPropsFromStores({ workspace }){
99 | const { cwd, directory } = workspace.getState();
100 |
101 | return {
102 | cwd,
103 | directory
104 | };
105 | }
106 | });
107 |
--------------------------------------------------------------------------------
/examples/DATA.bs2:
--------------------------------------------------------------------------------
1 | '{$STAMP BS2}
2 | '{$PBASIC 2.5}
3 |
4 | 'SOURCE: DATA
5 | 'This program stores a number of large text strings into EEPROM with the DATA
6 | 'directive and then sends them, one character at a time via the DEBUG command.
7 | 'This is a good demonstration of how to save program space by storing large
8 | 'amounts of data in EEPROM directly, rather than embedding the data into separate
9 | 'DEBUG commands.
10 |
11 | idx VAR Word 'current location number
12 | phrase VAR Nib 'current phrase number
13 | char VAR Byte 'character to print
14 |
15 | ' ----- Define all text phrases (out of order, just for fun!) -----
16 | '
17 | Text1 DATA "Here is the first part of a large chunk of text "
18 | DATA "data ", CR, "that needs to be transmitted. There's "
19 | DATA "a 5 second delay", CR, "between text paragraphs. ", CR
20 | DATA CR, 0
21 |
22 | Text3 DATA "The alternative (having multiple DEBUGs or SEROUTs, "
23 | DATA "each ", CR, "with their own line of text) consumes "
24 | DATA "MUCH more EEPROM ", CR, "(program/data) space. ", CR
25 | DATA CR, 0
26 |
27 | Text6 DATA "The 0 at the end of data blocks is used by this program "
28 | DATA "to indicate", CR, "we've reached the End of Text. The Main "
29 | DATA "routine pauses in-between each", CR, "block of text, "
30 | DATA "and then uses a LOOKUP command to retrieve the location", CR
31 | DATA "of the next desired block of text to print. ", 0
32 |
33 | Text4 DATA CLS, "This program also demonstrates retrieving data "
34 | DATA "out of order ", CR, "in relation to the way it is "
35 | DATA "stored in EEPROM. Additionally, ", CR, "control codes "
36 | DATA "(like carriage-returns, clear-screens, etc) can ", CR
37 | DATA "be embedded right in the data, as it is here. ", CR
38 | DATA CR, 0
39 |
40 | Text2 DATA "This is an example of a good way to save space in "
41 | DATA "your ", CR, "BASIC Stamp's program by storing data "
42 | DATA "into EEPROM and ", CR, "retrieving it, one byte at a "
43 | DATA "time, and transmitting it ", CR, "with just a single "
44 | DATA "DEBUG (or SEROUT) command.", CR, CR, 0
45 |
46 | Text5 DATA "The Print_It routine simply takes the idx variable, "
47 | DATA "retrieves ", CR, "the character at the EEPROM location "
48 | DATA "pointed to by it, and ", CR, "prints it to the screen "
49 | DATA "until it finds a byte with a value of 0.", CR, CR, 0
50 |
51 | Init:
52 | PAUSE 200 'short startup-pause
53 |
54 | Main:
55 | DEBUG CLS 'Clear DEBUG window
56 | FOR phrase = 1 TO 6 'Print blocks one by one
57 | LOOKUP (phrase - 1), [Text1, Text2, Text3, Text4, Text5, Text6], idx
58 | GOSUB Print_It
59 | PAUSE 5000 'Pause for 5 seconds
60 | NEXT
61 | END
62 |
63 | Print_It:
64 | DO
65 | READ idx, char 'Get next character
66 | idx = idx + 1 'Point to next location
67 | IF (char = 0) THEN EXIT 'If 0, we're done with block
68 | DEBUG char 'Otherwise, transmit it
69 | LOOP
70 | RETURN 'Return to the main routine
--------------------------------------------------------------------------------
/src/views/save-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const React = require('react');
4 | const { createContainer } = require('sovereign');
5 | const Button = require('../components/button');
6 | const TextField = require('react-material/components/TextField');
7 |
8 | const Overlay = require('../components/overlay');
9 | const OverlayTitle = require('../components/overlay-title');
10 | const OverlayFooter = require('../components/overlay-footer');
11 |
12 | const styles = {
13 | textField: {
14 | containerStyling: {
15 | width: '100%'
16 | }
17 | }
18 | };
19 |
20 | class SaveOverlay extends React.Component {
21 |
22 | constructor(...args){
23 | super(...args);
24 |
25 | const { defaultFilename } = this.props;
26 |
27 | this.state = {
28 | filename: defaultFilename,
29 | typing: false
30 | };
31 |
32 | this.save = this.save.bind(this);
33 | this.dontSave = this.dontSave.bind(this);
34 | this.cancel = this.cancel.bind(this);
35 | this.updateName = this.updateName.bind(this);
36 | }
37 |
38 | componentDidMount() {
39 | this.focusInput();
40 | }
41 |
42 | componentWillReceiveProps(nextProps){
43 | const { typing } = this.state;
44 |
45 | if(!typing){
46 | this.focusInput();
47 | this.setState({ filename: nextProps.defaultFilename });
48 | }
49 | }
50 |
51 | save(){
52 | const { filename } = this.state;
53 |
54 | const {
55 | saveFileAs
56 | } = this.props.handlers;
57 |
58 | saveFileAs(filename);
59 | this.clearName();
60 | }
61 |
62 | dontSave(){
63 | const {
64 | hideOverlay,
65 | dontSaveFile
66 | } = this.props.handlers;
67 |
68 | dontSaveFile();
69 | hideOverlay();
70 | this.clearName();
71 | }
72 |
73 | cancel(){
74 | const { hideOverlay } = this.props.handlers;
75 |
76 | hideOverlay();
77 | this.clearName();
78 | }
79 |
80 | updateName(evt){
81 | const { value } = evt.target;
82 |
83 | this.setState({
84 | filename: value,
85 | typing: true
86 | });
87 | }
88 |
89 | clearName(){
90 | this.setState({
91 | filename: '',
92 | typing: false
93 | });
94 | }
95 |
96 | focusInput() {
97 | const input = React.findDOMNode(this.refs.filename).getElementsByTagName('input')[0];
98 | const val = input.value;
99 | input.value = '';
100 | input.focus();
101 | input.value = val;
102 | }
103 |
104 | render(){
105 | const { isNew } = this.props;
106 | const { showDontSaveButton } = this.props.location.query;
107 | const { filename } = this.state;
108 |
109 | let dontSaveButton;
110 | if(isNew && showDontSaveButton){
111 | dontSaveButton = (
112 |
113 | );
114 | }
115 |
116 | return (
117 |
118 | Do you want to save the changes you made to this file?
119 |
126 |
127 |
128 | {dontSaveButton}
129 |
130 |
131 |
132 | );
133 | }
134 | }
135 |
136 | module.exports = createContainer(SaveOverlay, {
137 | getStores({ workspace }){
138 | return {
139 | workspace
140 | };
141 | },
142 |
143 | getPropsFromStores({ workspace }){
144 | const {
145 | isNew,
146 | filename
147 | } = workspace.getState();
148 |
149 | return {
150 | isNew,
151 | defaultFilename: filename
152 | };
153 | }
154 | });
155 |
--------------------------------------------------------------------------------
/src/plugins/keyboard-shortcuts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | The reason this file doesn't have some sort of generative
5 | event handlers is that they are generic now but are going
6 | to have "context" applied to them in the future.
7 |
8 | The functions may eventually be split into multiple files
9 | to reduce closures but for now, this is fine.
10 | */
11 |
12 | function keyboardShortcuts(app, opts, done){
13 |
14 | const { keypress, handlers } = app;
15 |
16 | const {
17 | F1,
18 | F3,
19 | F6,
20 | F7,
21 | F9,
22 | TAB,
23 | ESC,
24 | CTRL_I,
25 | CTRL_N,
26 | CTRL_O,
27 | CTRL_P,
28 | CTRL_R,
29 | CTRL_S,
30 | CTRL_T,
31 | CTRL_F4,
32 | CTRL_UP,
33 | SHIFT_F3,
34 | SHIFT_TAB,
35 | CTRL_DOWN,
36 | CTRL_SHIFT_S
37 | } = keypress;
38 |
39 | const {
40 | newFile,
41 | saveFile,
42 | hideOverlay,
43 | showHelpOverlay,
44 | showSaveOverlay,
45 | showDownloadOverlay,
46 | showProjectsOverlay,
47 | findNext,
48 | findPrevious,
49 | replace,
50 | moveByScrollUpLine,
51 | moveByScrollDownLine,
52 | indent,
53 | dedent,
54 | print,
55 | syntaxCheck,
56 | enableAutoDownload,
57 | disableAutoDownload
58 | } = handlers;
59 |
60 | keypress(CTRL_N, function(evt){
61 | evt.preventDefault();
62 | newFile();
63 | });
64 |
65 | keypress(CTRL_S, function(evt){
66 | evt.preventDefault();
67 | saveFile();
68 | });
69 |
70 | keypress(CTRL_SHIFT_S, function(evt){
71 | evt.preventDefault();
72 | showSaveOverlay();
73 | });
74 |
75 | keypress(CTRL_O, function(evt){
76 | evt.preventDefault();
77 | showProjectsOverlay();
78 | });
79 |
80 | keypress(ESC, function(evt){
81 | evt.preventDefault();
82 | // TODO: this won't clear text in a textbox, need to move to store?
83 | hideOverlay();
84 | });
85 |
86 | keypress(F1, function(evt){
87 | evt.preventDefault();
88 | showHelpOverlay();
89 | });
90 |
91 | keypress(F3, function(evt){
92 | evt.preventDefault();
93 | findNext();
94 | });
95 |
96 | keypress(SHIFT_F3, function(evt){
97 | evt.preventDefault();
98 | findPrevious();
99 | });
100 |
101 | keypress(CTRL_F4, function(evt){
102 | evt.preventDefault();
103 | replace();
104 | });
105 |
106 | keypress(CTRL_UP, function(evt){
107 | evt.preventDefault();
108 | moveByScrollUpLine();
109 | });
110 |
111 | keypress(CTRL_DOWN, function(evt){
112 | evt.preventDefault();
113 | moveByScrollDownLine();
114 | });
115 |
116 | keypress(TAB, function(evt){
117 | evt.preventDefault();
118 | indent();
119 | });
120 |
121 | keypress(SHIFT_TAB, function(evt){
122 | evt.preventDefault();
123 | dedent();
124 | });
125 |
126 | keypress(CTRL_P, function(evt){
127 | evt.preventDefault();
128 | print();
129 | });
130 |
131 | keypress(CTRL_T, function(evt){
132 | evt.preventDefault();
133 | syntaxCheck();
134 | });
135 |
136 | // TODO: combine with CTRL_T handler
137 | keypress(F7, function(evt){
138 | evt.preventDefault();
139 | syntaxCheck();
140 | });
141 |
142 | keypress(CTRL_R, function(evt){
143 | evt.preventDefault();
144 | enableAutoDownload();
145 | showDownloadOverlay();
146 | });
147 |
148 | // TODO: combine with CTRL_R handler
149 | keypress(F9, function(evt){
150 | evt.preventDefault();
151 | enableAutoDownload();
152 | showDownloadOverlay();
153 | });
154 |
155 | keypress(CTRL_I, function(evt){
156 | evt.preventDefault();
157 | disableAutoDownload();
158 | showDownloadOverlay();
159 | });
160 |
161 | // TODO: combine with CTRL_I handler
162 | keypress(F6, function(evt){
163 | evt.preventDefault();
164 | disableAutoDownload();
165 | showDownloadOverlay();
166 | });
167 |
168 | done();
169 | }
170 |
171 | module.exports = keyboardShortcuts;
172 |
--------------------------------------------------------------------------------
/src/views/rxtx.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | RxTx indicators were made a separate plugin for performance reasons
5 |
6 | They also don't use React
7 | */
8 |
9 | const _ = require('lodash');
10 | const React = require('react');
11 |
12 |
13 | const consoleStore = require('../console-store');
14 |
15 | const red = '#da2100';
16 | const blue = 'rgb(44, 131, 216)';
17 | const grey = '#666666';
18 |
19 | const styles = {
20 | bar: {
21 | margin: '0',
22 | height: '25px',
23 | backgroundColor: '#CFD8DC'
24 | },
25 | indicator: {
26 | backgroundColor: grey,
27 | height: '10px',
28 | width: '10px',
29 | borderRadius: '100%',
30 | margin: '0px 10px',
31 | display: 'inline-block'
32 | },
33 | rxtx: {
34 | float: 'right',
35 | paddingTop: '3px'
36 | },
37 | echo: {
38 | display: 'inline-block',
39 | paddingTop: '3px',
40 | paddingLeft: '16px'
41 | },
42 | echoOn: {
43 | color: '#000000'
44 | },
45 | echoOff: {
46 | color: '#888888'
47 | },
48 | rx: {
49 | backgroundColor: blue
50 | },
51 | tx: {
52 | backgroundColor: red
53 | }
54 | };
55 |
56 |
57 | class RxTx extends React.Component {
58 |
59 | componentDidMount(){
60 | const container = React.findDOMNode(this);
61 | const { toggleEcho } = this.props.handlers;
62 |
63 | let bottomBar;
64 | let rx;
65 | let tx;
66 | let echoContainer, echoLabel;
67 |
68 | function onConsoleChange(){
69 | const { rxtx, echo } = consoleStore.getState();
70 | const { flashRx, flashTx } = rxtx;
71 |
72 | if(flashRx){
73 | rx.style.backgroundColor = styles.rx.backgroundColor;
74 | } else {
75 | rx.style.backgroundColor = styles.indicator.backgroundColor;
76 | }
77 |
78 | if(flashTx){
79 | tx.style.backgroundColor = styles.tx.backgroundColor;
80 | } else {
81 | tx.style.backgroundColor = styles.indicator.backgroundColor;
82 | }
83 |
84 | if(echo){
85 | applyStyles(echoContainer, styles.echoOn);
86 | echoLabel.nodeValue = 'Echo On';
87 | }else{
88 | applyStyles(echoContainer, styles.echoOff);
89 | echoLabel.nodeValue = 'Echo Off';
90 | }
91 | }
92 |
93 | function applyStyles(el, stylesToApply){
94 | _.forEach(stylesToApply, (style, name) => el.style[name] = style);
95 | }
96 |
97 | if(!bottomBar){
98 | bottomBar = document.createElement('div');
99 | applyStyles(bottomBar, styles.bar);
100 |
101 | echoContainer = document.createElement('span');
102 | applyStyles(echoContainer, styles.echo);
103 | applyStyles(echoContainer, styles.echoOff);
104 | bottomBar.appendChild(echoContainer);
105 |
106 | echoLabel = document.createTextNode('Echo Off');
107 | echoContainer.appendChild(echoLabel);
108 |
109 | echoContainer.addEventListener('click', toggleEcho, false);
110 |
111 | const rxtxContainer = document.createElement('span');
112 | applyStyles(rxtxContainer, styles.rxtx);
113 | bottomBar.appendChild(rxtxContainer);
114 |
115 | tx = document.createElement('span');
116 | rx = document.createElement('span');
117 | const txLabel = document.createTextNode('TX');
118 | const rxLabel = document.createTextNode(' RX');
119 | rxtxContainer.appendChild(txLabel);
120 | rxtxContainer.appendChild(tx);
121 | rxtxContainer.appendChild(rxLabel);
122 | rxtxContainer.appendChild(rx);
123 | applyStyles(tx, styles.indicator);
124 | applyStyles(rx, styles.indicator);
125 |
126 | container.appendChild(bottomBar);
127 |
128 | consoleStore.subscribe(onConsoleChange);
129 | }
130 | }
131 |
132 | componentWillUnmount(){
133 | const container = React.findDOMNode(this);
134 | container.removeAll();
135 | }
136 |
137 |
138 | shouldComponentUpdate(){
139 | return false;
140 | }
141 |
142 | render(){
143 |
144 | return (
145 |
146 | );
147 | }
148 |
149 | }
150 |
151 | module.exports = RxTx;
152 |
--------------------------------------------------------------------------------
/src/views/project-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const React = require('react');
5 | const { createContainer } = require('sovereign');
6 | const Button = require('../components/button');
7 | const TextField = require('react-material/components/TextField');
8 |
9 | const Overlay = require('../components/overlay');
10 | const OverlayTitle = require('../components/overlay-title');
11 | const OverlayFooter = require('../components/overlay-footer');
12 | const ProjectList = require('../components/project-list');
13 | const ProjectListItem = require('../components/project-list-item');
14 | const DeleteButton = require('../components/delete-button');
15 |
16 | const styles = {
17 | textField: {
18 | containerStyling: {
19 | width: '100%'
20 | }
21 | }
22 | };
23 |
24 | class ProjectOverlay extends React.Component {
25 | constructor(){
26 | this.state = {
27 | projectName: ''
28 | };
29 |
30 | this.componentizeProject = this.componentizeProject.bind(this);
31 | this.updateName = this.updateName.bind(this);
32 | this.clearName = this.clearName.bind(this);
33 | this.create = this.create.bind(this);
34 | this.close = this.close.bind(this);
35 | }
36 |
37 | componentizeProject({ name, fullPath }){
38 | const self = this;
39 |
40 | const {
41 | cwd,
42 | handlers
43 | } = this.props;
44 |
45 | const {
46 | hideOverlay,
47 | changeProject,
48 | deleteProjectConfirm
49 | } = handlers;
50 |
51 | function onAccept(){
52 | changeProject(name);
53 | hideOverlay();
54 | self.clearName();
55 | }
56 |
57 | function onDelete(evt){
58 | evt.preventDefault();
59 | evt.stopPropagation();
60 |
61 | deleteProjectConfirm(name);
62 | }
63 |
64 | if(cwd === fullPath){
65 | return (
66 |
67 | {name}
68 |
69 | );
70 | } else {
71 | return (
72 |
73 | {name}
74 |
75 | );
76 | }
77 | }
78 |
79 | updateName(evt){
80 | const { value } = evt.target;
81 |
82 | this.setState({
83 | projectName: value
84 | });
85 | }
86 |
87 | clearName(){
88 | this.setState({
89 | projectName: ''
90 | });
91 | }
92 |
93 | create(){
94 | const {
95 | changeProject,
96 | hideOverlay
97 | } = this.props.handlers;
98 |
99 | const { projectName } = this.state;
100 |
101 | changeProject(projectName);
102 | hideOverlay();
103 | this.clearName();
104 | }
105 |
106 | close(){
107 | const { hideOverlay } = this.props.handlers;
108 |
109 | hideOverlay();
110 | this.clearName();
111 | }
112 |
113 | render(){
114 | const {
115 | projects
116 | } = this.props;
117 |
118 | const {
119 | projectName
120 | } = this.state;
121 |
122 | return (
123 |
124 | Open an existing project.
125 |
126 | {_.map(projects, this.componentizeProject)}
127 |
128 | Or start a brand new one.
129 |
135 |
136 |
137 |
138 |
139 |
140 | );
141 | }
142 | }
143 |
144 | module.exports = createContainer(ProjectOverlay, {
145 | getStores({ workspace }){
146 | return {
147 | workspace
148 | };
149 | },
150 |
151 | getPropsFromStores({ workspace }){
152 | const { cwd, projects } = workspace.getState();
153 |
154 | return {
155 | cwd,
156 | projects
157 | };
158 | }
159 | });
160 |
--------------------------------------------------------------------------------
/client.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const Irken = require('irken');
5 | const React = require('react');
6 | const { Router, Route, History, Link } = require('react-router');
7 | const memoryHistory = require('./src/lib/history');
8 |
9 | const Layout = require('./src/views/layout');
10 | const HelpOverlay = require('./src/views/help-overlay');
11 | const SaveOverlay = require('./src/views/save-overlay');
12 | const NewVersionOverlay = require('./src/views/new-version-overlay');
13 | const ProjectOverlay = require('./src/views/project-overlay');
14 | const DownloadOverlay = require('./src/views/download-overlay');
15 | const OverwriteOverlay = require('./src/views/overwrite-overlay');
16 | const DeleteFileOverlay = require('./src/views/delete-file-overlay');
17 | const DeleteProjectOverlay = require('./src/views/delete-project-overlay');
18 |
19 | const store = require('./src/store');
20 |
21 | const app = new Irken();
22 |
23 | const examples = _.reduce(EXAMPLES_LIST, function(result, name){
24 | result[name] = require(`./examples/${name}`);
25 | return result;
26 | }, {});
27 |
28 | const exampleFolder = 'examples';
29 |
30 | const plugins = [
31 | {
32 | register: require('bs2-serial')
33 | },
34 | {
35 | register: require('frylord'),
36 | options: {
37 | useTempFiles: true
38 | }
39 | },
40 | {
41 | register: require('snacks')
42 | },
43 | {
44 | register: require('skrim')
45 | },
46 | {
47 | register: require('iggins')
48 | },
49 | {
50 | register: require('./src/plugins/handlers')
51 | },
52 | {
53 | register: require('./src/plugins/examples'),
54 | options: {
55 | examples,
56 | folder: exampleFolder
57 | }
58 | },
59 | {
60 | register: require('./src/plugins/keyboard-shortcuts')
61 | },
62 | {
63 | register: require('./src/plugins/notifications')
64 | }
65 | ];
66 |
67 | function onRender(err){
68 | console.log('rendered', err);
69 |
70 | if(err){
71 | return;
72 | }
73 |
74 | const {
75 | userConfig,
76 | handlers
77 | } = app;
78 |
79 | const {
80 | newFile,
81 | showNewVersionOverlay,
82 | changeFile,
83 | changeProject,
84 | deviceAdded
85 | } = handlers;
86 |
87 | // Finish Loading Plugin
88 | // TODO: encapsulate into a startup handler?
89 | const config = userConfig.getState();
90 | const cwd = config.cwd || exampleFolder;
91 | const lastFile = config['last-file'];
92 | console.log(cwd, lastFile);
93 | changeProject(cwd)
94 | .then(() => {
95 | if(lastFile){
96 | changeFile(lastFile);
97 | } else {
98 | newFile();
99 | }
100 | showNewVersionOverlay();
101 | })
102 | .catch(console.error.bind(console));
103 |
104 | chrome.usb.onDeviceAdded.addListener(function(){
105 | setTimeout(deviceAdded, 200);
106 | });
107 | }
108 |
109 | function onRegister(err){
110 | console.log('registered', err, app);
111 | const addMountpoint = app.addMountpoint.bind(app);
112 | const removeMountpoint = app.removeMountpoint.bind(app);
113 | const { workspace, handlers } = app;
114 |
115 | if(err){
116 | return;
117 | }
118 |
119 | const RouterLayout = React.createClass({
120 | render() {
121 | console.log('render layout', this.props);
122 | return (
123 | {this.props.children && React.cloneElement(this.props.children, { handlers, workspace, store })}
124 |
125 | );
126 | }
127 | });
128 |
129 | const Component = (
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | );
143 |
144 | React.render(Component, document.body.firstChild, onRender);
145 | }
146 |
147 | app.register(plugins, onRegister);
148 |
149 | // for debugging purposes
150 | window.app = app;
151 | window.memoryHistory = memoryHistory;
152 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Parallax IDE
2 | Write, compile, and download code to your Parallax Boe-Bot Robot or custom BASIC Stamp microcontroller-based electronic creations.
3 |
4 | ## Quickstart
5 |
6 | 1. Visit our [github releases](https://github.com/parallaxinc/Parallax-IDE/releases) and download the desired release or download the latest release [here](https://github.com/parallaxinc/Parallax-IDE/releases/latest).
7 |
8 | 1. Go to your downloads folder and unzip the archive.
9 |
10 | _*Note:* for use on Chromebook you will need to unzip the archive and copy the unzipped directory onto the Chromebook._
11 |
12 | 1. Open Chrome and follow the [Installing in Chrome](https://github.com/parallaxinc/Parallax-IDE#user-content-installing-in-chrome) instructions.
13 |
14 | ## Building from Source/Developing
15 |
16 | Most of below is a one-time procedure needed to build the application, unless otherwise noted. To build the application you will need the node.js JavaScript runtime. node.js itself comes bundled with the `npm` package manager. If you don't have it, then:
17 |
18 | 1. Install node.js by going to [nodejs.org/download](https://nodejs.org/download/) and selecting the option that is right for your system.
19 |
20 | 1. You also need all the dependencies for node-gyp, a tool that comes with node.js for compiling native addon modules. The gyp project is used by the Chromium team makes it easier to build across platforms.
21 |
22 | Please visit the [node-gyp page](https://github.com/TooTallNate/node-gyp#installation) and note your system and the dependencies you will need.
23 |
24 | __* Note: that you do not need to install node-gyp, only its dependencies.__
25 |
26 | 1. Clone this respository. Assuming you have `git` installed (if not, [go here](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git)), choose your file destination from the command-line (CLI like Terminal), and
27 |
28 | ` git clone git@github.com:parallaxinc/Parallax-IDE `
29 |
30 | 
31 |
32 | 1. Go to the project root directory with
33 |
34 | ` cd Parallax-IDE/ `
35 |
36 | 1. Get all the project dependencies. At the root of the project you will find `package.json`. This manifest file includes a list of project dependencies needed to build the application. To learn more, [see this post on dependency installation](https://github.com/iceddev/getting-started/blob/master/environments/nodejs-and-npm.md#user-content-dependency-installation). __This step must be run each time you update the repository (including pulling updates from GitHub).__
37 |
38 | To get dependencies, enter:
39 |
40 | ` npm install `
41 |
42 | _*Note:* To ensure all dependencies are updated, it's recommended to do the following_
43 |
44 | ```
45 | npm cache clean
46 | npm install
47 | ```
48 |
49 | 1. Build the application by entering. __This step must be run each time you update the repository (including pulling updates from GitHub).__
50 |
51 | `npm run build` or `npm run build -- --watch`*
52 |
53 | __* Note: using `--watch` will result in a rebuild of the application any time a file changes__
54 |
55 |
56 | ## Installing in Chrome
57 |
58 | 1. Open your Chrome browser and navigate to
59 |
60 | ` chrome://extensions `
61 |
62 | 1. Enable 'Developer Mode' by clicking the checkbox.
63 |
64 | 
65 |
66 | 1. Before you install your extension must be built and bundled. If you haven't done so follow the instructions in the [Build from Source](#user-content-build-from-source) section first.
67 |
68 | 1. Click on __'Load unpacked extensions...'__, go to the directory where Parallax IDE was built, highlight the *'Parallax-IDE'* folder and and click select.
69 |
70 | 
71 | 
72 |
73 | 1. Return to the ` chrome://extensions ` page and you should see __'Parallax IDE'__ listed in available extensions.
74 |
75 | 
76 | 1. Ensure the checkbox is *'enabled'* and click __'launch'__.
77 | 1. __Congratulations!__ You just launched Parallax IDE which will look something like this:
78 |
79 | 
80 |
81 |
82 | ## Coming Back
83 |
84 | One you install the built application it is super easy to launch it again. You can either:
85 |
86 | * go to ` chrome:// extensions `, search through the list until you find *Parallax IDE* and then click `launch'
87 |
88 | or
89 |
90 | * go to chrome app launcher and click on/search for *Parallax IDE*
91 |
92 | 
93 |
94 | 
95 |
96 |
--------------------------------------------------------------------------------
/fonts/roboto.css:
--------------------------------------------------------------------------------
1 | /* roboto-100 - latin */
2 | @font-face {
3 | font-family: 'Roboto';
4 | font-style: normal;
5 | font-weight: 100;
6 | src: local('Roboto Thin'), local('Roboto-Thin'),
7 | url('roboto-v15-latin-100.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
8 | url('roboto-v15-latin-100.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
9 | }
10 | /* roboto-100italic - latin */
11 | @font-face {
12 | font-family: 'Roboto';
13 | font-style: italic;
14 | font-weight: 100;
15 | src: local('Roboto Thin Italic'), local('Roboto-ThinItalic'),
16 | url('roboto-v15-latin-100italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
17 | url('roboto-v15-latin-100italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
18 | }
19 | /* roboto-300 - latin */
20 | @font-face {
21 | font-family: 'Roboto';
22 | font-style: normal;
23 | font-weight: 300;
24 | src: local('Roboto Light'), local('Roboto-Light'),
25 | url('roboto-v15-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
26 | url('roboto-v15-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
27 | }
28 | /* roboto-300italic - latin */
29 | @font-face {
30 | font-family: 'Roboto';
31 | font-style: italic;
32 | font-weight: 300;
33 | src: local('Roboto Light Italic'), local('Roboto-LightItalic'),
34 | url('roboto-v15-latin-300italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
35 | url('roboto-v15-latin-300italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
36 | }
37 | /* roboto-regular - latin */
38 | @font-face {
39 | font-family: 'Roboto';
40 | font-style: normal;
41 | font-weight: 400;
42 | src: local('Roboto'), local('Roboto-Regular'),
43 | url('roboto-v15-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
44 | url('roboto-v15-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
45 | }
46 | /* roboto-italic - latin */
47 | @font-face {
48 | font-family: 'Roboto';
49 | font-style: italic;
50 | font-weight: 400;
51 | src: local('Roboto Italic'), local('Roboto-Italic'),
52 | url('roboto-v15-latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
53 | url('roboto-v15-latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
54 | }
55 | /* roboto-500 - latin */
56 | @font-face {
57 | font-family: 'Roboto';
58 | font-style: normal;
59 | font-weight: 500;
60 | src: local('Roboto Medium'), local('Roboto-Medium'),
61 | url('roboto-v15-latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
62 | url('roboto-v15-latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
63 | }
64 | /* roboto-500italic - latin */
65 | @font-face {
66 | font-family: 'Roboto';
67 | font-style: italic;
68 | font-weight: 500;
69 | src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
70 | url('roboto-v15-latin-500italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
71 | url('roboto-v15-latin-500italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
72 | }
73 | /* roboto-700 - latin */
74 | @font-face {
75 | font-family: 'Roboto';
76 | font-style: normal;
77 | font-weight: 700;
78 | src: local('Roboto Bold'), local('Roboto-Bold'),
79 | url('roboto-v15-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
80 | url('roboto-v15-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
81 | }
82 | /* roboto-700italic - latin */
83 | @font-face {
84 | font-family: 'Roboto';
85 | font-style: italic;
86 | font-weight: 700;
87 | src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'),
88 | url('roboto-v15-latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
89 | url('roboto-v15-latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
90 | }
91 | /* roboto-900 - latin */
92 | @font-face {
93 | font-family: 'Roboto';
94 | font-style: normal;
95 | font-weight: 900;
96 | src: local('Roboto Black'), local('Roboto-Black'),
97 | url('roboto-v15-latin-900.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
98 | url('roboto-v15-latin-900.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
99 | }
100 | /* roboto-900italic - latin */
101 | @font-face {
102 | font-family: 'Roboto';
103 | font-style: italic;
104 | font-weight: 900;
105 | src: local('Roboto Black Italic'), local('Roboto-BlackItalic'),
106 | url('roboto-v15-latin-900italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+ */
107 | url('roboto-v15-latin-900italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
108 | }
109 |
--------------------------------------------------------------------------------
/src/views/download-overlay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const React = require('react');
5 | const Button = require('../components/button');
6 | const Loader = require('react-loader');
7 | const { createContainer } = require('sovereign');
8 |
9 | const Overlay = require('../components/overlay');
10 | const OverlayTitle = require('../components/overlay-title');
11 | const OverlayFooter = require('../components/overlay-footer');
12 | const ProgressBar = require('../components/progress-bar');
13 |
14 | const styles = {
15 | overlay: {
16 | paddingBottom: 40,
17 | width: 600,
18 | // keep the download progress pinned to the bottom
19 | position: 'relative'
20 | },
21 | overlayFooter: {
22 | marginLeft: 0,
23 | display: 'flex'
24 | },
25 | errorSpan: {
26 | color: '#FF0000',
27 | display: 'inline-block'
28 | },
29 | deviceTable: {
30 | width: '100%',
31 | maxWidth: '100%',
32 | borderCollapse: 'collapse',
33 | borderSpacing: 0
34 | },
35 | deviceTh: {
36 | padding: '8px 8px 8px 0',
37 | textAlign: 'left',
38 | borderTop: 0,
39 | borderBottom: '2px solid #ddd',
40 | verticalAlign: 'bottom',
41 | fontWeight: 'bold'
42 | },
43 | deviceTr:{
44 | height: '3rem'
45 | },
46 | deviceTd: {
47 | padding: '8px 8px 8px 0',
48 | borderSpacing: 'collapse',
49 | verticalAlign: 'top',
50 | borderTop: '1px solid #ddd'
51 | },
52 | statusTh: {
53 | padding: '8px 8px 8px 0',
54 | textAlign: 'left',
55 | borderTop: 0,
56 | borderBottom: '2px solid #ddd',
57 | verticalAlign: 'bottom',
58 | fontWeight: 'bold',
59 | maxWidth: 160
60 | },
61 | statusTd: {
62 | padding: '8px 8px 8px 0',
63 | borderSpacing: 'collapse',
64 | verticalAlign: 'top',
65 | borderTop: '1px solid #ddd',
66 | maxWidth: 160,
67 | overflow: 'auto',
68 | whiteSpace: 'nowrap',
69 | color: '#333333'
70 | },
71 | scrollingContainer: {
72 | height: 325,
73 | overflow: 'auto',
74 | position: 'relative'
75 | },
76 | bottomBar: {
77 | height: 40,
78 | position: 'absolute',
79 | bottom: 0,
80 | left: 0,
81 | width: '100%',
82 | display: 'flex'
83 | },
84 | overlayUserMessage: {
85 | color: '#911',
86 | backgroundColor: '#fcdede',
87 | padding: '10px 16px',
88 | textAlign: 'center',
89 | width: '100%'
90 | },
91 | refreshButton: {
92 | marginRight: 'auto'
93 | },
94 | active: {
95 | backgroundColor: '#ddd'
96 | },
97 | inactive: {
98 | backgroundColor: 'transparent'
99 | }
100 | };
101 |
102 | class DownloadOverlay extends React.Component {
103 |
104 | constructor(...args){
105 | super(...args);
106 |
107 | this.componentizeDevice = this.componentizeDevice.bind(this);
108 | }
109 |
110 | componentizeDevice(device){
111 | const {
112 | path,
113 | handlers
114 | } = this.props;
115 |
116 | const {
117 | selectDevice
118 | } = handlers;
119 |
120 | const highlight = device.path === path ? 'active' : 'inactive';
121 | const deviceRowStyle = _.assign({}, styles.deviceTr, styles[highlight]);
122 | return (
123 | selectDevice(device)}>
124 | | {device.name} |
125 | {device.version} |
126 | {device.path} |
127 | {device.displayError} |
128 |
129 | );
130 | }
131 |
132 | render(){
133 | const {
134 | deviceList,
135 | searchStatus,
136 | downloadProgress,
137 | searching,
138 | handlers
139 | } = this.props;
140 |
141 | const {
142 | reloadDevices,
143 | hideOverlay
144 | } = handlers;
145 |
146 | const deviceRows = _.map(deviceList, this.componentizeDevice);
147 |
148 | let bottomBar;
149 | if(searchStatus){
150 | bottomBar = (
151 | {searchStatus}
152 | );
153 | } else {
154 | bottomBar = (
155 |
156 | );
157 | }
158 |
159 | return (
160 |
161 | Please choose your connected device.
162 |
163 |
164 |
165 |
166 |
167 | | Device |
168 | Version |
169 | Port |
170 | Status |
171 |
172 |
173 |
174 | {deviceRows}
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 | {bottomBar}
185 |
186 |
187 | );
188 | }
189 |
190 | }
191 |
192 | module.exports = createContainer(DownloadOverlay, {
193 | getStores({ store }){
194 | return {
195 | store
196 | };
197 | },
198 |
199 | getPropsFromStores({ store }) {
200 | const { deviceList, device, downloadProgress } = store.getState();
201 | const { searchStatus, searching, path } = device;
202 |
203 | return {
204 | deviceList,
205 | downloadProgress,
206 | searchStatus,
207 | searching,
208 | path
209 | };
210 | }
211 | });
212 |
--------------------------------------------------------------------------------
/src/lib/scroller.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 |
5 | function Scroller(consoleElement) {
6 | this.lines = [];
7 | this.lineOffset = 0;
8 | this.visibleCount = 50;
9 | this.startPosition = 0;
10 | this.endPosition = 0;
11 | this.animateRequest = null;
12 | this.sticky = true;
13 | this.jumpToBottom = true;
14 | this.dirty = false;
15 | this.console = consoleElement;
16 | this.expandDistance = 200;
17 |
18 | //pre-bind functions
19 | this.refresh = this._renderVisible.bind(this);
20 | this.scroll = this._onScroll.bind(this);
21 | this.expandTop = this._expandTop.bind(this);
22 | this.expandBottom = this._expandBottom.bind(this);
23 | }
24 |
25 | Scroller.prototype._generateContent = function(){
26 | return _(this.lines)
27 | .slice(this.startPosition - this.lineOffset, this.endPosition - this.lineOffset)
28 | .map(function(line){
29 | if(line.length === 0){
30 | // insert a blank space to prevent pre omitting a trailing newline,
31 | // even though pre/pre-nowrap/pre-line are specified.
32 | return '\u2009';
33 | }
34 | return line;
35 | })
36 | .join('\n');
37 | };
38 |
39 | Scroller.prototype.setLines = function(newLines, offset) {
40 | this.lines = newLines;
41 | this.lineOffset = offset;
42 | if(this.sticky){
43 | this.endPosition = this.lineCount();
44 | this.startPosition = Math.max(this.lineOffset, this.endPosition - this.visibleCount);
45 | if(this.endPosition <= this.visibleCount * 2){
46 | // follow text during initial lines (console can show up to twice the visibleCount when expanding)
47 | this.jumpToBottom = true;
48 | }
49 | }else if(newLines.length === 1 && newLines[0].length === 0){
50 | // ^^ `lines` is reset to an array with one empty line. ugh.
51 |
52 | // handle the reset case when lines is replaced with an empty array
53 | // we don't have a direct event that can call this
54 | this.reset();
55 | }else if(this.lineOffset > this.startPosition){
56 | // when buffer trims and we are now below the trimmed area, move up by difference
57 | const lineDiff = this.lineOffset - this.startPosition;
58 | this.startPosition += lineDiff;
59 | this.endPosition += lineDiff;
60 | }
61 | this.dirty = true;
62 | };
63 |
64 | Scroller.prototype.lineCount = function(){
65 | return this.lines.length + this.lineOffset;
66 | };
67 |
68 | Scroller.prototype.reset = function(){
69 | this.endPosition = Math.max(0, this.lineCount());
70 | this.startPosition = Math.max(0, this.endPosition - this.visibleCount);
71 | this.lineOffset = 0;
72 | this.jumpToBottom = true;
73 | this.sticky = true;
74 | this.dirty = true;
75 | };
76 |
77 | Scroller.prototype.requestRefresh = function(){
78 | if(this.console){
79 | this.animateRequest = requestAnimationFrame(this.refresh);
80 | }
81 | };
82 |
83 | Scroller.prototype._renderVisible = function(){
84 | this.animateRequest = null;
85 | if(this.dirty && this.console){
86 | if(this.sticky){
87 | this.endPosition = this.lineCount();
88 | this.startPosition = Math.max(this.lineOffset, this.endPosition - this.visibleCount);
89 | }
90 | this.console.innerHTML = this._generateContent();
91 | if(this.jumpToBottom){
92 | this.console.scrollTop = 4000;
93 | this.jumpToBottom = false;
94 | }
95 | this.dirty = false;
96 | }
97 | };
98 |
99 | Scroller.prototype._expandTop = function(){
100 | this.startPosition = Math.max(this.lineOffset, this.startPosition - this.visibleCount);
101 | if(this.console){
102 | this.sticky = false;
103 | const scrollHeight = this.console.scrollHeight;
104 | const scrollTop = this.console.scrollTop;
105 |
106 | // do an inline scroll to avoid potential scroll interleaving
107 | this.console.innerHTML = this._generateContent();
108 | const newScrollHeight = this.console.scrollHeight;
109 | this.console.scrollTop = scrollTop + newScrollHeight - scrollHeight;
110 |
111 | const oldEndPos = this.endPosition;
112 | this.endPosition = Math.min(this.endPosition, this.startPosition + (this.visibleCount * 2));
113 |
114 | this.dirty = oldEndPos !== this.endPosition;
115 | if(this.dirty && !this.animateRequest){
116 | this.animateRequest = requestAnimationFrame(this.refresh);
117 | }
118 | }
119 | };
120 |
121 | Scroller.prototype._expandBottom = function(){
122 | this.endPosition = Math.min(this.lineCount(), this.endPosition + this.visibleCount);
123 | if(this.console){
124 | // add the new content to the bottom, then get scroll position to remove content
125 | this.console.innerHTML = this._generateContent();
126 | const scrollHeight = this.console.scrollHeight;
127 | const scrollTop = this.console.scrollTop;
128 |
129 | // update start position and render
130 | this.startPosition = Math.max(this.lineOffset, Math.min(this.lineCount() - (this.visibleCount * 2), this.endPosition - (this.visibleCount * 2)));
131 | this.console.innerHTML = this._generateContent();
132 |
133 | // use difference to scroll offset
134 | const newScrollHeight = this.console.scrollHeight;
135 | this.console.scrollTop = scrollTop - (scrollHeight - newScrollHeight);
136 |
137 | this.dirty = false;
138 | }
139 | };
140 |
141 | Scroller.prototype._onScroll = function(){
142 | if(this.jumpToBottom){
143 | // do nothing, prepare to jump
144 | return;
145 | }
146 | const height = this.console.offsetHeight;
147 | const scrollHeight = this.console.scrollHeight;
148 | const scrollTop = this.console.scrollTop;
149 | const nearTop = scrollTop < this.expandDistance;
150 | const nearBottom = scrollTop + height > scrollHeight - this.expandDistance;
151 | const nearSticky = scrollTop + height > scrollHeight - 10;
152 |
153 | if(this.sticky){
154 | if(!nearSticky){
155 | this.sticky = false;
156 | }
157 | }else{
158 | if(nearTop && this.startPosition > this.lineOffset){
159 | this.expandTop();
160 | }else if(nearBottom){
161 | if(this.endPosition < this.lineCount() - 2){
162 | this.expandBottom();
163 | }else if(nearSticky){
164 | this.jumpToBottom = true;
165 | this.sticky = true;
166 | this.dirty = true;
167 | }
168 | }
169 | }
170 |
171 |
172 |
173 | if(this.dirty && !this.animateRequest){
174 | this.animateRequest = requestAnimationFrame(this.refresh);
175 | }
176 | };
177 |
178 | module.exports = Scroller;
179 |
--------------------------------------------------------------------------------
/src/lib/terminal.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 |
5 | const TAB_WIDTH = 8;
6 |
7 | class Terminal {
8 | constructor() {
9 | this.state = {
10 | lastRefresh: 0,
11 | lines: [''],
12 | lineWrap: 256,
13 | lineOffset: 0,
14 | maxLines: 10000,
15 | pointerLine: 0,
16 | pointerColumn: 0,
17 | refreshDelayMillis: 64,
18 | refreshQueued: null,
19 | trimCount: 64
20 | };
21 |
22 | this.queue = this.queue.bind(this);
23 | }
24 |
25 | queue(cb){
26 | this.state.lastRefresh = Date.now();
27 | this.state.refreshQueued = null;
28 | cb();
29 | }
30 |
31 | clearAll(){
32 | const { refreshQueued } = this.state;
33 |
34 | this.state.lines = [''];
35 | this.state.lineOffset = 0;
36 | this.state.pointerLine = 0;
37 | this.state.pointerColumn = 0;
38 |
39 | if(refreshQueued != null){
40 | clearInterval(refreshQueued);
41 | this.state.refreshQueued = null;
42 | }
43 | this.state.lastRefresh = 0;
44 | }
45 |
46 | refreshBuffer(msg, cb) {
47 | const { lastRefresh, refreshDelayMillis, refreshQueued } = this.state;
48 |
49 | this._update(msg);
50 |
51 | if(refreshQueued != null){
52 | return;
53 | }
54 |
55 | // TODO: remove zalgo
56 | if(lastRefresh < Date.now() - refreshDelayMillis){
57 | this.queue(cb);
58 | } else {
59 | this.state.refreshQueued = setTimeout(this.queue, refreshDelayMillis, cb);
60 | }
61 | }
62 |
63 | _update(events) {
64 | if(Array.isArray(events)){
65 | _.forEach(events, this.processEvent, this);
66 | }else{
67 | this.processEvent(events);
68 | }
69 | }
70 |
71 | setCursorPosition(line, col){
72 | const { lines } = this.state;
73 | for(let ix = lines.length; ix <= line; ix++){
74 | lines[ix] = '';
75 | }
76 | this.state.pointerLine = Math.max(0, line);
77 | this.state.pointerColumn = Math.min(255, Math.max(0, col));
78 | }
79 |
80 | backspace(){
81 | const { lines, pointerLine, pointerColumn } = this.state;
82 | if(pointerColumn > 0){
83 | const targetLine = lines[pointerLine];
84 | if(pointerColumn < targetLine.length){
85 | lines[pointerLine] = targetLine.slice(0, pointerColumn - 1) + targetLine.slice(pointerColumn);
86 | } else {
87 | lines[pointerLine] = targetLine.slice(0, pointerColumn - 1);
88 | }
89 | this.state.pointerColumn = pointerColumn - 1;
90 | } else {
91 | const prevLineNum = Math.max(0, pointerLine - 1);
92 | const prevLine = lines[prevLineNum] || '';
93 | this.state.pointerLine = prevLineNum;
94 | this.state.pointerColumn = prevLine.length;
95 | }
96 | }
97 |
98 | clearEol(){
99 | const { lines, pointerLine, pointerColumn } = this.state;
100 | const line = lines[pointerLine] || '';
101 | if(pointerColumn < line.length){
102 | lines[pointerLine] = line.slice(0, pointerColumn);
103 | }
104 | }
105 |
106 | clearBelow(){
107 | const { lines, pointerLine } = this.state;
108 | _.fill(lines, '', pointerLine, lines.length);
109 | this.state.pointerColumn = 0;
110 | }
111 |
112 | tab(){
113 | const { pointerColumn } = this.state;
114 | const tabColumn = Math.floor(pointerColumn / TAB_WIDTH);
115 | this.state.pointerColumn = (tabColumn + 1) * TAB_WIDTH;
116 | }
117 |
118 | processEvent(evt){
119 | const { pointerLine, pointerColumn } = this.state;
120 | switch(evt.type){
121 | case 'text':
122 | this.addText(evt.data);
123 | break;
124 | case 'linefeed':
125 | this.setCursorPosition(pointerLine + 1, 0);
126 | break;
127 | case 'cursor-home':
128 | this.setCursorPosition(0, 0);
129 | break;
130 | case 'cursor-position':
131 | this.setCursorPosition(evt.data[1], evt.data[0]);
132 | break;
133 | case 'cursor-position-x':
134 | this.setCursorPosition(pointerLine, evt.data[0]);
135 | break;
136 | case 'cursor-position-y':
137 | this.setCursorPosition(evt.data[0], pointerColumn);
138 | break;
139 | case 'cursor-left':
140 | this.setCursorPosition(pointerLine, pointerColumn - 1);
141 | break;
142 | case 'cursor-right':
143 | this.setCursorPosition(pointerLine, pointerColumn + 1);
144 | break;
145 | case 'cursor-up':
146 | this.setCursorPosition(pointerLine - 1, pointerColumn);
147 | break;
148 | case 'cursor-down':
149 | this.setCursorPosition(pointerLine + 1, pointerColumn);
150 | break;
151 | case 'clear-screen':
152 | this.clearAll();
153 | break;
154 | case 'backspace':
155 | this.backspace();
156 | break;
157 | case 'clear-eol':
158 | this.clearEol();
159 | break;
160 | case 'clear-below':
161 | this.clearBelow();
162 | break;
163 | case 'tab':
164 | this.tab();
165 | break;
166 | default:
167 | console.log('Not yet implemented:', evt);
168 | break;
169 | }
170 | }
171 |
172 | addText(newText){
173 | const { lines, lineWrap, trimCount, maxLines } = this.state;
174 |
175 | let { pointerColumn, pointerLine } = this.state;
176 |
177 | while(newText.length > 0){
178 | let oldLine = lines[pointerLine] || '';
179 | let initial = _.padRight(oldLine.slice(0, pointerColumn), pointerColumn);
180 |
181 | let insert = newText.slice(0, Math.max(lineWrap - initial.length, 0));
182 |
183 | let remainder = oldLine.slice(insert.length + initial.length);
184 |
185 | let leftOver = newText.slice(insert.length);
186 |
187 | lines[pointerLine] = initial + insert + remainder;
188 |
189 | newText = leftOver;
190 | if(newText.length > 0){
191 | pointerLine++;
192 | pointerColumn = 0;
193 | }else{
194 | pointerColumn = initial.length + insert.length;
195 | }
196 | }
197 |
198 | if(lines.length > maxLines){
199 | const newLines = lines.slice(trimCount);
200 | this.state.lines = newLines;
201 | this.state.lineOffset = this.state.lineOffset + trimCount;
202 | this.state.pointerLine = Math.max(0, pointerLine - trimCount);
203 | this.state.pointerColumn = pointerColumn;
204 | } else {
205 | this.state.pointerLine = pointerLine;
206 | this.state.pointerColumn = pointerColumn;
207 | }
208 | }
209 |
210 | getLines(){
211 | return this.state.lines;
212 | }
213 |
214 | getOffset(){
215 | return this.state.lineOffset;
216 | }
217 |
218 | }
219 |
220 | module.exports = Terminal;
221 |
--------------------------------------------------------------------------------