├── .eslintrc.json ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── actions │ └── fetch-electron-versions │ │ ├── action.yml │ │ ├── dist │ │ └── index.js │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json └── workflows │ ├── main.yml │ └── publish.yml ├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── docs ├── code_structure.md ├── developing.md ├── publish.md ├── serialport-rebuild.md └── settings.md ├── keymaps └── pycom-sync.json ├── lib ├── board │ ├── authorize.js │ ├── pyboard.js │ ├── shell-workers.js │ ├── shell.js │ └── snippets.js ├── config.js ├── connections │ ├── auto-connect.js │ ├── connection.js │ ├── device.js │ ├── pyserial.js │ ├── pysocket.js │ ├── pytelnet.js │ └── telnet │ │ ├── format.js │ │ ├── telnetcli.js │ │ └── util-telnet.js ├── features │ ├── run │ │ └── runner.js │ ├── snippets │ │ └── snippets.js │ └── sync │ │ ├── project-status.js │ │ ├── sync-helper.js │ │ └── sync.js ├── helpers │ ├── commands.js │ ├── logger.js │ └── utils.js ├── main.js ├── pybytes.js ├── pymakr.js ├── third-parties │ ├── chrome-tabs.js │ └── draggabilly.pkgd.min.js ├── views │ ├── action-view.html │ ├── action-view.js │ ├── info-view.html │ ├── info-view.js │ ├── overlay-view.html │ ├── overlay-view.js │ ├── panel-view.html │ ├── panel-view.js │ ├── pybytes-panel-home.html │ ├── pybytes-panel.html │ ├── sidebar-view.html │ ├── sidebar-view.js │ ├── snippets-view.html │ ├── snippets-view.js │ └── terminal.js └── wrappers │ ├── api-wrapper.js │ └── settings-wrapper.js ├── menus └── pycom-sync.json ├── native_modules ├── @serialport │ └── bindings │ │ └── lib │ │ └── binding │ │ ├── node-v69-darwin-x64 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v69-linux-ia32 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v69-linux-x64 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v69-win32-ia32 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v69-win32-x64 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v70-darwin-x64 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v70-linux-ia32 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v70-linux-x64 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v70-win32-ia32 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v70-win32-x64 │ │ ├── bindings.node │ │ ├── config.gypi │ │ └── origin.md │ │ ├── node-v73-darwin-x64 │ │ ├── bindings.node │ │ └── origin.md │ │ ├── node-v73-linux-ia32 │ │ ├── bindings.node │ │ └── origin.md │ │ ├── node-v73-linux-x64 │ │ ├── bindings.node │ │ └── origin.md │ │ ├── node-v73-win32-ia32 │ │ ├── bindings.node │ │ └── origin.md │ │ ├── node-v73-win32-x64 │ │ ├── bindings.node │ │ └── origin.md │ │ ├── node-v80-darwin-x64 │ │ └── bindings.node │ │ ├── node-v80-linux-x64 │ │ └── bindings.node │ │ ├── node-v80-win32-ia32 │ │ └── bindings.node │ │ └── node-v80-win32-x64 │ │ └── bindings.node └── included_runtimes.md ├── package-lock.json ├── package.json ├── scripts ├── atom-versions-fetcher.sh ├── compress.py ├── download-binaries.js ├── functions-versions.js ├── mp-download-atom.ps1 ├── post-install.js ├── restart-atom.sh └── update-check.js ├── snippets ├── ble-connect-data.py ├── index.js ├── lte-cat-m1.py ├── lte-get-imei.py ├── lte-nb-iot.py ├── pyscan.py ├── pysense.py ├── pytrack.py ├── rgb-led-traficlight.py ├── wifi-multi-network.py ├── wifi-simple.py └── wifi-static-ip.py ├── spec ├── pycom-sync-atom-spec.js └── pycom-sync-atom-view-spec.js ├── styles ├── assets │ ├── logo-navy.png │ ├── logo.png │ ├── pybytes-logo.png │ └── pycom-icon.svg ├── pymakr.less ├── tabs.less └── xterm.css └── test-electron ├── bindings_1.5.0 ├── LICENSE.md ├── README.md ├── bindings.js └── package.json ├── index.js ├── package.json └── runtest.ps1 /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": ["airbnb-base", "prettier"], 7 | "globals": { 8 | "Atomics": "readonly", 9 | "SharedArrayBuffer": "readonly" 10 | }, 11 | "parserOptions": { 12 | "ecmaVersion": 2018, 13 | "sourceType": "module" 14 | }, 15 | "rules": { 16 | "no-underscore-dangle": "off", 17 | "quotes": [2, "single", { "avoidEscape": true }], 18 | "arrow-parens": "off", 19 | "no-eval": "off", 20 | "class-methods-use-this": "off", 21 | "operator-linebreak": "off", 22 | "radix": "off" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via an issue, email, or any other method with the owners of this repository before making a change. 4 | 5 | *Please note we have a Code of Conduct, please follow it in all your interactions with the project.* 6 | 7 | ## Pull Request Process 8 | 9 | 1. Update the `README.md` with details of changes to the interface, this includes new environment variables, useful file locations and container parameters. 10 | 2. Increase the version numbers in any examples files and the `README.md` to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org). 11 | 12 | ## Code of Conduct 13 | 14 | ### Our Pledge 15 | 16 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 17 | 18 | ### Our Standards 19 | 20 | Examples of behaviour that contributes to creating a positive environment include: 21 | 22 | * Using welcoming and inclusive language 23 | * Being respectful of differing viewpoints and experiences 24 | * Gracefully accepting constructive criticism 25 | * Focusing on what is best for the community 26 | * Showing empathy towards other community members 27 | 28 | Examples of unacceptable behaviour by participants include: 29 | 30 | * The use of sexualised language or imagery and unwelcome sexual attention or advances 31 | * Trolling, insulting/derogatory comments, and personal or political attacks 32 | * Public or private harassment 33 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 34 | * Other conduct which could reasonably be considered inappropriate in a professional setting 35 | 36 | ### Our Responsibilities 37 | 38 | Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviours that they deem inappropriate, threatening, offensive, or harmful. 41 | 42 | ### Scope 43 | 44 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 45 | 46 | ### Enforcement 47 | 48 | Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by contacting the project team at `support[at]pycom.io` and adding the `[CoC]` tag to the subject line. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 49 | 50 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 51 | 52 | ### Attribution 53 | 54 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 55 | 56 | [homepage]: http://contributor-covenant.org 57 | [version]: http://contributor-covenant.org/version/1/4 58 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | (Hi! 👋 Thanks for reporting an issue! Please make sure you click the link above to view the issue guidelines, then fill out the blanks below.) 8 | 9 | ## What are the steps to reproduce this issue? 10 | 1. 11 | 2. 12 | 3. 13 | 14 | ## What happens? 15 | 16 | 17 | ## What were you expecting to happen? 18 | 19 | 20 | ## Any logs, error output, etc? 21 | *(If it’s long, please paste to https://gist.github.com and insert the link here)* 22 | 23 | 24 | ## Any other comments? 25 | 26 | 27 | ## What versions of software are you using? 28 | 29 | **Operating system:** 30 | 31 | **Atom version:** 32 | 33 | **Pymakr version:** 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | # Feature Request 🚀 8 | 9 | ## Is your feature request related to a problem? Please describe. 10 | *A clear and concise description of what the problem is. E.g. I have an issue when...* 11 | 12 | 13 | ## Describe the solution you'd like 14 | *A clear and concise description of what you want to happen. Add any considered drawbacks.* 15 | 16 | 17 | ## Describe alternatives you've considered 18 | *A clear and concise description of any alternative solutions or features you've considered.* 19 | 20 | 21 | ## Teachability, Documentation, Adoption, Migration Strategy 22 | *If you can, explain how users will be able to use this and possibly write out a version the docs. Maybe a screenshot or design?* 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | (Hi! 👋 Thanks for sending a pull request! Please make sure you click the link above to view the contribution guidelines, then fill out the blanks below.) 2 | 3 | ## What does this implement/fix? Explain your changes. 4 | 5 | 6 | ## Does this close any currently open issues? 7 | 8 | 9 | ## Any relevant logs, error output, etc? 10 | *(If it’s long, please paste to https://gist.github.com and insert the link here)* 11 | 12 | 13 | ## Any other comments? 14 | 15 | 16 | ## Where has this been tested? 17 | 18 | **Operating system:** 19 | 20 | **Atom version:** 21 | 22 | **Pymakr version:** 23 | -------------------------------------------------------------------------------- /.github/actions/fetch-electron-versions/action.yml: -------------------------------------------------------------------------------- 1 | name: "Fetch Electron Versions" 2 | description: "Fetch and Parse Electron Versions to Test for Atom" 3 | author: BradenM 4 | inputs: 5 | max-count: 6 | default: 2 7 | description: "Max Number of versions to return" 8 | required: false 9 | git-token: 10 | description: "Github Authentication Token" 11 | required: true 12 | outputs: 13 | versions: 14 | description: "Electron Versions to Test" 15 | runs: 16 | using: "node12" 17 | main: "dist/index.js" 18 | -------------------------------------------------------------------------------- /.github/actions/fetch-electron-versions/index.js: -------------------------------------------------------------------------------- 1 | const core = require("@actions/core"); 2 | const github = require("@actions/github"); 3 | const axios = require("axios"); 4 | const gitToken = core.getInput("git-token") || process.env.GITHUB_TOKEN; 5 | const octokit = new github.GitHub(gitToken); 6 | 7 | const repo = { 8 | owner: "atom", 9 | repo: "atom" 10 | }; 11 | 12 | const unsupportedElectronVersions = ["3.1.10"]; 13 | 14 | /** 15 | * Resolves Electron runtime target for given 16 | * Atom git tag 17 | * 18 | * @param {string} tag - VSCode Git Tag 19 | * @returns {*} Object with tag and runtime_version 20 | */ 21 | const resolveElectronVersion = async tag => { 22 | try { 23 | // Fetch package.json file (contains electron target) 24 | const response = await axios.get( 25 | `https://raw.githubusercontent.com/atom/atom/${tag}/package.json` 26 | ); 27 | const version = response.data.electronVersion.toString(); 28 | 29 | core.info(`Atom ${tag} uses Electron v${version}`); 30 | return version; 31 | } catch (e) { 32 | throw e; 33 | } 34 | }; 35 | 36 | /** 37 | * Fetches three different electron versions from Atom Git Tags 38 | * 39 | * @param {number} count - maximum number of versions to return 40 | * @returns {string[]} Array containing master and 3 of the latest tags 41 | */ 42 | const getAtomTagsElectron = async (count = 3) => { 43 | try { 44 | console.log("Fetching tags..."); 45 | const tags = ( 46 | await octokit.repos.listTags({ 47 | ...repo, 48 | per_page: 50 49 | }) 50 | ).data.map(item => item.name); 51 | const atomNightlyTag = tags[0]; 52 | let currentIndex = 1; 53 | let atomCurrentTag = tags[currentIndex]; 54 | while ( 55 | (atomCurrentTag.includes('beta') || 56 | (atomCurrentTag=='master') && currentIndex < 10) 57 | ) { 58 | currentIndex += 1; 59 | atomCurrentTag = tags[currentIndex]; 60 | } 61 | const atomNightlyElectron = await resolveElectronVersion( 62 | atomNightlyTag, 63 | ); 64 | const atomCurrentElectron = await resolveElectronVersion(atomCurrentTag); 65 | const electronVersions = []; 66 | electronVersions.push(atomCurrentElectron); 67 | if (atomCurrentElectron != atomNightlyElectron) 68 | electronVersions.push(atomNightlyElectron); 69 | const filteredFoundTags = electronVersions.filter( 70 | item => 71 | !unsupportedElectronVersions.some( 72 | version => version === item 73 | ) 74 | ); 75 | if (filteredFoundTags.length != electronVersions.length) { 76 | console.log( 77 | `\nRemoved ${foundTags.length - 78 | filteredFoundTags.length} unsupported electron version (${unsupportedElectronVersions.join( 79 | ", " 80 | )})` 81 | ); 82 | } 83 | core.info(`\nElectron Versions: ${filteredFoundTags} \n`); 84 | core.setOutput("versions", filteredFoundTags); 85 | } catch (error) { 86 | core.setFailed(error.message); 87 | } 88 | }; 89 | 90 | getAtomTagsElectron(); 91 | -------------------------------------------------------------------------------- /.github/actions/fetch-electron-versions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "compile-modules-action", 3 | "version": "1.0.0", 4 | "description": "Compiles Native Modules for XPlatform Support", 5 | "main": "index.js", 6 | "author": "BradenM", 7 | "license": "MIT", 8 | "scripts": { 9 | "build": "ncc build index.js" 10 | }, 11 | "dependencies": { 12 | "@actions/core": "^1.2.0", 13 | "@actions/github": "^1.1.0", 14 | "atob": "^2.1.2", 15 | "axios": "^0.19.0" 16 | }, 17 | "devDependencies": { 18 | "ncc": "^0.3.6", 19 | "@zeit/ncc": "^0.20.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build Pymakr 2 | 3 | on: 4 | pull_request: ~ 5 | push: 6 | branches-ignore: 7 | - "dependabot/**" 8 | paths-ignore: 9 | - "doc/**" 10 | schedule: 11 | # Run everyday at 1am 12 | - cron: "0 1 * * *" 13 | 14 | jobs: 15 | build: 16 | name: "Build ${{ matrix.os }}" 17 | runs-on: ${{ matrix.os }} 18 | strategy: 19 | matrix: 20 | os: [windows-latest, macos-latest, ubuntu-latest] 21 | steps: 22 | - uses: actions/checkout@v1 23 | 24 | - name: Setup node 25 | uses: actions/setup-node@v1.2.0 26 | env: 27 | ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' 28 | with: 29 | node-version: "10" 30 | 31 | - name: Fetch Electron Versions 32 | id: electron 33 | uses: ./.github/actions/fetch-electron-versions 34 | with: 35 | max-count: 3 36 | git-token: ${{ secrets.GITHUB_TOKEN }} 37 | 38 | - name: Install Dependencies 39 | shell: bash 40 | run: | 41 | npm install npx 42 | npm add prebuild-install --save-dev 43 | npm install --no-audit 44 | 45 | # todo: fix errors in running prebuild-install in Action runners 46 | # - name: Update Native Modules 47 | # run: npm run download-native 48 | 49 | # TODO 50 | # - name: Test Bindings 51 | 52 | # generic all up electron test 53 | - name: Test Bindings (macOS/Windows) 54 | if: matrix.os != 'ubuntu-latest' 55 | run: npm run test-electron -- ${{ steps.electron.outputs.versions }} 56 | 57 | # electron tests with virtual x server 58 | - name: Test Bindings (Linux) 59 | if: matrix.os == 'ubuntu-latest' 60 | run: xvfb-run -e /dev/stdout -a npm run test-electron -- ${{ steps.electron.outputs.versions }} 61 | 62 | # No tests written :( 63 | # - name: Run Tests 64 | # run: npm run test 65 | 66 | # - name: Package Extension 67 | # run: npx vsce package -o pymakr-${{ github.sha }}.vsix 68 | 69 | # - name: Upload VSIX 70 | # if: github.event_name == 'schedule' 71 | # uses: actions/upload-artifact@master 72 | # with: 73 | # name: pymakr-nightly.vsix 74 | # path: ./pymakr-${{ github.sha }}.vsix 75 | 76 | # deploy: 77 | # name: Publish 78 | # needs: build 79 | # # if current branch name contains release and is not a PR 80 | # if: contains(github.ref, 'release') && github.event_name == 'push' 81 | # runs-on: ubuntu-latest 82 | # steps: 83 | # - uses: actions/checkout@v1 84 | 85 | # - name: Install Production Dependencies 86 | # run: | 87 | # npm ci 88 | # npm prune --production 89 | 90 | # - name: Package Extension 91 | # run: npx vsce package 92 | 93 | # - name: Publish Extension 94 | # run: npx vsce publish --pat ${{ secrets.VSCE_TOKEN }} 95 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Deploy PyMakr 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | environment: atom-publish-config 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | persist-credentials: false 18 | 19 | - name: Install Atom 20 | uses: UziTech/action-setup-atom@v2 21 | 22 | - name: Install Node.js 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: 16 26 | 27 | - run: npm ci 28 | 29 | - name: Publish 30 | # for testing, add -- --dry-run --debug 31 | run: npm run semantic-release -- --debug 32 | env: 33 | ATOM_ACCESS_TOKEN: ${{ secrets.PUBLISHER_TOKEN }} 34 | GH_TOKEN: ${{ secrets.ADMIN_TOKEN }} 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | connection_state.json 5 | # ignore the vscode instance used in testing 6 | .atom-test/* 7 | 8 | # ignore the test package lock ( but not the package file) 9 | test-electron/package-lock.json 10 | 11 | scripts/atom 12 | scripts/pymakr 13 | atom 14 | pymakr 15 | precompiles 16 | 17 | .history -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 70 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Pycom Limited. 2 | 3 | This software is licensed under the GNU GPL version 3 or any 4 | later version, with permitted additional terms. For more information 5 | see the Pycom Licence v1.0 document supplied with this file, or 6 | available at https://www.pycom.io/opensource/licensing 7 | -------------------------------------------------------------------------------- /docs/code_structure.md: -------------------------------------------------------------------------------- 1 | 2 | | Folder | Description 3 | |------------------|------------------------------------------------- 4 | | docs | Instructions for developers 5 | | keymaps | Hotkeys 6 | | lib | functional code for the pymakr package 7 | | lib/board | *Shared with VSC plugin* All code related to communication with the Pycom boards 8 | | lib/connections | *Shared with VSC plugin* Lotic to connect to the board 9 | | lib/helpers | *Shared with VSC plugin* Utils and logger 10 | | lib/main | Main logic of the Pymakr plugin 11 | | lib/python | Python files for execution on the Pycom boards, used by the upload/download/run features 12 | | lib/snippets | Code files for the 'snippets' feature (pymakr 2.0 only) 13 | | lib/config.js | All parameters and default configurations for the plugin 14 | | lib/main.js | The main file that starts the plugin, called from package.json 15 | | lib/pymakr.js | 16 | | menus | Describes the commands and context menus for Pymakr to Atom 17 | | precompiles | Folder with precompiled bindings for the serialport library 18 | | scripts | Some functional scripts for different procedures used in the pakcage, from installation to runtime compression of python code 19 | | spec | Basic code for tests for the package 20 | | styles | CSS styles for the UI 21 | -------------------------------------------------------------------------------- /docs/developing.md: -------------------------------------------------------------------------------- 1 | - uninstall pymakr 2 | - Clone pymakr github to local folder 3 | - Run 'apm link' and 'apm install' from that folder 4 | - Reload atom 5 | 6 | - Micropython specific documentation on REPL / RAW_REPL / ect: 7 | - http://docs.micropython.org/en/latest/ 8 | -------------------------------------------------------------------------------- /docs/publish.md: -------------------------------------------------------------------------------- 1 | Procedure 2 | - Merge new code to master 3 | - Update changelog.md 4 | - Make sure to up the version compatibility in package.json if needed "engines->atom" 5 | - Push to master 6 | - Run 'apm publish major|minor|patch' command to publish to the Atom servers 7 | - This updates package.json with the right version 8 | - Creates a tag 9 | - Pushes it to master 10 | - then deploys to the atom servers 11 | More info: https://flight-manual.atom.io/hacking-atom/sections/publishing/ 12 | 13 | To be able to publish, you need access to the pycom/pymakr-atom repo on github. Secondly, you need to create a personal access token for the command line. See these instructions: 14 | https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line 15 | -------------------------------------------------------------------------------- /docs/serialport-rebuild.md: -------------------------------------------------------------------------------- 1 | The serialport library has to be re-build against the version of electron of the latest atom (folder /precompiles) 2 | 3 | - Get the version of the latest atom version 4 | - run 'process.versions.electron' in the atom dev console 5 | - In 'index.js' change the 'electron_version' variable to this version 6 | - Run rebuild.js. This will: 7 | - Remove node_modules 8 | - Run 'apm install' again 9 | - this will trigger index.js to be run, that will rebuild serialport using electron-rebuild 10 | - Find the bindings.node file from node_modules/@serialport/bindings/build/Release/bindings.node 11 | - Copy that bindings.node file to 'precompiles/serialport-' 12 | 13 | To recompile for all OS systems, we'll have to run the above script on those operating systems: linux, osx, win32 and win64 14 | 15 | More documentation on electron rebuild: 16 | - https://github.com/electron/electron-rebuild 17 | -------------------------------------------------------------------------------- /docs/settings.md: -------------------------------------------------------------------------------- 1 | ## Settings 2 | The majority of the sessing can be specified in both the global config file as wel as the per project file. 3 | 4 | | Setting | Project | Global | Default | Purpose 5 | |------------------|---------|--------|-----------------------| ----------------------------------------------------------- 6 | | open_on_start | yes | yes | true | Weather to open the terminal and connect to the board when starting Code 7 | | address | yes | yes | /something | IP address or comport for your device 8 | | username | yes | yes | micro | Board username, only for telnet 9 | | password | yes | yes | python | Board password, only for telnet 10 | | ctrl_c_on_connect| yes | yes | false | If true, executes a ctrl-c on connect to stop running programs 11 | |||| 12 | | auto_connect | no | yes | true | Autoconnect on USB. Ignores any \'address\' setting and automatically connects to the top item in the serialport list 13 | | autoconnect_comport_manufacturers| no | yes | 'Pycom','Pycom Ltd.','FTDI', 'Microsoft','Microchip Technology, Inc.'| Comma separated list of all the comport manufacturers supported for the autoconnect feature. Defaults to all possible manufacturers that pycom boards can return. 14 | |||| 15 | | sync_folder | yes | yes | "" | Folder to synchronize. Empty to sync projects main folder 16 | | sync_file_types | yes | yes | "py,txt,log,json,xml,html,js, css,mpy" | Types of files to be synchronized 17 | | sync_all_file_types | yes | yes | false | 'If enabled, all files will be uploaded no matter the file type. The list of file types below will be ignored 18 | | py_ignore | yes | yes | [] | Comma separated list of files and folders to ignore when uploading (no wildcard or regular expressions supported) 19 | |||| 20 | | safe_boot_on_upload | yes | yes | false | Safe-boot before upload, Only works with firmware v1.16.0.b1 and up. Safe boots the board before uploading to prevent running out of memory while uploading. Especially useful on older boards with less memory, but adds about 2 seconds to the upload procedure' 21 | | reboot_after_upload| yes | yes | true | Reboots your pycom board after any upload or download action 22 | |||| 23 | | fast_upload | yes | yes | false| Fast upload (experimental), Uses bigger batches and compresses larger (>4kb) files to make uploading faster. Only works on newer devices with 4mb of ram and firmware version >=1.19.x 24 | |||| 25 | | statusbar_buttons| yes | yes |['status', 'run', 'upload', 'download', 'disconnect', 'listserial', 'settings', 'projectsettings', 'getversion', 'getssid'] | Which quick-access buttons to show in the statusbar. 26 | -------------------------------------------------------------------------------- /keymaps/pycom-sync.json: -------------------------------------------------------------------------------- 1 | { 2 | "atom-workspace": { 3 | "ctrl-alt-s": "pymakr:upload", 4 | "ctrl-shift-s": "pymakr:uploadFile", 5 | "ctrl-alt-t": "pymakr:toggle REPL", 6 | "ctrl-alt-c": "pymakr:connect", 7 | "ctrl-alt-d": "pymakr:disconnect", 8 | "ctrl-alt-r": "pymakr:run", 9 | "ctrl-shift-enter": "pymakr:runselection", 10 | "ctrl-r": "pymakr:clearTerminal" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/board/authorize.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | export default class Authorize { 4 | constructor(pyboard) { 5 | this.pyboard = pyboard; 6 | this.running = false; 7 | this.received_login_as = false; 8 | } 9 | 10 | run(cb) { 11 | const { pyboard } = this; 12 | const _this = this; 13 | this.running = true; 14 | 15 | if (pyboard.connection.type === 'telnet') { 16 | pyboard.waitForBlocking('Login as:', (err) => { 17 | _this.received_login_as = true; 18 | if (err) { 19 | _this._stoppedRunning(); 20 | if (err.message === 'timeout') { 21 | cb(new Error('Login timed out')); 22 | } else { 23 | cb(new Error(err.message)); 24 | } 25 | } else { 26 | pyboard.sendWaitForBlocking(pyboard.params.username, 'Password:', (err2) => { 27 | if (err2 && err2.message === 'timeout') { 28 | _this._stoppedRunning(); 29 | cb(new Error('Username timed out')); 30 | } else { 31 | // timeout of 50 ms to be sure the board is ready to receive the password 32 | // Without this, sometimes connecting via the boards access point fails 33 | setTimeout(() => { 34 | pyboard.sendWaitForBlocking( 35 | pyboard.params.password, 36 | 'Login succeeded!\r\nType "help()" for more information.\r\n', 37 | err3 => { 38 | _this._stoppedRunning(); 39 | if (err3 && err3.message === 'timeout') { 40 | cb('Password timed out'); 41 | } else { 42 | cb(null); 43 | } 44 | }, 45 | 7000, 46 | ); 47 | }, 50); 48 | } 49 | }, 7000); 50 | } 51 | }, 7000); 52 | } else { 53 | cb('Telnet connection, no login needed'); 54 | this.running = false; 55 | } 56 | } 57 | 58 | _stoppedRunning() { 59 | this.running = false; 60 | this.received_login_as = false; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/board/shell-workers.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Logger from '../helpers/logger'; 4 | 5 | const binascii = require('binascii'); 6 | 7 | export default class ShellWorkers { 8 | constructor(shell, pyboard, settings) { 9 | this.shell = shell; 10 | this.settings = settings; 11 | this.BIN_CHUNK_SIZE = this.settings.upload_chunk_size; 12 | this.pyboard = pyboard; 13 | this.logger = new Logger('ShellWorkers'); 14 | } 15 | 16 | writeFile(value, callback) { 17 | const _this = this; 18 | const blockSize = _this.BIN_CHUNK_SIZE; 19 | const content = value[0]; 20 | const counter = value[1]; 21 | let errMsg = ''; 22 | 23 | if (counter * blockSize >= content.length) { 24 | callback(null, content, true); 25 | } else { 26 | const start = counter * blockSize; 27 | const end = Math.min((counter + 1) * blockSize, content.length); 28 | const chunk = content.base64Slice(start, end); 29 | // c = binascii.b2a_base64(chunk) 30 | 31 | _this.pyboard.execRaw( 32 | `f.write(ubinascii.a2b_base64('${chunk}'))\r\n`, 33 | (err, data) => { 34 | let newErr = err; 35 | if ( 36 | data.includes('Traceback: ') || 37 | data.includes('Error: ') 38 | ) { 39 | errMsg = data.slice(data.indexOf('Error: ') + 7, -3); 40 | newErr = new Error(`Failed to write file: ${errMsg}`); 41 | } 42 | if (newErr) { 43 | _this.logger.error('Failed to write chunk:'); 44 | _this.logger.error(newErr); 45 | callback(newErr, null); 46 | return; 47 | } 48 | callback(null, [content, counter + 1]); 49 | }, 50 | ); 51 | } 52 | } 53 | 54 | listFiles(params, callback) { 55 | const _this = this; 56 | let [root, names, fileList] = params; 57 | if (names.length === 0) { 58 | callback(null, fileList, true); 59 | } else { 60 | const currentFile = names[0]; 61 | const currentFileRoot = `${root}/${currentFile}`; 62 | names = names.splice(1); 63 | const isDir = currentFile.indexOf('.') === -1; 64 | if (isDir) { 65 | let c = 'import ubinascii,sys\r\n'; 66 | c += `list = ubinascii.hexlify(str(os.listdir('${currentFileRoot}')))\r\n`; 67 | c += 'sys.stdout.write(list)\r\n'; 68 | _this.shell.eval(c, (err, content) => { 69 | if (content) { 70 | let data = binascii.unhexlify(content); 71 | data = data.slice(1, -2); 72 | try { 73 | const list = eval(data); 74 | for (let i = 0; i < list.length; i += 1) { 75 | const item = list[i]; 76 | names.push( 77 | _this.getFileWithPath(currentFileRoot, item), 78 | ); 79 | } 80 | callback(null, [root, names, fileList]); 81 | } catch (e) { 82 | _this.logger.error('Evaluation of content went wrong'); 83 | _this.logger.error(e); 84 | callback(e, [root, names, fileList]); 85 | } 86 | } else { 87 | callback(new Error('Failed to write file'), [ 88 | root, 89 | names, 90 | fileList, 91 | ]); 92 | } 93 | }); 94 | } else { 95 | let filePath = currentFileRoot; 96 | if (filePath[0] === '/') { 97 | filePath = filePath.substring(1); 98 | } 99 | 100 | filePath = filePath.replace('/flash/', ''); 101 | filePath = filePath.replace('flash/', ''); 102 | 103 | fileList.push(filePath); 104 | callback(null, [root, names, fileList]); 105 | } 106 | } 107 | } 108 | 109 | getFileWithPath(root, file) { 110 | let rootCleaned = root.replace('/flash/', ''); 111 | rootCleaned = rootCleaned.replace('flash/', ''); 112 | 113 | if (rootCleaned !== '') { 114 | rootCleaned += '/'; 115 | } 116 | let filePath = rootCleaned + file; 117 | if (filePath[0] === '/') { 118 | filePath = filePath.substring(1); 119 | } 120 | return filePath; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/board/snippets.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import ApiWrapper from '../main/api-wrapper'; 4 | import ConfigSnippets from '../config-snippets'; 5 | 6 | const fs = require('fs'); 7 | 8 | export default class Snippets { 9 | constructor(view) { 10 | this.view = view; 11 | this.api = new ApiWrapper(); 12 | this.arraylist = ConfigSnippets.defaults().files; 13 | this.hashlist = {}; 14 | this.package_path = this.api.getPackageSrcPath(); 15 | this.project_path = this.api.getProjectPath(); 16 | this.snippets_path = `${this.package_path}snippets/`; 17 | this.list(); 18 | 19 | const _this = this; 20 | this.view.on('snippet.copy', (id) => { 21 | _this.copy(id); 22 | }); 23 | 24 | this.view.on('snippet.create_file', (id, content) => { 25 | _this.create_file(id, content); 26 | }); 27 | 28 | this.view.on('snippet.insert', (id, content) => { 29 | _this.insert(id, content); 30 | }); 31 | } 32 | 33 | list() { 34 | for (const i in this.arraylist) { 35 | const item = this.arraylist[i]; 36 | if (!item.code) { 37 | item.filename = `${item.id}.py`; 38 | item.filepath = this.snippets_path + item.filename; 39 | item.code = fs.readFileSync(item.filepath); 40 | } 41 | this.hashlist[item.id] = item; 42 | } 43 | return this.arraylist; 44 | } 45 | 46 | get(id) { 47 | return this.hashlist[id]; 48 | } 49 | 50 | copy(id) { 51 | this.api.writeToCipboard(this.hashlist[id].code); 52 | return true; 53 | } 54 | 55 | create_file(id, content) { 56 | const item = this.hashlist[id]; 57 | let filename = `${id}.py`; 58 | let filepath = `${this.project_path}/${filename}`; 59 | let i = 1; 60 | if (!content) { 61 | content = item.code; 62 | } 63 | while (fs.existsSync(filepath)) { 64 | filename = `${id}[${i}].py`; 65 | filepath = `${this.project_path}/${filename}`; 66 | 67 | i += 1; 68 | } 69 | fs.writeFile(filepath, content); 70 | atom.workspace.open(filepath); 71 | this.api.info(`Created snippet file ${filename} inside your project`); 72 | return fs.existsSync(filepath); 73 | } 74 | 75 | insert(id, content) { 76 | if (!content) { 77 | content = this.hashlist[id].code; 78 | } 79 | return this.api.insertInOpenFile(content); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/connections/auto-connect.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Config from '../config'; 4 | import Logger from '../helpers/logger'; 5 | import Utils from '../helpers/utils'; 6 | import PySerial from './pyserial'; 7 | 8 | const EventEmitter = require('events'); 9 | 10 | export default class AutoConnect extends EventEmitter { 11 | constructor(pymakr, terminal, settings) { 12 | super(); 13 | this.terminal = terminal; 14 | this.pymakr = pymakr; 15 | this.settings = settings; 16 | this.logger = new Logger('ConnectionHelper'); 17 | this.autoConnect_timer = null; 18 | this.autoConnect_address = undefined; 19 | this.connection_timer = null; 20 | this.addresses = []; 21 | this.address_names = []; 22 | this.ip_addresses = []; 23 | this.ip_address_names = []; 24 | this.initial_scan = true; 25 | this.utils = new Utils(settings); 26 | } 27 | 28 | getAllAddressNames() { 29 | return this.address_names.concat(this.ip_address_names); 30 | } 31 | 32 | getAllAddresses() { 33 | return this.addresses.concat(this.ip_addresses); 34 | } 35 | 36 | enabled() { 37 | return this.settings.auto_connect; 38 | } 39 | 40 | start(cb, wait) { 41 | const _this = this; 42 | this.stop(); 43 | if (!wait) { 44 | this.refreshPycomBoards(); 45 | } 46 | 47 | this.refreshIpAddresses(); 48 | 49 | this.settings.onChange('address', () => { 50 | _this.refreshIpAddresses(); 51 | }); 52 | 53 | this.autoConnect_timer = setInterval(() => { 54 | _this.refreshPycomBoards(); 55 | }, 2500); 56 | } 57 | 58 | stop() { 59 | if (this.autoConnect_timer) { 60 | clearInterval(this.autoConnect_timer); 61 | this.autoConnect_address = undefined; 62 | } 63 | } 64 | 65 | sleep(ms) { 66 | return new Promise(resolve => { 67 | setTimeout(() => { 68 | resolve(ms); 69 | }, ms); 70 | }); 71 | } 72 | 73 | refreshIpAddresses() { 74 | let addedAddresses = 0; 75 | $('#pymakr-address-list').html( 76 | '
No valid IP addresses found
', 77 | ); 78 | if ( 79 | typeof this.settings.address === 'string' || 80 | this.settings.address instanceof String 81 | ) { 82 | if (this.settings.address !== 'PASTE_YOUR_SERIAL_PORT_HERE') { 83 | this.addIpAddress(this.settings.address); 84 | addedAddresses += 1; 85 | } 86 | } else { 87 | for (let i = 0; i < this.settings.address.length; i += 1) { 88 | const a = this.settings.address[i]; 89 | if (this.ip_addresses.indexOf(a) === -1) { 90 | this.addIpAddress(a); 91 | addedAddresses += 1; 92 | } 93 | } 94 | for (let j = 0; j < this.ip_addresses.length; j += 1) { 95 | const ip = this.ip_addresses[j]; 96 | if (this.settings.address.indexOf(ip) === -1) { 97 | this.removeIpAddress(ip); 98 | addedAddresses -= 1; 99 | j -= 1; 100 | } 101 | } 102 | } 103 | if (addedAddresses) { 104 | $('#pymakr-address-list').removeClass('disabled'); 105 | } else { 106 | $('#pymakr-address-list').addClass('disabled'); 107 | $('#pymakr-address-list').html( 108 | '
No valid addresses were found
', 109 | ); 110 | } 111 | } 112 | 113 | refreshPycomBoards(cb) { 114 | const _this = this; 115 | const addressStartCount = this.address_names.length; 116 | 117 | PySerial.listPycom(this.settings, async (list, manufacturers) => { 118 | for (let i = 0; i < list.length; i += 1) { 119 | const name = list[i]; 120 | const m = manufacturers[i]; 121 | if (_this.address_names.indexOf(name) === -1) { 122 | _this.addToAddresses(name, m); 123 | // it's necessary in this case 124 | // eslint-disable-next-line no-await-in-loop 125 | await _this.sleep(100); 126 | } 127 | } 128 | for (let i = 0; i < _this.addresses.length; i += 1) { 129 | if (list.indexOf(_this.addresses[i].name) === -1) { 130 | _this.removeAddress(_this.addresses[i].name, i); 131 | } 132 | } 133 | if ( 134 | list.length === 0 && 135 | (addressStartCount > 0 || this.initial_scan) 136 | ) { 137 | this.emit('autoconnect.no_addresses'); 138 | } 139 | if (!this.initial_scan) { 140 | this.initial_scan = true; 141 | } 142 | if (cb) { 143 | cb(this.addresses, this.address_names); 144 | } 145 | }); 146 | } 147 | 148 | addIpAddress(ip) { 149 | this.ip_addresses.push(ip); 150 | this.ip_address_names.push(ip); 151 | this.emit('autoconnect.ip_added', ip); 152 | } 153 | 154 | removeIpAddress(ip) { 155 | const i = this.ip_addresses.indexOf(ip); 156 | if (i > -1) { 157 | this.ip_addresses.splice(i, 1); 158 | this.emit('autoconnect.ip_removed', ip); 159 | } 160 | } 161 | 162 | addToAddresses(name, manual) { 163 | const title = `${name} (${manual})`; 164 | const shortName = this.utils.shortenComport(name); 165 | const comInfo = { 166 | name, 167 | manual, 168 | title, 169 | shortName, 170 | }; 171 | this.addresses.push(comInfo); 172 | this.address_names.push(name); 173 | this.emit('autoconnect.address_added', comInfo, name); 174 | } 175 | 176 | removeAddress(name, i) { 177 | this.addresses.splice(i, 1); 178 | this.address_names.splice(i, 1); 179 | this.emit('autoconnect.address_removed', name); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /lib/connections/connection.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Logger from '../helpers/logger'; 4 | import ApiWrapper from '../wrappers/api-wrapper'; 5 | 6 | export default class Connection { 7 | constructor(device, pyboard, settings) { 8 | this.pyboard = pyboard; 9 | this.terminal = device.terminal; 10 | this.settings = settings; 11 | this.device = device; 12 | this.view = this.device.view; 13 | this.api = new ApiWrapper(settings); 14 | this.logger = new Logger('ConnectionHelper'); 15 | this.message_callback = null; 16 | this.connection_timer = null; 17 | } 18 | 19 | setMessageCallback(cb) { 20 | this.message_callback = cb; 21 | } 22 | 23 | connectedInOtherWindow(address) { 24 | const state = this.api.getConnectionState(address); 25 | const ts = new Date().getTime(); 26 | if ( 27 | state && 28 | state.project !== this.view.project_name && 29 | state.timestamp > ts - 11000 30 | ) { 31 | return state.project; 32 | } 33 | return null; 34 | } 35 | 36 | connect(cb, onDisconnect) { 37 | const _this = this; 38 | 39 | const { address } = this.device; 40 | 41 | this.terminal.writeln(`Connecting to ${this.device.address}...`); 42 | 43 | this.logger.info('Connecting...'); 44 | this.logger.info(address); 45 | 46 | this.pyboard.refreshConfig(() => { 47 | const onconnect = err => { 48 | if (err) { 49 | _this.device.writeln(`Connection error: ${err}`); 50 | } else { 51 | _this.api.setConnectionState( 52 | address, 53 | true, 54 | _this.view.project_name, 55 | ); 56 | cb(true); 57 | } 58 | }; 59 | 60 | const onerror = err => { 61 | let message = _this.pyboard.getErrorMessage(err.message); 62 | if (message === '') { 63 | message = err.message ? err.message : 'Unknown error'; 64 | } 65 | 66 | if (_this.pyboard.connected) { 67 | _this.logger.warning(`An error occurred: ${message}`); 68 | if (_this.device.synchronizing) { 69 | this.terminal.writeln(`An error occurred: ${message}`); 70 | _this.logger.warning('Synchronizing, stopping sync'); 71 | _this.device.sync_helper.stopSilent(); 72 | } 73 | } else { 74 | _this.terminal.writeln(`> Failed to connect (${message}).`); 75 | } 76 | if (onDisconnect) { 77 | onDisconnect(); 78 | } 79 | }; 80 | 81 | const ontimeout = () => { 82 | _this.terminal.writeln('> Connection timed out.'); 83 | if (onDisconnect) { 84 | onDisconnect(); 85 | } 86 | }; 87 | 88 | const onmessage = mssg => { 89 | _this.message_callback(mssg); 90 | }; 91 | 92 | _this.pyboard.connect( 93 | address, 94 | onconnect, 95 | onerror, 96 | ontimeout, 97 | onmessage, 98 | ); 99 | }); 100 | } 101 | 102 | disconnect(cb) { 103 | const _this = this; 104 | this.logger.info('Disconnecting...'); 105 | if (this.pyboard.isConnecting()) { 106 | this.terminal.writeln('Connection attempt canceled'); 107 | } 108 | 109 | const continueDisconnect = () => { 110 | clearInterval(this.connection_timer); 111 | _this.api.setConnectionState(_this.pyboard.address, false); 112 | _this.pyboard.disconnect(() => { 113 | if (cb) cb(); 114 | }); 115 | _this.device.synchronizing = false; 116 | }; 117 | 118 | if (this.device.synchronizing) { 119 | this.device.sync_helper.stop(() => { 120 | this.device.synchronizing = false; 121 | continueDisconnect(); 122 | }); 123 | } else { 124 | continueDisconnect(); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /lib/connections/pyserial.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Logger from '../helpers/logger'; 4 | 5 | const { SerialPort } = require('serialport'); 6 | const fs = require('fs'); 7 | 8 | export default class PySerial { 9 | constructor(address, params, settings) { 10 | this.type = 'serial'; 11 | this.params = params; 12 | this.address = address; 13 | this.ayt_pending = false; 14 | this.logger = new Logger('PySerial'); 15 | this.stream = new SerialPort( 16 | { 17 | path: address, 18 | baudRate: 115200, 19 | autoOpen: false, 20 | } 21 | ); 22 | 23 | this.comport_manufacturers = 24 | settings.autoconnect_comport_manufacturers; 25 | const dtrSupport = ['darwin']; 26 | 27 | this.dtr_supported = dtrSupport.indexOf(process.platform) > -1; 28 | } 29 | 30 | connect(onconnect, onerror, ontimeout) { 31 | const _this = this; 32 | let errorThrown = false; 33 | 34 | // open errors will be emitted as an error event 35 | this.stream.on('error', err => { 36 | if (!errorThrown) { 37 | errorThrown = true; 38 | onerror(new Error(err)); 39 | } 40 | }); 41 | 42 | let timeout = null; 43 | this.stream.open(() => { 44 | _this.sendPing(err => { 45 | if (!err) { 46 | clearTimeout(timeout); 47 | _this.send('\r\n', () => { 48 | onconnect(); 49 | }); 50 | } 51 | }); 52 | }); 53 | 54 | timeout = setTimeout(() => { 55 | if (!errorThrown) { 56 | errorThrown = true; 57 | ontimeout(new Error('Timeout while connecting')); 58 | _this.disconnect(() => {}); 59 | } 60 | }, _this.params.timeout); 61 | } 62 | 63 | disconnect(cb) { 64 | this.stream.close(); 65 | cb(); 66 | } 67 | 68 | registerListener(cb) { 69 | const _this = this; 70 | this.onmessage = cb; 71 | this.stream.on('data', data => { 72 | let finalData = data; 73 | const dataStr = finalData.toString(); 74 | finalData = Buffer(finalData); 75 | _this.onmessage(dataStr, finalData); 76 | }); 77 | } 78 | 79 | send(mssg, cb) { 80 | const data = new Buffer(mssg, 'binary'); 81 | this.send_raw(data, cb); 82 | } 83 | 84 | send_raw(data, cb) { 85 | const _this = this; 86 | this.stream.write(data, () => { 87 | if (cb) { 88 | _this.stream.drain(cb); 89 | } 90 | }); 91 | } 92 | 93 | send_cmd(cmd, cb) { 94 | const mssg = `\x1b\x1b${cmd}`; 95 | const data = new Buffer(mssg, 'binary'); 96 | this.send_raw(data, () => { 97 | cb(); 98 | }); 99 | } 100 | 101 | static isSerialPort(name, cb) { 102 | if ( 103 | name && 104 | (name.substr(0, 3) === 'COM' || 105 | name.indexOf('tty') > -1 || 106 | name.indexOf('/dev') > -1) 107 | ) { 108 | cb(true); 109 | } else { 110 | fs.access(name, fs.constants.F_OK, err => { 111 | if (err === true) { 112 | cb(true); 113 | } else { 114 | cb(false); 115 | } 116 | }); 117 | } 118 | } 119 | 120 | static listPycom(settings, cb) { 121 | const pycomList = []; 122 | const pycomManus = []; 123 | settings.refresh(); 124 | const comportManufacturers = 125 | settings.autoconnect_comport_manufacturers; 126 | PySerial.list(settings, (names, manus) => { 127 | for (let i = 0; i < names.length; i += 1) { 128 | const name = names[i]; 129 | const manu = manus[i]; 130 | if (comportManufacturers.indexOf(manu) > -1) { 131 | pycomList.push(name); 132 | pycomManus.push(manu); 133 | } 134 | } 135 | cb(pycomList, pycomManus); 136 | }); 137 | } 138 | 139 | static list(settings, cb) { 140 | const comportManufacturers = 141 | settings.autoconnect_comport_manufacturers; 142 | SerialPort.list().then(ports => { 143 | const portnames = []; 144 | const otherPortnames = []; 145 | const manufacturers = []; 146 | const otherManufacturers = []; 147 | ports.forEach((port, index, array) => { 148 | const name = port.path; 149 | let manu = ''; 150 | if (name) { 151 | if (name.indexOf('Bluetooth') === -1) { 152 | manu = port.manufacturer 153 | ? port.manufacturer 154 | : 'Unknown manufacturer'; 155 | const pycomManuIndex = comportManufacturers.indexOf(manu); 156 | if (pycomManuIndex > -1) { 157 | let j; 158 | for (j = 0; j < manufacturers.length; j += 1) { 159 | if ( 160 | pycomManuIndex < 161 | comportManufacturers.indexOf(manufacturers[j]) 162 | ) { 163 | break; 164 | } 165 | } 166 | portnames.splice(j, 0, name); 167 | manufacturers.splice(j, 0, manu); 168 | } 169 | } else { 170 | otherPortnames.push(name); 171 | otherManufacturers.push(manu); // push to top of array 172 | } 173 | } 174 | }); 175 | const result = portnames.concat(otherPortnames); 176 | const manus = manufacturers.concat(otherManufacturers); 177 | cb(result, manus); 178 | }); 179 | } 180 | 181 | sendPing(cb) { 182 | // not implemented 183 | if (this.dtr_supported) { 184 | this.stream.set({ dtr: true }, err => { 185 | if (cb) { 186 | cb(err); 187 | return !err; 188 | } 189 | return false; 190 | }); 191 | } else { 192 | cb(); 193 | return true; 194 | } 195 | return false; 196 | } 197 | 198 | flush(cb) { 199 | this.stream.flush(cb); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /lib/connections/pysocket.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | const { Socket } = require('net'); 4 | 5 | export default class PySocket { 6 | constructor(address, params) { 7 | this.type = 'socket'; 8 | this.stream = new Socket(); 9 | 10 | this.stream.setTimeout(params.timeout); 11 | this.connected = false; 12 | this.params = params; 13 | this.address = address; 14 | this.receive_buffer = ''; 15 | this.on_error_called = false; 16 | } 17 | 18 | connect(onconnect, onerror, ontimeout) { 19 | this.onconnect = onconnect; 20 | this.onerror = onerror; 21 | this.ontimeout = ontimeout; 22 | this.username_sent = false; 23 | this.password_sent = false; 24 | const _this = this; 25 | this.stream.connect(this.params.port, this.address); 26 | this.stream.on('connect', () => { 27 | onconnect(); 28 | }); 29 | this.stream.on('timeout', () => { 30 | ontimeout(); 31 | }); 32 | this.stream.on('error', error => { 33 | if (!_this.on_error_called) { 34 | _this.on_error_called = true; 35 | onerror(error); 36 | } 37 | }); 38 | this.stream.on('close', hadError => { 39 | if (hadError && !_this.on_error_called) { 40 | _this.on_error_called = true; 41 | onerror(); 42 | } 43 | }); 44 | this.stream.on('end', () => { 45 | if (!_this.on_error_called) { 46 | _this.on_error_called = true; 47 | } 48 | }); 49 | } 50 | 51 | disconnect(cb) { 52 | if (this.stream) { 53 | this.stream.destroy(); 54 | this.stream = null; 55 | } 56 | cb(); 57 | } 58 | 59 | registerListener(cb) { 60 | this.onmessage = cb; 61 | this.stream.on('data', data => { 62 | const raw = Buffer(data); 63 | cb(data, raw); 64 | }); 65 | } 66 | 67 | send(mssg, cb) { 68 | mssg = mssg.replace('\x1b', '\x1b\x1b'); 69 | const data = new Buffer(mssg, 'binary'); 70 | this.send_raw(data, cb); 71 | } 72 | 73 | send_raw(data, cb) { 74 | if (this.stream) { 75 | this.stream.write(data, () => { 76 | if (cb) cb(); 77 | }); 78 | } else { 79 | cb(new Error('Not connected')); 80 | } 81 | } 82 | 83 | send_cmd(cmd, cb) { 84 | const mssg = `\x1b\x1b${cmd}`; 85 | const data = new Buffer(mssg, 'binary'); 86 | this.send_raw(data, cb); 87 | } 88 | 89 | sendPing(cb) { 90 | if (cb) cb(null); 91 | return true; 92 | } 93 | 94 | flush(cb) { 95 | cb(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/connections/pytelnet.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import TelnetClient from './telnet/telnetcli'; 4 | 5 | const AYT = '\xff\xf6'; 6 | 7 | export default class PyTelnet { 8 | constructor(address, params) { 9 | this.type = 'telnet'; 10 | this.stream = new TelnetClient('pycomboard'); 11 | this.connected = false; 12 | this.listening = false; 13 | this.username_sent = false; 14 | this.password_sent = false; 15 | this.params = params; 16 | this.address = address; 17 | this.pingTimer = null; 18 | this.receive_buffer = ''; 19 | this.ayt_pending = false; 20 | } 21 | 22 | sendPing(cb) { 23 | if (this.ayt_pending) { 24 | cb(new Error('Ping failed')); 25 | } else { 26 | cb(null); 27 | } 28 | this.ayt_pending = true; 29 | this.send(AYT); 30 | return true; 31 | } 32 | 33 | connect(onconnect, onerror, ontimeout) { 34 | this.onconnect = onconnect; 35 | this.onerror = onerror; 36 | this.ontimeout = ontimeout; 37 | this.username_sent = false; 38 | this.password_sent = false; 39 | const _this = this; 40 | this.params.host = this.address; 41 | this.stream.connect(this.params, err => { 42 | onconnect(new Error(err)); 43 | }); 44 | this.stream.setReportErrorHandler((telnet, error) => { 45 | let finalError = error; 46 | if (onerror) { 47 | if (!finalError) { 48 | finalError = 'Connection lost'; 49 | } 50 | onerror(new Error(finalError)); 51 | } 52 | }); 53 | 54 | let timeoutTriggered = false; 55 | this.stream.setReportTimeoutHandler((telnet, error) => { 56 | if (ontimeout) { 57 | if (!timeoutTriggered) { 58 | timeoutTriggered = true; 59 | ontimeout(error); 60 | } 61 | } 62 | }); 63 | 64 | this.stream.setReportAYTHandler(() => { 65 | _this.ayt_pending = false; 66 | }); 67 | } 68 | 69 | disconnect(cb) { 70 | this.stream.close(); 71 | // give the connection time to close. 72 | // there is no proper callback for this in the telnet lib. 73 | setTimeout(cb, 200); 74 | } 75 | 76 | registerListener(cb) { 77 | this.onmessage = cb; 78 | 79 | this.stream.read((err, recv) => { 80 | if (recv) { 81 | const data = recv.join(''); 82 | const raw = Buffer(recv); 83 | cb(data, raw); 84 | } 85 | }); 86 | } 87 | 88 | send(mssg, cb) { 89 | const data = new Buffer(mssg, 'binary'); 90 | this.send_raw(data, cb); 91 | } 92 | 93 | send_raw(data, cb) { 94 | this.stream.write(data, () => { 95 | if (cb) cb(); 96 | }); 97 | } 98 | 99 | send_cmd(cmd, cb) { 100 | const mssg = `\x1b\x1b${cmd}`; 101 | const data = new Buffer(mssg, 'binary'); 102 | this.send_raw(data, cb); 103 | } 104 | 105 | flush(cb) { 106 | cb(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /lib/connections/telnet/format.js: -------------------------------------------------------------------------------- 1 | exports.error = (name, err) => { 2 | // console.error(name,' | ',err.toString()); // to use for debugging 3 | }; 4 | 5 | exports.log = (name, info) => { 6 | // console.log(name,' | ',info.toString()); // to use for debugging 7 | }; 8 | -------------------------------------------------------------------------------- /lib/features/run/runner.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import ApiWrapper from '../../wrappers/api-wrapper'; 4 | 5 | export default class Runner { 6 | constructor(pyboard, terminal, pymakr) { 7 | this.pyboard = pyboard; 8 | this.terminal = terminal; 9 | this.pymakr = pymakr; 10 | this.api = new ApiWrapper(); 11 | this.busy = false; 12 | } 13 | 14 | toggle(cb) { 15 | if (this.busy) { 16 | this.stop(cb); 17 | } else { 18 | this.start(cb); 19 | } 20 | } 21 | 22 | start(cb) { 23 | const _this = this; 24 | this._getCurrentFile((file, filename) => { 25 | _this.terminal.writeln(`Running ${filename}`); 26 | _this.busy = true; 27 | // _this.pymakr.view.setButtonState() 28 | _this.pyboard.run(file, () => { 29 | _this.busy = false; 30 | if (cb) cb(); 31 | }); 32 | }, (err) => { 33 | _this.terminal.writelnAndPrompt(err); 34 | }); 35 | } 36 | 37 | selection(codeblock, cb) { 38 | const _this = this; 39 | codeblock = this.__trimcodeblock(codeblock); 40 | _this.terminal.writeln('Running selected lines'); 41 | _this.busy = true; 42 | _this.pyboard.run(codeblock, () => { 43 | _this.busy = false; 44 | if (cb) cb(); 45 | }, (err) => { 46 | _this.terminal.writelnAndPrompt(err); 47 | }); 48 | } 49 | 50 | stop(cb) { 51 | const _this = this; 52 | if (this.busy) { 53 | this.pyboard.stopRunningProgramsNofollow(() => { 54 | _this.pyboard.flush(() => { 55 | _this.pyboard.enterFriendlyRepl(() => { 56 | }); 57 | _this.busy = false; 58 | if (cb) cb(); 59 | }); 60 | }); 61 | } 62 | } 63 | 64 | _getCurrentFile(cb, onerror) { 65 | this.api.getOpenFile((file, name) => { 66 | if (!file) { 67 | onerror('No file open to run'); 68 | return; 69 | } 70 | 71 | let filename = 'untitled file'; 72 | if (name) { 73 | filename = name.split('/').pop(-1); 74 | const filetype = filename.split('.').pop(-1); 75 | if (filetype.toLowerCase() !== 'py') { 76 | onerror(`Can't run ${filetype} files, please run only python files`); 77 | return; 78 | } 79 | } 80 | cb(file, filename); 81 | }, onerror); 82 | } 83 | 84 | // remove excessive identation 85 | __trimcodeblock(codeblock) { 86 | // regex to split both win and unix style 87 | const lines = codeblock.match(/[^\n]+(?:\r?\n|$)/g); 88 | // count leading spaces in line1 ( Only spaces, not TAB) 89 | let count = 0; 90 | if (lines) { 91 | while (lines[0].startsWith(' ', count)) { 92 | count++; 93 | } 94 | 95 | // remove from all lines 96 | if (count > 0) { 97 | const prefix = ' '.repeat(count); 98 | for (let i = 0; i < lines.length; i += 1) { 99 | if (lines[i].startsWith(prefix)) { 100 | lines[i] = lines[i].slice(count); 101 | } else { 102 | // funky identation or selection; just trim spaces and add warning 103 | lines[i] = `${lines[i].trim()} # <- IndentationError`; 104 | } 105 | } 106 | } 107 | // glue the lines back together 108 | return (lines.join('')); 109 | } 110 | return codeblock; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/features/snippets/snippets.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import ApiWrapper from '../../wrappers/api-wrapper'; 4 | import Utils from '../../helpers/utils'; 5 | import ConfigSnippets from '../../../snippets/index'; 6 | 7 | const fs = require('fs'); 8 | const slugify = require('slugify'); 9 | 10 | export default class Snippets { 11 | constructor(view, settings) { 12 | this.view = view; 13 | this.api = new ApiWrapper(); 14 | this.utils = new Utils(settings); 15 | this.arraylist = ConfigSnippets.defaults().files; 16 | this.hashlist = {}; 17 | this.custom_snippets_index = {}; 18 | this.package_path = this.api.getPackagePath(); 19 | this.project_path = this.api.getProjectPath(); 20 | this.snippets_path = `${this.package_path}/snippets/`; 21 | this.custom_snippets_path = `${this.api.getIDEPath()}/pymakr_snippets/`; 22 | this.custom_snippets_index_path = `${this.custom_snippets_path}index.json`; 23 | 24 | this.__prepareCustomSnippetsPath(); 25 | 26 | this.list(); 27 | 28 | const _this = this; 29 | this.view.on('snippet.copy', (id) => { 30 | _this.copy(id); 31 | }); 32 | 33 | this.view.on('snippet.create_file', (id, content) => { 34 | _this.create_file(id, content); 35 | }); 36 | 37 | this.view.on('snippet.insert', (id, content) => { 38 | _this.insert(id, content); 39 | }); 40 | 41 | this.view.on('snippet.add_new', (snippet) => { 42 | _this.create_new(snippet); 43 | }); 44 | } 45 | 46 | __prepareCustomSnippetsPath() { 47 | this.utils.ensureDirectoryExistence(this.custom_snippets_path); 48 | this.utils.ensureFileDirectoryExistence(this.custom_snippets_index_path); 49 | try { 50 | const snippets_index_content = fs.readFileSync(this.custom_snippets_index_path); 51 | this.custom_snippets_index = JSON.parse(snippets_index_content); 52 | } catch (e) { 53 | // no problem, index didn't exist yet, just initialse an empty one 54 | this.custom_snippets_index = []; 55 | } 56 | } 57 | 58 | __addToCustomSnippetsIndex(snippet) { 59 | this.custom_snippets_index.push(snippet); 60 | fs.writeFile(this.custom_snippets_index_path, JSON.stringify(this.custom_snippets_index)); 61 | } 62 | 63 | list() { 64 | // fixed snippets 65 | for (var i in this.arraylist) { 66 | var item = this.arraylist[i]; 67 | this.addToList(item, this.snippets_path); 68 | } 69 | 70 | // custom snippets 71 | for (var i in this.custom_snippets_index) { 72 | var item = this.custom_snippets_index[i]; 73 | this.addToList(item, this.custom_snippets_path); 74 | } 75 | 76 | return this.hashlist; 77 | } 78 | 79 | addToList(item, path) { 80 | item.filename = `${item.id}.py`; 81 | item.filepath = path + item.filename; 82 | item.code = fs.readFileSync(item.filepath); 83 | this.hashlist[item.id] = item; 84 | return item; 85 | } 86 | 87 | get(id) { 88 | return this.hashlist[id]; 89 | } 90 | 91 | copy(id) { 92 | this.api.writeToCipboard(this.hashlist[id].code); 93 | return true; 94 | } 95 | 96 | create_file(id, content) { 97 | const item = this.hashlist[id]; 98 | let filename = `${id}.py`; 99 | let filepath = `${this.project_path}/${filename}`; 100 | let i = 1; 101 | if (!content) { 102 | content = item.code; 103 | } 104 | while (fs.existsSync(filepath)) { 105 | filename = `${id}[${i}].py`; 106 | filepath = `${this.project_path}/${filename}`; 107 | i += 1; 108 | } 109 | fs.writeFile(filepath, content); 110 | atom.workspace.open(filepath); 111 | this.api.info(`Created snippet file ${filename} inside your project`); 112 | return fs.existsSync(filepath); 113 | } 114 | 115 | insert(id, content) { 116 | if (!content) { 117 | content = this.hashlist[id].code; 118 | } 119 | return this.api.insertInOpenFile(content); 120 | } 121 | 122 | create_new(snippet) { 123 | const id = slugify(snippet.name.toLowerCase()); 124 | snippet.id = id; 125 | snippet.custom = true; 126 | const filepath = `${this.custom_snippets_path + id}.py`; 127 | fs.writeFile(filepath, snippet.code); 128 | this.api.info(`Created new snippet ${id}.py `); 129 | 130 | this.__addToCustomSnippetsIndex(snippet); 131 | this.addToList(snippet, this.custom_snippets_path); 132 | this.view.emit('snippets.created_new', snippet); 133 | 134 | return fs.existsSync(filepath); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /lib/features/sync/sync-helper.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Logger from '../../helpers/logger'; 4 | import ApiWrapper from '../../wrappers/api-wrapper'; 5 | import Sync from './sync'; 6 | 7 | export default class SyncHelper { 8 | constructor(pymakr, pyboard, terminal, settings) { 9 | this.pymakr = pymakr; 10 | this.pyboard = pyboard; 11 | this.terminal = terminal; 12 | this.settings = settings; 13 | this.synchronizing = false; 14 | this.synchronize_type = ''; 15 | this.api = new ApiWrapper(settings); 16 | this.logger = new Logger('SyncHelper'); 17 | this.sync_worker = null; 18 | } 19 | 20 | uploadCurrentFile() { 21 | const _this = this; 22 | this.api.getOpenFile((contents, path) => { 23 | if (!path) { 24 | _this.api.warning('No file open to upload'); 25 | } else { 26 | _this.logger.info(path); 27 | _this.sync('send', path); 28 | } 29 | }); 30 | } 31 | 32 | upload(path) { 33 | this.projectPath = path; 34 | this.sync('send'); 35 | } 36 | 37 | download() { 38 | this.sync('receive'); 39 | } 40 | 41 | sync(type, files) { 42 | this.logger.info('Sync'); 43 | this.logger.info(type); 44 | 45 | const _this = this; 46 | if (!this.pyboard.connected) { 47 | this.terminal.writeln('Please connect your device'); 48 | return; 49 | } 50 | if (!this.synchronizing) { 51 | this.sync_worker = new Sync(this.pyboard, this.settings, this.terminal); 52 | this.synchronizing = true; 53 | this.synchronize_type = type; 54 | const cb = () => { 55 | _this.synchronizing = false; 56 | _this.logger.info('Synchronizing disabled, now setting buttons'); 57 | if (_this.pyboard.type !== 'serial') { 58 | _this.terminal.writeln('Waiting for reboot...'); 59 | setTimeout(() => { 60 | _this.connect(); 61 | }, 4000); 62 | } 63 | }; 64 | if (type === 'receive') { 65 | this.sync_worker.startReceive(cb); 66 | } else { 67 | this.sync_worker.start(cb, files); 68 | } 69 | } 70 | } 71 | 72 | stop(cb) { 73 | const _this = this; 74 | if (this.synchronizing) { 75 | this.sync_worker.stop(() => { 76 | _this.synchronizing = false; 77 | cb(); 78 | }); 79 | const type = this.synchronize_type === 'receive' ? 'download' : 'upload'; 80 | this.terminal.writeln(`Stopping ${type}....`); 81 | } 82 | } 83 | 84 | stopSilent() { 85 | this.sync_helper.stopSilent(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/helpers/logger.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Config from '../config'; 4 | 5 | const LOG_LEVEL = Config.constants().logging_level; 6 | const LEVELS = ['silly', 'verbose', 'info', 'warning', 'error', 'critical']; 7 | 8 | 9 | // Import this class and create a new logger object in the constructor, providing 10 | // the class name. Use the logger anywhere in the code 11 | // this.logger = new Logger('Pyboard') 12 | // this.logger.warning("Syncing to outdated firmware") 13 | // Result in the console will be: 14 | // [warning] Pyboard | Syncing to outdated firmware 15 | 16 | export default class Logger { 17 | constructor(classname) { 18 | this.classname = classname; 19 | } 20 | 21 | log(level, mssg) { 22 | if (level >= LOG_LEVEL) { 23 | console.log(`[${LEVELS[level]}] ${this.classname} | ${mssg}`); 24 | } 25 | } 26 | 27 | silly(mssg) { 28 | this.log(0, mssg); 29 | } 30 | 31 | verbose(mssg) { 32 | this.log(1, mssg); 33 | } 34 | 35 | info(mssg) { 36 | this.log(2, mssg); 37 | } 38 | 39 | warning(mssg) { 40 | this.log(3, mssg); 41 | } 42 | 43 | error(mssg) { 44 | this.log(4, mssg); 45 | } 46 | 47 | critical(mssg) { 48 | this.log(5, mssg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/helpers/utils.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | const path = require('path'); 4 | const rimraf = require('rimraf'); 5 | const slugify = require('slugify'); 6 | 7 | // Import this class and create a new logger object in the constructor, providing 8 | // the class name. Use the logger anywhere in the code 9 | // this.logger = new Logger('Pyboard') 10 | // this.logger.warning("Syncing to outdated firmware") 11 | // Result in the console will be: 12 | // [warning] Pyboard | Syncing to outdated firmware 13 | 14 | export default class Utils { 15 | constructor(settings) { 16 | this.settings = settings; 17 | 18 | // TODO: grab from a .pyignore file or setting 19 | this.allowed_file_types = this.settings.getAllowedFileTypes(); 20 | } 21 | 22 | // runs a worker recursively untill a task is Done 23 | // worker should take 2 params: value and a continuation callback 24 | // continuation callback takes 2 params: error and the processed value 25 | // calls 'end' whenever the processed_value comes back empty/null or when an error is thrown 26 | doRecursively(value, worker, end) { 27 | const _this = this; 28 | worker(value, (err, processedValue, done) => { 29 | if (err) { 30 | end(err); 31 | } else if (done) { 32 | end(null, processedValue); 33 | } else { 34 | setTimeout(() => { 35 | _this.doRecursively(processedValue, worker, end); 36 | }, 20); 37 | } 38 | }); 39 | } 40 | 41 | base64decode(b64str) { 42 | let content = ''; 43 | const bufferList = []; 44 | const b64strArr = b64str.split('='); 45 | 46 | for (let i = 0; i < b64strArr.length; i += 1) { 47 | let chunk = b64strArr[i]; 48 | if (chunk.length > 0) { 49 | // Add == to only the last chunk 50 | // Ignore last 2 items, becuase the original string contains '==' + some extra chars 51 | if (i === b64strArr.length - 3) { 52 | chunk += '=='; 53 | } else { 54 | chunk += '='; 55 | } 56 | const bc = Buffer.from(chunk, 'base64'); 57 | bufferList.push(bc); 58 | content += bc.toString(); 59 | } 60 | } 61 | return [content, bufferList]; 62 | } 63 | 64 | plural(text, number) { 65 | return text + (number === 1 ? '' : 's'); 66 | } 67 | 68 | parseError(content) { 69 | const errIndex = content.indexOf('OSError:'); 70 | if (errIndex > -1) { 71 | return Error(content.slice(errIndex, content.length - 2)); 72 | } 73 | return null; 74 | } 75 | 76 | slug(text) { 77 | return slugify(text); 78 | } 79 | 80 | ensureFileDirectoryExistence(filePath) { 81 | const dirname = path.dirname(filePath); 82 | return this.ensureDirectoryExistence(dirname); 83 | } 84 | 85 | ensureDirectoryExistence(dirname) { 86 | if (fs.existsSync(dirname)) { 87 | return true; 88 | } 89 | fs.mkdirSync(dirname); 90 | return false; 91 | } 92 | 93 | setIgnoreFilter() { 94 | const ignoreList = this.settings.py_ignore; 95 | const pyCompFolder = this.settings.config.compressed_files_folder; 96 | if (ignoreList.indexOf(pyCompFolder) === -1) { 97 | ignoreList.push(pyCompFolder); 98 | } 99 | return ignoreList; 100 | } 101 | 102 | ignoreFilter(fileList) { 103 | const newList = []; 104 | for (let i = 0; i < fileList.length; i += 1) { 105 | const file = fileList[i]; 106 | const filename = file.split('/').pop(); 107 | if ( 108 | file && 109 | file !== '' && 110 | file.length > 0 && 111 | file.substring(0, 1) !== '.' 112 | ) { 113 | if ( 114 | file.indexOf('.') === -1 || 115 | this.settings.sync_all_file_types || 116 | this.allowed_file_types.indexOf(file.split('.').pop()) > -1 117 | ) { 118 | if ( 119 | this.settings.py_ignore.indexOf(file) === -1 && 120 | this.settings.py_ignore.indexOf(filename) === -1 121 | ) { 122 | newList.push(file); 123 | } 124 | } 125 | } 126 | } 127 | return newList; 128 | } 129 | 130 | rmdir(pathDir, cb) { 131 | rimraf(pathDir, () => { 132 | cb(); 133 | }); 134 | } 135 | 136 | calculateIntVersion(version) { 137 | const knownTypes = ['a', 'b', 'rc', 'r']; 138 | if (!version) { 139 | return 0; 140 | } 141 | const versionParts = version.split('.'); 142 | const dots = versionParts.length - 1; 143 | if (dots === 2) { 144 | versionParts.push('0'); 145 | } 146 | 147 | for (let i = 0; i < knownTypes.length; i += 1) { 148 | const t = knownTypes[i]; 149 | if (versionParts[3] && versionParts[3].indexOf(t) > -1) { 150 | versionParts[3] = versionParts[3].replace(t, ''); 151 | } 152 | } 153 | 154 | let versionString = ''; 155 | 156 | for (let i = 0; i < versionParts.length; i += 1) { 157 | const val = versionParts[i]; 158 | if (parseInt(val, 10) < 10) { 159 | versionParts[i] = `0${val}`; 160 | } 161 | versionString += versionParts[i]; 162 | } 163 | return parseInt(versionString, 10); 164 | } 165 | 166 | fileWasNotExisting(exception) { 167 | const errorList = ['ENOENT', 'ENODEV', 'EINVAL', 'OSError:']; 168 | const stre = exception.message; 169 | for (let i = 0; i < errorList.length; i += 1) { 170 | if (stre.indexOf(errorList[i]) > -1) { 171 | return true; 172 | } 173 | } 174 | return false; 175 | } 176 | 177 | shortenComport(address) { 178 | const s = address.split('-'); 179 | return s[s.length - 1]; 180 | } 181 | 182 | int16(int) { 183 | const b = new Buffer(2); 184 | b.writeUInt16BE(int); 185 | return b; 186 | } 187 | 188 | int32(int) { 189 | const b = new Buffer(4); 190 | b.writeUInt32BE(int); 191 | return b; 192 | } 193 | 194 | isIP(address) { 195 | const r = RegExp( 196 | '^http[s]?://((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])', 197 | ); 198 | return r.test(address); 199 | } 200 | 201 | isString(x) { 202 | return Object.prototype.toString.call(x) === '[object String]'; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import { CompositeDisposable } from 'atom'; 4 | import Config from './config'; 5 | 6 | const $ = require('jquery'); 7 | 8 | export default { 9 | config: Config.settings(), 10 | 11 | activate(state) { 12 | try { 13 | require('serialport'); 14 | } catch (err) { 15 | if (err.code === 'MODULE_NOT_FOUND') { 16 | console.log('serialport not installed. Installing...'); 17 | require('child_process').execSync('npm install serialport', { cwd: __dirname + '/..' }); 18 | console.log('Installed serialport!'); 19 | } 20 | } 21 | 22 | const _this = this; 23 | this.prepareSerialPort(error => { 24 | if (error) { 25 | const err_mess = 26 | 'There was an error with your serialport module, Pymakr will likely not work properly. Please try to install again or report an issue on our github (see developer console for details)'; 27 | atom.notifications.addError(err_mess); 28 | 29 | console.log(err_mess); 30 | console.log(error); 31 | } 32 | 33 | const Pymakr = require('./pymakr'); 34 | const PanelView = require('./views/panel-view'); 35 | 36 | const SettingsWrapper = require('./wrappers/settings-wrapper'); 37 | 38 | _this.isDark = false; 39 | _this.buildStatusBarOnConsume = false; 40 | _this.settings = new SettingsWrapper(settings => { 41 | _this.view = new PanelView(settings, state.viewState, null); 42 | _this.view.addPanel(); 43 | _this.view.build(); 44 | _this.pymakr = new Pymakr( 45 | state.viewState, 46 | _this.view, 47 | settings, 48 | ); 49 | _this.buildStatusBar(); 50 | // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable 51 | _this.subscriptions = new CompositeDisposable(); 52 | // Register command that toggles this view 53 | _this.subscriptions.add( 54 | atom.commands.add('atom-workspace', { 55 | 'pymakr:sync': () => _this.pymakr.sync(), 56 | 'pymakr:upload': () => _this.pymakr.upload(), 57 | 'pymakr:upload File': () => _this.pymakr.uploadFile(), 58 | 'pymakr:toggle REPL': () => 59 | _this.pymakr.toggleVisibility(), 60 | 'pymakr:connect': () => _this.pymakr.connect(), 61 | 'pymakr:run': () => _this.pymakr.run(), 62 | 'pymakr:run Selection': () => _this.pymakr.runselection(), 63 | 'pymakr:help': () => _this.pymakr.writeHelpText(), 64 | 'pymakr:clear Terminal': () => 65 | _this.pymakr.clearTerminal(), 66 | 'pymakr:disconnect': () => _this.pymakr.disconnect(), 67 | }), 68 | ); 69 | }); 70 | }); 71 | }, 72 | 73 | buildStatusBar() { 74 | const _this = this; 75 | const div = $('
').addClass('pymakr-status-bar'); 76 | const svg = $('
').addClass('pymakr-logo'); 77 | svg.load( 78 | `${this.pymakr.api.getPackagePath()}/styles/assets/pycom-icon.svg`, 79 | ); 80 | const title = $('') 81 | .addClass('title') 82 | .html('Pymakr'); 83 | svg.css('color', 'red'); 84 | div.append(svg); 85 | div.append(title); 86 | div.click(() => { 87 | _this.pymakr.toggleVisibility(); 88 | }); 89 | 90 | if (this.statusBar) 91 | this.statusBar.addRightTile({ item: div, priority: 1 }); 92 | else this.buildStatusBarOnConsume = true; 93 | }, 94 | 95 | prepareSerialPort(cb) { 96 | try { 97 | require('serialport'); 98 | cb(); 99 | } catch (e) { 100 | console.log('Error while loading serialport library'); 101 | console.log(e); 102 | } 103 | }, 104 | 105 | consumeStatusBar(statusBar) { 106 | this.statusBar = statusBar; 107 | if (this.buildStatusBarOnConsume) { 108 | this.buildStatusBar(); 109 | } 110 | }, 111 | 112 | deactivate() { 113 | this.subscriptions.dispose(); 114 | this.pymakr.destroy(); 115 | }, 116 | 117 | serialize() { 118 | const ser = { 119 | viewState: null, 120 | feedbackPopupSeen: null, 121 | }; 122 | if (this.pymakr) { 123 | (ser.viewState = this.pymakr.serialize()), 124 | (ser.feedbackPopupSeen = this.pymakr.view.feedback_popup_seen); 125 | } 126 | return ser; 127 | }, 128 | }; 129 | -------------------------------------------------------------------------------- /lib/pybytes.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | const $ = require('jquery'); 4 | const fs = require('fs'); 5 | 6 | const rootElement = 7 | '
'; 8 | 9 | export default class Pybytes { 10 | constructor(api) { 11 | this.token = ''; 12 | this.isLoadingLogin = false; 13 | this.view = $(rootElement).html(); 14 | this.panel = null; 15 | this.api = api; 16 | this.staySignedIn = false; 17 | this.loginButton = $('#pybytes-login-button'); 18 | this.loginEmailInput = $('#pybytes-login-email'); 19 | this.loginPasswordInput = $('#pybytes-login-password'); 20 | this.loginPath = `${this.api.getPackageSrcPath()}/views/pybytes-panel.html`; 21 | this.homePath = `${this.api.getPackageSrcPath()}/views/pybytes-panel-home.html`; 22 | this.init(); 23 | } 24 | 25 | init(){ 26 | const absolutePath = this.api.getPackagePath(); 27 | const pybytesLogo = $('.pybytes-logo'); 28 | pybytesLogo 29 | .html('') 30 | .attr( 31 | 'src', 32 | `${absolutePath}/styles/assets/pybytes-logo.png`, 33 | ); 34 | } 35 | 36 | render() { 37 | let HTML = null; 38 | 39 | const plainHtml = fs.readFileSync( 40 | this.token ? this.homePath : this.loginPath, 41 | ); 42 | if ($('#pybytes-root').length) { 43 | HTML = $('#pybytes-root').html(plainHtml.toString()); 44 | } else HTML = $(rootElement).html(plainHtml.toString()); 45 | this.view = HTML; 46 | this.bindingEventsHome(); 47 | return HTML; 48 | } 49 | 50 | bindingEventsLogin() { 51 | this.loginButton = $('#pybytes-login-button'); 52 | this.loginEmailInput = $('#pybytes-login-email'); 53 | 54 | this.loginEmailInput.keydown(event => { 55 | if (event.key === 'Tab') { 56 | this.loginPasswordInput.focus(); 57 | } else if (event.key === 'Enter') { 58 | this.login(); 59 | } 60 | }); 61 | 62 | this.loginPasswordInput = $('#pybytes-login-password'); 63 | 64 | this.loginPasswordInput.keydown(event => { 65 | if (event.key === 'Tab') { 66 | this.loginEmailInput.focus(); 67 | } else if (event.key === 'Enter') { 68 | this.login(); 69 | } 70 | }); 71 | 72 | this.loginButton.on('click', async () => { 73 | this.login(); 74 | }); 75 | this.loginButton.keydown(event => { 76 | if (event.key === 'Enter') { 77 | this.login(); 78 | } 79 | }); 80 | this.closeButton = $('#pybytes-close'); 81 | this.closeButton.on('click', async () => { 82 | this.closePanel(); 83 | }); 84 | 85 | this.stayLabel = $('#pybytes-login-stay-label'); 86 | this.stayCb = $('#pybytes-login-stay-cb'); 87 | this.stayLabel.on('click', () => { 88 | this.staySignedIn = !this.staySignedIn; 89 | this.stayCb.prop('checked', this.staySignedIn); 90 | }); 91 | this.stayCb.on('click', () => { 92 | this.staySignedIn = !this.staySignedIn; 93 | this.stayCb.prop('checked', this.staySignedIn); 94 | }); 95 | } 96 | 97 | async login() { 98 | if (!this.isLoadingLogin) { 99 | await this.loginRequest( 100 | this.loginEmailInput.val(), 101 | this.loginPasswordInput.val(), 102 | ); 103 | } 104 | } 105 | 106 | bindingEventsHome() { 107 | this.homeLogoutLink = $('#pybytes-home-logout-link'); 108 | this.homeLogoutLink.on('click', async () => { 109 | this.token = null; 110 | localStorage.removeItem('session'); 111 | this.render(); 112 | this.bindingEventsLogin(); 113 | }); 114 | this.closeButton = $('#pybytes-close'); 115 | this.closeButton.on('click', async () => { 116 | this.closePanel(); 117 | }); 118 | $('#token').text(`Token: ${this.token}`); 119 | } 120 | 121 | togglePanel() { 122 | // eslint-disable-next-line no-undef 123 | if (atom.workspace.getRightPanels().length === 0) { 124 | if (!this.token) { 125 | const session = localStorage.getItem('session'); 126 | if (session) { 127 | const sessionObj = JSON.parse(session); 128 | const { token } = sessionObj; 129 | this.token = token; 130 | } 131 | } 132 | const view = this.render(); 133 | // eslint-disable-next-line no-undef 134 | const panel = atom.workspace.addRightPanel({ item: view }); 135 | this.pybytesPanel = panel; 136 | this.bindingEventsLogin(); 137 | this.bindingEventsHome(); 138 | this.init(); 139 | } else { 140 | this.pybytesPanel.destroy(); 141 | } 142 | } 143 | 144 | closePanel() { 145 | if (this.pybytesPanel) this.pybytesPanel.destroy(); 146 | } 147 | 148 | clearLoginInputs() { 149 | this.loginEmailInput.val(''); 150 | this.loginPasswordInput.val(''); 151 | } 152 | 153 | clearErrors() { 154 | $('#pybytes-login-email-error').text(''); 155 | $('#pybytes-login-password-error').text(''); 156 | } 157 | 158 | async loginRequest(email, password) { 159 | this.clearErrors(); 160 | if (!email || !password) { 161 | if (!email) 162 | $('#pybytes-login-email-error').text('Fill in your e-mail'); 163 | if (!password) 164 | $('#pybytes-login-password-error').text( 165 | 'Fill in your password', 166 | ); 167 | } else { 168 | this.isLoadingLogin = true; 169 | this.loginButton.toggleClass('disabled'); 170 | 171 | setTimeout(() => { 172 | this.loginButton.toggleClass('disabled'); 173 | this.isLoadingLogin = false; 174 | const token = 'EUSAEASJEASLK'; 175 | this.token = token; 176 | this.render(); 177 | if (this.staySignedIn) { 178 | localStorage.setItem('session', JSON.stringify({ token })); 179 | } 180 | }, 1500); 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /lib/views/action-view.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | 16 | 23 | 27 | 32 |
33 | -------------------------------------------------------------------------------- /lib/views/action-view.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import ApiWrapper from '../wrappers/api-wrapper'; 4 | import Logger from '../helpers/logger'; 5 | 6 | $ = require('jquery'); 7 | const EventEmitter = require('events'); 8 | 9 | fs = require('fs'); 10 | 11 | export default class ActionView extends EventEmitter { 12 | constructor(panelview, settings) { 13 | super(); 14 | this.panelview = panelview; 15 | this.settings = settings; 16 | this.visible = true; 17 | this.api = new ApiWrapper(); 18 | this.package_folder = this.api.getPackageSrcPath(); 19 | this.logger = new Logger('PanelView'); 20 | } 21 | 22 | build(rootElement) { 23 | const _this = this; 24 | 25 | const html = fs.readFileSync( 26 | `${_this.package_folder}/views/action-view.html`, 27 | ); 28 | rootElement.append(html.toString()); 29 | this.left_panel = $('#pymakr-left-panel'); 30 | this.connect = $('#pymakr-action-connect'); 31 | this.connect_sub = $('pymakr-action-connect .sub'); 32 | this.run = $('#pymakr-action-run'); 33 | this.run_sub = $('pymakr-action-run .sub'); 34 | this.upload = $('#pymakr-action-upload'); 35 | this.upload_sub = $('pymakr-action-upload .sub'); 36 | this.download = $('#pymakr-action-download'); 37 | this.download_sub = $('pymakr-action-download .sub'); 38 | this.info = $('#pymakr-action-info'); 39 | this.info_sub = $('pymakr-action-info .sub'); 40 | this.left_buttons = $('.left-button'); 41 | this.left_buttons.addClass('disabled'); 42 | this.runActionButton = $('#iab-run'); 43 | this.runActionDialog = $('#action-dialog-run'); 44 | 45 | const platform = process.platform; 46 | const tooltipOptions = title => ({ 47 | title, 48 | trigger: 'hover', 49 | delay: 0, 50 | placement: 'right', 51 | }); 52 | atom.tooltips.add( 53 | this.connect, 54 | tooltipOptions( 55 | `Connect/Disconnect ${ 56 | platform === 'darwin' ? '⌃⌥C' : 'ctrl+alt+c' 57 | } ${ 58 | platform === 'darwin' ? '⌃⌥D' : 'ctrl+alt+d' 59 | }`, 60 | ), 61 | ); 62 | atom.tooltips.add( 63 | this.run, 64 | tooltipOptions( 65 | `Run selected file ${ 66 | platform === 'darwin' ? '⌃⌥R' : 'ctrl+alt+r' 67 | }`, 68 | ), 69 | ); 70 | atom.tooltips.add( 71 | this.download, 72 | tooltipOptions('Download from device'), 73 | ); 74 | atom.tooltips.add( 75 | this.upload, 76 | tooltipOptions( 77 | `Upload project to device ${ 78 | platform === 'darwin' ? '⌃⌥S' : 'ctrl+alt+s' 79 | }`, 80 | ), 81 | ); 82 | atom.tooltips.add(this.info, tooltipOptions('Get device info')); 83 | this.bindOnClicks(); 84 | } 85 | 86 | enable() { 87 | this.left_buttons.removeClass('disabled'); 88 | } 89 | 90 | disable() { 91 | this.left_buttons.addClass('disabled'); 92 | // $('#pymakr-action-connect span.main').removeClass('toggle-off') 93 | } 94 | 95 | disableExceptConnectButton() { 96 | this.left_buttons.addClass('disabled'); 97 | $('#pymakr-action-connect').removeClass('disabled'); 98 | } 99 | 100 | update(connected, disableAll) { 101 | if (connected) { 102 | this.enable(); 103 | $('#pymakr-action-connect').removeClass('not-connected'); 104 | } else { 105 | if (disableAll && !connected) this.disable(); 106 | else this.disableExceptConnectButton(); 107 | $('#pymakr-action-connect').addClass('not-connected'); 108 | } 109 | $('#pymakr-action-connect span.main').attr( 110 | 'class', 111 | 'main fa fa-toggle-on', 112 | ); 113 | } 114 | 115 | bindOnClicks() { 116 | const _this = this; 117 | this.connect.click(e => { 118 | e.preventDefault(); 119 | 120 | if ( 121 | !_this.connect.hasClass('disabled') && 122 | !_this.connect.hasClass('no-devices') 123 | ) { 124 | _this.panelview.emit('connect.toggle'); 125 | if (this.panelview.selectedDevice) { 126 | this.panelview.selectedDevice.terminal.xterm.focus(); 127 | } 128 | } 129 | }); 130 | this.run.click(() => { 131 | $('.device-terminal.open').click(); 132 | if (!_this.run.hasClass('disabled')) { 133 | _this.panelview.emit('run'); 134 | if (_this.panelview.selectedDevice) { 135 | _this.panelview.selectedDevice.terminal.xterm.focus(); 136 | } 137 | } 138 | }); 139 | this.upload.click(() => { 140 | $('.device-terminal.open').click(); 141 | if (!_this.run.hasClass('disabled')) { 142 | _this.panelview.emit('sync'); 143 | if (_this.panelview.selectedDevice) { 144 | _this.panelview.selectedDevice.terminal.xterm.focus(); 145 | } 146 | } 147 | }); 148 | this.download.click(() => { 149 | $('.device-terminal.open').click(); 150 | if (!_this.run.hasClass('disabled')) { 151 | _this.panelview.emit('sync_receive'); 152 | if (_this.panelview.selectedDevice) { 153 | _this.panelview.selectedDevice.terminal.xterm.focus(); 154 | } 155 | } 156 | }); 157 | 158 | this.info.click(() => { 159 | $('.device-terminal.open').click(); 160 | if (!_this.run.hasClass('disabled')) { 161 | _this.panelview.emit('openInfo'); 162 | } 163 | }); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /lib/views/info-view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Close board info 4 |
5 |
6 |
7 |
Board Type
8 |
loading...
9 |
10 |
11 |
Firmware version
12 |
loading...
13 |
14 |
15 |
Mac Address
16 |
loading...
17 |
18 |
19 |
Wifi AP Name
20 |
loading...
21 |
22 |
23 |
Wifi IP
24 |
loading...
25 |
26 |
27 |
Wifi mode
28 |
loading...
29 |
30 |
31 |
LoRa ID
32 |
loading...
33 |
34 |
35 |
LTE Imei
36 |
TBI
37 |
38 |
39 | 40 | 70 | 71 | 87 |
88 | -------------------------------------------------------------------------------- /lib/views/info-view.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import ApiWrapper from '../wrappers/api-wrapper'; 4 | 5 | const EventEmitter = require('events'); 6 | fs = require('fs'); 7 | $ = require('jquery'); 8 | 9 | export default class InfoView extends EventEmitter { 10 | constructor(panelview, overlayview, settings) { 11 | super(); 12 | this.api = new ApiWrapper(settings); 13 | this.packageFolder = this.api.getPackageSrcPath(); 14 | this.panelview = panelview; 15 | this.overlayview = overlayview; 16 | this.settings = settings; 17 | this.packageFolder; 18 | } 19 | 20 | build(rootElement) { 21 | const _this = this; 22 | $(document).ready(() => { 23 | const snippetsHtml = fs.readFileSync( 24 | `${_this.packageFolder}/views/info-view.html`, 25 | ); 26 | rootElement.append(snippetsHtml.toString()); 27 | 28 | _this.info_content = $('#pymakr-info-view'); 29 | _this.info_close = $('#pymakr-info-close'); 30 | 31 | _this.info_close.click(async () => { 32 | if (_this.panelview.selectedDevice) { 33 | const { commands } = _this.panelview.selectedDevice; 34 | _this.panelview.closeOverlay(commands); 35 | _this.panelview.selectedDevice.terminal.xterm.focus(); 36 | } 37 | }); 38 | 39 | _this.bindClicks(); 40 | }); 41 | } 42 | 43 | bindClicks() { 44 | const _this = this; 45 | 46 | $('#info-view-wifiOnBoot input').change(event => { 47 | const { commands } = _this.panelview.selectedDevice; 48 | commands.prepare(() => { 49 | commands.setWifiOnBoot(event.currentTarget.checked, () => { 50 | commands.exit(() => {}); 51 | }); 52 | }); 53 | }); 54 | $('button#info-button-free-memory').click(() => { 55 | const { commands } = _this.panelview.selectedDevice; 56 | commands.prepare(() => { 57 | commands.formatFlash(() => { 58 | _this.panelview.selectedDevice.commands.getFreeMemory( 59 | result => { 60 | commands.exit(() => { 61 | _this.setContent({ freeMemory: result }); 62 | }); 63 | }, 64 | ); 65 | }); 66 | }); 67 | }); 68 | $('button#info-button-free-ram').click(async () => { 69 | const { commands } = _this.panelview.selectedDevice; 70 | await commands.prepareAsync(); 71 | const result = await commands.gcCollect(); 72 | await commands.exit(); 73 | this.setContent({ freeRam: result }); 74 | }); 75 | $('button#info-button-reboot').click(async () => { 76 | const { commands } = _this.panelview.selectedDevice; 77 | this.panelview.closeOverlay(); 78 | await commands.reset(); 79 | this.panelview.closeOverlay(); 80 | }); 81 | } 82 | 83 | setContent(info) { 84 | $(document).ready(() => { 85 | for (const key in info) { 86 | const val = info[key]; 87 | const el = $(`#info-view-${key}`); 88 | if (el.hasClass('radio')) { 89 | $(`input:radio[name=info-view-${key}-input]`).val([val]); 90 | // $('input:radio[name=info-view-fsType-input]').val([val]).trigger('change'); 91 | $(`#info-view-${key}-test`).html(val); 92 | } else if (el.hasClass('checkbox')) { 93 | $(`input:checkbox[name=info-view-${key}-input]`).attr( 94 | 'checked', 95 | val == 'True', 96 | ); 97 | } else { 98 | $(`#info-view-${key}`).html(val); 99 | } 100 | } 101 | }); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /lib/views/overlay-view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /lib/views/overlay-view.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import { Pane } from 'atom'; 4 | 5 | import Term from './terminal'; 6 | import Pyserial from '../connections/pyserial'; 7 | import ApiWrapper from '../wrappers/api-wrapper'; 8 | import Logger from '../helpers/logger'; 9 | import InfoView from './info-view'; 10 | 11 | $ = require('jquery'); 12 | const EventEmitter = require('events'); 13 | 14 | fs = require('fs'); 15 | 16 | export default class OverlayView extends EventEmitter { 17 | constructor(panelView, settings) { 18 | super(); 19 | const _this = this; 20 | this.panelview = panelView; 21 | this.settings = settings; 22 | this.api = new ApiWrapper(); 23 | this.package_folder = this.api.getPackageSrcPath(); 24 | this.infoView = new InfoView(panelView, this, settings); 25 | } 26 | 27 | open(info) { 28 | this.infoView.setContent(info); 29 | } 30 | 31 | openSnippet(s) { 32 | this.infoView.open(s); 33 | } 34 | 35 | closeOverlay() { 36 | _this.panelview.closeOverlay(); 37 | } 38 | 39 | build(rootElement) { 40 | const _this = this; 41 | 42 | const html = fs.readFileSync(`${_this.package_folder}/views/overlay-view.html`); 43 | rootElement.append(html.toString()); 44 | 45 | this.wrapper = $('#pymakr-overlay-wrapper'); 46 | this.close = $('#wrapper-close'); 47 | this.content_wrapper = $('#pymakr-overlay-content-wrapper'); 48 | this.infoView.build(this.content_wrapper); 49 | 50 | this.close.click(() => { 51 | _this.closeOverlay(); 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/views/panel-view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | x 4 |
5 | 6 |
7 |
8 | 18 | 19 | 45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 | 53 |
54 | 55 | 56 |
57 | 58 |
59 | 62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 | No terminal open. Use the 'Connect Device' button to open a 70 | device. 71 |
72 |
73 |
74 |
75 | -------------------------------------------------------------------------------- /lib/views/pybytes-panel-home.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | Pybytes Integration 7 | 8 | Logout 15 |
16 |
17 | -------------------------------------------------------------------------------- /lib/views/sidebar-view.html: -------------------------------------------------------------------------------- 1 |
2 | 41 | 55 | 78 |
79 | -------------------------------------------------------------------------------- /lib/views/sidebar-view.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import ApiWrapper from '../wrappers/api-wrapper'; 4 | import Logger from '../helpers/logger'; 5 | 6 | $ = require('jquery'); 7 | const EventEmitter = require('events'); 8 | 9 | fs = require('fs'); 10 | 11 | export default class SideBar extends EventEmitter { 12 | constructor(panelView, settings) { 13 | super(); 14 | this.panelView = panelView; 15 | this.settings = settings; 16 | this.visible = true; 17 | this.api = new ApiWrapper(); 18 | this.package_folder = this.api.getPackageSrcPath(); 19 | this.logger = new Logger('SideBar'); 20 | } 21 | 22 | build(rootElement) { 23 | const _this = this; 24 | 25 | const html = fs.readFileSync( 26 | `${_this.package_folder}/views/sidebar-view.html`, 27 | ); 28 | rootElement.append(html.toString()); 29 | 30 | this.connect = $('#pymakr-action-connect'); 31 | this.button_settings = $('#pymakr #settings'); 32 | this.button_settings_sub = $('#pymakr #settings .subnav'); 33 | this.settings_project_settings = $('#pymakr-project_settings'); 34 | this.settings_global_settings = $('#pymakr-global_settings'); 35 | this.settings_auto_connect = $('#pymakr-setting-autoconnect'); 36 | this.settings_auto_connect_checkbox = $( 37 | '#setting-autoconnect-value', 38 | ); 39 | 40 | $('#pybytes-logo').load( 41 | `${this.api.getPackagePath()}/styles/assets/pycom-icon.svg`, 42 | ); 43 | this.buttonPybytes = $('#pybytes'); 44 | const pybytesLabel = $('Pybytes'); 45 | this.buttonPybytes.addClass('badge-new'); 46 | this.buttonPybytes.append(pybytesLabel); 47 | 48 | this.bindOnClicks(); 49 | } 50 | 51 | bindOnClicks() { 52 | const _this = this; 53 | this.button_settings.click(() => { 54 | _this.panelView.emit('settings'); 55 | }); 56 | this.button_settings.on('blur', () => { 57 | _this.panelView.emit('settings_blur'); 58 | }); 59 | 60 | this.settings_global_settings.click(() => { 61 | _this.panelView.emit('global_settings'); 62 | _this.button_settings.removeClass('open'); 63 | }); 64 | 65 | this.settings_project_settings.click(() => { 66 | _this.panelView.emit('project_settings'); 67 | _this.button_settings.removeClass('open'); 68 | }); 69 | 70 | this.buttonPybytes.click(() => { 71 | this.buttonPybytes.removeClass('badge-new'); 72 | _this.panelView.emit('pybytes.toggle'); 73 | }); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/views/snippets-view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | All snippets + 4 |
5 |
    6 |
7 |
8 |
9 |
10 | Selected snippet: 11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /lib/views/snippets-view.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import { Pane } from 'atom'; 4 | 5 | import Term from './terminal'; 6 | import Pyserial from '../connections/pyserial'; 7 | import ApiWrapper from '../wrappers/api-wrapper'; 8 | import Logger from '../helpers/logger'; 9 | 10 | const EventEmitter = require('events'); 11 | const ElementResize = require('element-resize-detector'); 12 | fs = require('fs'); 13 | $ = require('jquery'); 14 | 15 | export default class SnippetsView extends EventEmitter { 16 | constructor(panelview, overlayview, settings) { 17 | super(); 18 | const _this = this; 19 | this.api = new ApiWrapper(settings); 20 | this.package_folder = this.api.getPackageSrcPath(); 21 | this.panelview = panelview; 22 | this.overlayview = overlayview; 23 | this.settings = settings; 24 | this.logger = new Logger('SnippetsView'); 25 | } 26 | 27 | build(rootElement) { 28 | const _this = this; 29 | $(document).ready(() => { 30 | const snippetsHtml = fs.readFileSync( 31 | `${_this.package_folder}/views/snippets-view.html`, 32 | ); 33 | rootElement.append(snippetsHtml.toString()); 34 | 35 | _this.list = $('#snippets-list'); 36 | _this.snippet_name = $('#snippet-name'); 37 | _this.content_right = $('#snippets-right'); 38 | _this.snippets_description = $('#snippets-description'); 39 | _this.button_insert = $('#snippets-button-insert'); 40 | _this.button_create = $('#snippets-button-create'); 41 | _this.button_new = $('#snippets-button-new'); 42 | _this.content_display_box = $('#snippets-display-box'); 43 | 44 | _this.plus = $('#snippets-plus'); 45 | 46 | _this.panelview.on('snippets.created_new', snippet => { 47 | _this.addSnippetToList(snippet); 48 | _this.open(snippet); 49 | }); 50 | 51 | _this.button_insert.on('click', () => { 52 | if (_this.selected_snippet) { 53 | _this.panelview.emit( 54 | 'snippet.insert', 55 | _this.selected_snippet.id, 56 | _this.getInputBoxContent(), 57 | ); 58 | } 59 | }); 60 | 61 | _this.button_create.on('click', () => { 62 | if (_this.selected_snippet) { 63 | _this.panelview.emit( 64 | 'snippet.create_file', 65 | _this.selected_snippet.id, 66 | _this.getInputBoxContent(), 67 | ); 68 | } 69 | }); 70 | 71 | _this.button_new.on('click', () => { 72 | if (_this.new_snippet) { 73 | _this.addNewSnippet(); 74 | } 75 | }); 76 | 77 | _this.plus.on('click', () => { 78 | _this.displayAddBox(); 79 | }); 80 | }); 81 | } 82 | 83 | setContent(list) { 84 | const _this = this; 85 | 86 | this.list.html(''); 87 | for (const i in list) { 88 | const item = list[i]; 89 | this.addSnippetToList(item); 90 | } 91 | this.list.append( 92 | '', 93 | ); 94 | } 95 | 96 | getInputBoxContent() { 97 | return this.content_display_box.val(); 98 | } 99 | 100 | addSnippetToList(item) { 101 | const _this = this; 102 | // build list item 103 | const liEl = document.createElement('li'); 104 | liEl.innerHTML = item.name; 105 | if (item.custom) { 106 | liEl.innerHTML += ' (custom)'; 107 | } 108 | liEl.id = item.id; 109 | liEl.onclick = el => { 110 | _this.panelview.emit('snippets.open', el.srcElement.id); 111 | }; 112 | this.list.append(liEl); 113 | } 114 | 115 | open(snippet) { 116 | this.snippet_name.html(snippet.name); 117 | this.snippets_description.html(snippet.description); 118 | this.selected_snippet = snippet; 119 | this.content_display_box.val(snippet.code.toString()); 120 | } 121 | 122 | displayAddBox() { 123 | this.new_snippet = { 124 | name: '', 125 | description: 'Custom snippet', 126 | id: '', 127 | }; 128 | $('#add-snippet').removeClass('hidden'); 129 | $('#snippets-button-new').removeClass('hidden'); 130 | this.selected_snippet = null; 131 | this.snippet_name.html('New snippet'); 132 | this.snippets_description.html(''); 133 | this.content_display_box.val(''); 134 | } 135 | 136 | addNewSnippet() { 137 | this.new_snippet.name = $('#add-snippet input').val(); 138 | this.new_snippet.code = this.getInputBoxContent(); 139 | this.panelview.emit('snippet.add_new', this.new_snippet); 140 | $('#add-snippet').addClass('hidden'); 141 | $('#snippets-button-new').addClass('hidden'); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /lib/views/terminal.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | // let Terminal = require('xterm') 4 | import { Terminal } from 'xterm'; 5 | import { FitAddon } from 'xterm-addon-fit'; 6 | import Logger from '../helpers/logger'; 7 | import Config from '../config'; 8 | import ApiWrapper from '../wrappers/api-wrapper'; 9 | 10 | export default class Term { 11 | constructor(cb, element, pyboard) { 12 | this.shellprompt = '>>> '; 13 | this.element = element; // get original dom element from jquery element 14 | this.element_original = element[0]; // get original dom element from jquery element 15 | this.pyboard = pyboard; 16 | this.logger = new Logger('Term'); 17 | this.api = new ApiWrapper(); 18 | this.onMessage = function() {}; 19 | this.term_rows = Config.constants().term_rows; 20 | this.lastWrite = ''; 21 | const fontSize = atom.config.get('pymakr.font_size'); 22 | this.fontSize = parseInt(fontSize); 23 | this.lastRows = this.term_rows.default; 24 | this.startY = null; 25 | const _this = this; 26 | this.fit = new FitAddon(); 27 | this.xterm = new Terminal({ 28 | cursorBlink: true, 29 | fontSize: fontSize || 14, 30 | rows: this.term_rows.default, 31 | cols: 120, 32 | rendererType: 'dom', 33 | scrollback: this.api.config('scrollback') 34 | }); 35 | this.xterm.loadAddon(this.fit); 36 | // for copy-paste with cmd key 37 | this.element.on('keydown', e => { 38 | if (_this.isActionKey(e)) { 39 | _this.termKeyPress('', e); 40 | } 41 | }); 42 | this.xterm.onKey(e => { 43 | _this.termKeyPress(e.key, e.domEvent); 44 | }); 45 | this.xterm.open(this.element_original); 46 | this.fit.fit(); 47 | 48 | atom.config.observe('pymakr.font_size', newValue => { 49 | const MINIMUM_FONT_SIZE = 10; 50 | const MAXIMUM_FONT_SIZE = 50; 51 | const DEFAULT_FONT_SIZE = 14; 52 | try { 53 | let newFontSize = newValue || DEFAULT_FONT_SIZE; 54 | if (newValue > MAXIMUM_FONT_SIZE) 55 | newFontSize = MAXIMUM_FONT_SIZE; 56 | else if (newValue < MINIMUM_FONT_SIZE) 57 | newFontSize = MINIMUM_FONT_SIZE; 58 | _this.fontSize = parseInt(newFontSize); 59 | _this.xterm.setOption('fontSize', _this.fontSize); 60 | _this.fit.fit(); 61 | } catch (e) { 62 | atom.notifications.addError('Invalid font size.'); 63 | atom.config.set(`pymakr.font_size`, DEFAULT_FONT_SIZE); 64 | } 65 | }); 66 | } 67 | 68 | setRows(pixels, rows) { 69 | this.xterm.resize(120, rows); 70 | this.element.height(`${pixels}px`); 71 | } 72 | 73 | getHeight() { 74 | return parseInt(this.element.height(), 10); 75 | } 76 | 77 | setHeight(height, rows) { 78 | this.last_height = this.element_original.style.height; 79 | this.element_original.style.height = `${height}px`; 80 | const fontMeasurement = $('.font-size-measurement'); 81 | fontMeasurement.css('font-size', `${this.fontSize}px`); 82 | const terminalWidth = $('#pymakr').innerWidth(); 83 | const sidebarWidth = $('#pymakr-left-panel').width(); 84 | const availableWidth = terminalWidth - sidebarWidth; 85 | const newColumns = Math.floor( 86 | availableWidth / fontMeasurement.width() - 5, 87 | ); 88 | this.xterm.resize(newColumns, rows); 89 | } 90 | 91 | resetHeight() { 92 | this.element_original.style.height = `${this.last_height}px`; 93 | // this.wrapper_element.style.height = 42 + this.last_height + "px" 94 | this.xterm.resize(120, this.lastRows); 95 | } 96 | 97 | setOnMessageListener(cb) { 98 | this.onMessage = cb; 99 | } 100 | 101 | isActionKey(e) { 102 | return ( 103 | (e.keyCode == 67 || e.keyCode == 86 || e.keyCode == 82) && 104 | (e.ctrlKey || e.metaKey) 105 | ); 106 | } 107 | 108 | termKeyPress(key, e) { 109 | if (this.isActionKey(e)) { 110 | if (e.keyCode === 67) { 111 | // ctrl-c 112 | this.copy(); 113 | } 114 | if (e.keyCode === 82) { 115 | // ctrl-r 116 | this.clear(); 117 | } 118 | } 119 | if (this.pyboard.connected) { 120 | if (e.keyCode === 86 && this.isActionKey(e)) { 121 | // ctrl-v 122 | this.paste(e); 123 | } 124 | this.logger.silly(e.keyCode); 125 | this.userInput(key); 126 | } 127 | } 128 | 129 | writeln(msg) { 130 | this.xterm.writeln(msg); 131 | this.lastWrite += msg; 132 | if (this.lastWrite.length > 20) { 133 | this.lastWrite = this.lastWrite.substring(1); 134 | } 135 | } 136 | 137 | write(msg) { 138 | this.xterm.write(msg); 139 | this.lastWrite += msg; 140 | if (this.lastWrite.length > 20) { 141 | this.lastWrite = this.lastWrite.substring(1); 142 | } 143 | } 144 | 145 | writelnAndPrompt(msg) { 146 | this.writeln(`${msg}\r\n`); 147 | this.writePrompt(); 148 | } 149 | 150 | writePrompt() { 151 | this.write(this.shellprompt); 152 | } 153 | 154 | enter() { 155 | this.write('\r\n'); 156 | } 157 | 158 | clear() { 159 | this.xterm.clear(); 160 | this.lastWrite = ''; 161 | } 162 | 163 | userInput(input) { 164 | this.onMessage(input); 165 | } 166 | 167 | paste() { 168 | const content = this.api.clipboard().replace(/\n/g, '\r'); 169 | this.userInput(content); 170 | } 171 | 172 | copy() { 173 | const selection = this.xterm.getSelection().toString(); 174 | if (selection.length > 0) { 175 | this.logger.silly( 176 | `Copied content to clipboard of length ${selection.length}`, 177 | ); 178 | this.api.writeClipboard(selection); 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /menus/pycom-sync.json: -------------------------------------------------------------------------------- 1 | { 2 | "context-menu": { 3 | "atom-text-editor": [ 4 | { 5 | "label": "Pymakr", 6 | "submenu": [ 7 | { 8 | "label": "Toggle Pycom Console", 9 | "command": "pymakr:toggle REPL" 10 | }, 11 | { 12 | "label": "Run current file", 13 | "command": "pymakr:run" 14 | } 15 | ] 16 | } 17 | ] 18 | }, 19 | "menu": [ 20 | { 21 | "label": "Packages", 22 | "submenu": [ 23 | { 24 | "label": "Pymakr", 25 | "submenu": [ 26 | { 27 | "label": "Toggle Pycom Console", 28 | "command": "pymakr:toggle REPL" 29 | }, 30 | { 31 | "label": "Run current file", 32 | "command": "pymakr:run" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-darwin-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v69-darwin-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-darwin-x64/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-darwin-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 4.2.7 7 | platform : darwin 8 | arch : x64 9 | abi : 69 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-linux-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v69-linux-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-linux-ia32/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-linux-ia32/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 4.2.7 7 | platform : linux 8 | arch : ia32 9 | abi : 69 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-linux-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v69-linux-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-linux-x64/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-linux-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 4.2.7 7 | platform : linux 8 | arch : x64 9 | abi : 69 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-win32-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v69-win32-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-win32-ia32/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-win32-ia32/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 4.2.7 7 | platform : win32 8 | arch : ia32 9 | abi : 69 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-win32-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v69-win32-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-win32-x64/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v69-win32-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 4.2.7 7 | platform : win32 8 | arch : x64 9 | abi : 69 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-darwin-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v70-darwin-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-darwin-x64/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-darwin-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 5.0.13 7 | platform : darwin 8 | arch : x64 9 | abi : 70 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-linux-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v70-linux-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-linux-ia32/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "build_v8_with_gn": "false", 13 | "coverage": "false", 14 | "debug_nghttp2": "false", 15 | "enable_lto": "false", 16 | "enable_pgo_generate": "false", 17 | "enable_pgo_use": "false", 18 | "force_dynamic_crt": 0, 19 | "host_arch": "x64", 20 | "icu_gyp_path": "tools/icu/icu-system.gyp", 21 | "icu_small": "false", 22 | "icu_ver_major": "64", 23 | "is_debug": 0, 24 | "llvm_version": "0.0", 25 | "napi_build_version": "5", 26 | "node_byteorder": "little", 27 | "node_code_cache": "yes", 28 | "node_debug_lib": "false", 29 | "node_enable_d8": "false", 30 | "node_install_npm": "false", 31 | "node_module_version": 79, 32 | "node_no_browser_globals": "false", 33 | "node_prefix": "/usr/local/Cellar/node/13.2.0", 34 | "node_release_urlbase": "", 35 | "node_report": "true", 36 | "node_shared": "false", 37 | "node_shared_cares": "false", 38 | "node_shared_http_parser": "false", 39 | "node_shared_libuv": "false", 40 | "node_shared_nghttp2": "false", 41 | "node_shared_openssl": "false", 42 | "node_shared_zlib": "false", 43 | "node_tag": "", 44 | "node_target_type": "executable", 45 | "node_use_bundled_v8": "true", 46 | "node_use_dtrace": "true", 47 | "node_use_etw": "false", 48 | "node_use_large_pages": "false", 49 | "node_use_large_pages_script_lld": "false", 50 | "node_use_node_snapshot": "true", 51 | "node_use_openssl": "true", 52 | "node_use_v8_platform": "true", 53 | "node_with_ltcg": "false", 54 | "node_without_node_options": "false", 55 | "openssl_fips": "", 56 | "openssl_is_fips": "false", 57 | "shlib_suffix": "79.dylib", 58 | "target_arch": "x64", 59 | "v8_enable_gdbjit": 0, 60 | "v8_enable_i18n_support": 1, 61 | "v8_enable_inspector": 1, 62 | "v8_no_strict_aliasing": 1, 63 | "v8_optimized_debug": 1, 64 | "v8_promise_internal_field_count": 1, 65 | "v8_random_seed": 0, 66 | "v8_trace_maps": 0, 67 | "v8_use_siphash": 1, 68 | "want_separate_host_toolset": 0, 69 | "xcode_version": "11.0", 70 | "nodedir": "/Users/pk/Library/Caches/node-gyp/13.2.0", 71 | "standalone_static_library": 1, 72 | "dry_run": "", 73 | "legacy_bundling": "", 74 | "save_dev": "", 75 | "commit_hooks": "true", 76 | "viewer": "man", 77 | "browser": "", 78 | "only": "", 79 | "also": "", 80 | "rollback": "true", 81 | "sign_git_commit": "", 82 | "audit": "true", 83 | "usage": "", 84 | "globalignorefile": "/usr/local/etc/npmignore", 85 | "shell": "/bin/zsh", 86 | "maxsockets": "50", 87 | "init_author_url": "", 88 | "shrinkwrap": "true", 89 | "metrics_registry": "https://registry.npmjs.org/", 90 | "parseable": "", 91 | "init_license": "ISC", 92 | "timing": "", 93 | "if_present": "", 94 | "cache_max": "Infinity", 95 | "init_author_email": "", 96 | "sign_git_tag": "", 97 | "git_tag_version": "true", 98 | "cert": "", 99 | "local_address": "", 100 | "long": "", 101 | "preid": "", 102 | "registry": "https://registry.npmjs.org/", 103 | "fetch_retries": "2", 104 | "noproxy": "", 105 | "message": "%s", 106 | "key": "", 107 | "versions": "", 108 | "globalconfig": "/usr/local/etc/npmrc", 109 | "logs_max": "10", 110 | "always_auth": "", 111 | "prefer_online": "", 112 | "dirPacker": "", 113 | "npm_session": "e2cfbaeacd679d22", 114 | "cache_lock_retries": "10", 115 | "global_style": "", 116 | "update_notifier": "true", 117 | "audit_level": "low", 118 | "heading": "npm", 119 | "searchlimit": "20", 120 | "fetch_retry_mintimeout": "10000", 121 | "offline": "", 122 | "read_only": "", 123 | "access": "", 124 | "json": "", 125 | "npmVersion": "6.13.1", 126 | "allow_same_version": "", 127 | "description": "true", 128 | "engine_strict": "", 129 | "https_proxy": "", 130 | "dmode": "493", 131 | "init_module": "/Users/pk/.npm-init.js", 132 | "userconfig": "/Users/pk/.npmrc", 133 | "cidr": "", 134 | "node_version": "13.2.0", 135 | "user": "", 136 | "refer": "ci", 137 | "auth_type": "legacy", 138 | "save": "true", 139 | "editor": "vi", 140 | "ignore_prepublish": "", 141 | "tag": "latest", 142 | "script_shell": "", 143 | "includeDeprecated": "", 144 | "progress": "true", 145 | "before": "", 146 | "global": "", 147 | "log": "", 148 | "optional": "true", 149 | "searchstaleness": "900", 150 | "ham_it_up": "", 151 | "bin_links": "true", 152 | "force": "", 153 | "save_prod": "", 154 | "searchopts": "", 155 | "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 156 | "depth": "Infinity", 157 | "sso_poll_frequency": "500", 158 | "rebuild_bundle": "true", 159 | "unicode": "true", 160 | "hashAlgorithm": "sha1", 161 | "fetch_retry_maxtimeout": "60000", 162 | "scripts_prepend_node_path": "warn-only", 163 | "strict_ssl": "true", 164 | "sso_type": "oauth", 165 | "save_prefix": "^", 166 | "tag_version_prefix": "v", 167 | "ca": "", 168 | "group": "20", 169 | "fetch_retry_factor": "10", 170 | "dev": "", 171 | "save_exact": "", 172 | "cache_lock_stale": "60000", 173 | "prefer_offline": "", 174 | "version": "", 175 | "cache_min": "10", 176 | "otp": "", 177 | "cache": "/Users/pk/.npm", 178 | "searchexclude": "", 179 | "color": "true", 180 | "package_lock": "true", 181 | "fund": "true", 182 | "package_lock_only": "", 183 | "project_scope": "", 184 | "save_optional": "", 185 | "user_agent": "npm/6.13.1 node/v13.2.0 darwin x64", 186 | "ignore_scripts": "", 187 | "cache_lock_wait": "10000", 188 | "production": "", 189 | "save_bundle": "", 190 | "send_metrics": "", 191 | "umask": "0022", 192 | "init_version": "1.0.0", 193 | "node_options": "", 194 | "scope": "", 195 | "git": "git", 196 | "init_author_name": "", 197 | "fmode": "420", 198 | "tmp": "/var/folders/_y/1nln5cw151708jp_7r_y84kr0000gn/T", 199 | "unsafe_perm": "true", 200 | "onload_script": "", 201 | "format_package_lock": "true", 202 | "prefix": "/usr/local", 203 | "link": "" 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-linux-ia32/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 5.0.13 7 | platform : linux 8 | arch : ia32 9 | abi : 70 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-linux-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v70-linux-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-linux-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 5.0.13 7 | platform : linux 8 | arch : x64 9 | abi : 70 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-win32-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v70-win32-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-win32-ia32/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 5.0.13 7 | platform : win32 8 | arch : ia32 9 | abi : 70 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-win32-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v70-win32-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v70-win32-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 5.0.13 7 | platform : win32 8 | arch : x64 9 | abi : 70 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-darwin-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v73-darwin-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-darwin-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 6.1.12 7 | platform : darwin 8 | arch : x64 9 | abi : 73 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-linux-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v73-linux-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-linux-ia32/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 6.1.12 7 | platform : linux 8 | arch : ia32 9 | abi : 73 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-linux-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v73-linux-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-linux-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 6.1.12 7 | platform : linux 8 | arch : x64 9 | abi : 73 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-win32-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v73-win32-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-win32-ia32/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 6.1.12 7 | platform : win32 8 | arch : ia32 9 | abi : 73 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-win32-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v73-win32-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v73-win32-x64/origin.md: -------------------------------------------------------------------------------- 1 | # Native module binding 2 | @serialport/bindings@8.0.4 3 | 4 | # Target 5 | runtime : electron 6 | version : 6.1.12 7 | platform : win32 8 | arch : x64 9 | abi : 73 10 | -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v80-darwin-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v80-darwin-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v80-linux-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v80-linux-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v80-win32-ia32/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v80-win32-ia32/bindings.node -------------------------------------------------------------------------------- /native_modules/@serialport/bindings/lib/binding/node-v80-win32-x64/bindings.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/native_modules/@serialport/bindings/lib/binding/node-v80-win32-x64/bindings.node -------------------------------------------------------------------------------- /native_modules/included_runtimes.md: -------------------------------------------------------------------------------- 1 | Includes support for electron/node versions: 2 | * electron 4.2.7 uses ABI 69 3 | - win32 , x64 4 | - win32 , ia32 5 | - darwin , x64 6 | - linux , x64 7 | - linux , ia32 8 | Includes support for electron/node versions: 9 | * electron 4.2.7 uses ABI 69 10 | - win32 , x64 11 | - win32 , ia32 12 | - darwin , x64 13 | - linux , x64 14 | - linux , ia32 15 | Includes support for electron/node versions: 16 | * electron 4.2.7 uses ABI 69 17 | - win32 , x64 18 | - win32 , ia32 19 | - darwin , x64 20 | - linux , x64 21 | - linux , ia32 22 | Includes support for electron/node versions: 23 | * electron 4.2.7 uses ABI 69 24 | - win32 , x64 25 | - win32 , ia32 26 | - darwin , x64 27 | - linux , x64 28 | - linux , ia32 29 | * electron 5.0.13 uses ABI 70 30 | - win32 , x64 31 | - win32 , ia32 32 | - darwin , x64 33 | - linux , x64 34 | - linux , ia32 35 | Includes support for electron/node versions: 36 | * electron 6.1.12 uses ABI 73 37 | - win32 , x64 38 | - win32 , ia32 39 | - darwin , x64 40 | - linux , x64 41 | - linux , ia32 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pymakr", 3 | "main": "./lib/main.js", 4 | "version": "2.3.7", 5 | "description": "Adds a REPL console to Atom that connects to your Pycom board. It can run code on the board or synchronize your project files to it.", 6 | "keywords": [ 7 | "Pycom", 8 | "Pymakr", 9 | "MicroPython", 10 | "WiPy", 11 | "Wipy2", 12 | "LoPy", 13 | "SiPy", 14 | "FiPy" 15 | ], 16 | "repository": "https://github.com/pycom/pymakr-atom", 17 | "license": "GPL-3.0", 18 | "engines": { 19 | "atom": ">=1.41.0" 20 | }, 21 | "dependencies": { 22 | "binascii": "0.0.2", 23 | "bindings": "^1.5.0", 24 | "bluebird": "^3.7.2", 25 | "commander": "^2.13.0", 26 | "crypto": "^1.0.1", 27 | "debug": "^4.1.0", 28 | "draggabilly": "2.2.0", 29 | "electron-rebuild": "^1.8.5", 30 | "element-resize-detector": "^1.1.14", 31 | "font-awesome": "^4.7.0", 32 | "jquery": "^3.4.0", 33 | "lie": "^3.1.0", 34 | "nan": "^2.9.2", 35 | "ncp": "^2.0.0", 36 | "node-abi": "^2.19.3", 37 | "object.assign": "^4.0.3", 38 | "parser-byte-length": "^1.0.2", 39 | "parser-cctalk": "^1.0.2", 40 | "parser-delimiter": "^1.0.2", 41 | "parser-readline": "^1.0.2", 42 | "parser-ready": "^1.0.2", 43 | "parser-regex": "^1.0.2", 44 | "prebuild-install": "^5.2.1", 45 | "prettysize": "^2.0.0", 46 | "promirepl": "^1.0.1", 47 | "prompt-list": "^3.1.2", 48 | "request": "^2.88.0", 49 | "rimraf": "^2.6.2", 50 | "safe-buffer": "^5.0.1", 51 | "slugify": "^1.3.4", 52 | "tar": ">=2.2.2", 53 | "telnet-client": "^0.16.1", 54 | "utf8": "^3.0.0", 55 | "xterm": "4.4.0", 56 | "xterm-addon-fit": "0.3.0" 57 | }, 58 | "scripts": { 59 | "watch": "onchange '**/*.js' '**/*.html' '**/*.less' -- sh scripts/restart-atom.sh", 60 | "test-electron": "pwsh -nop -f ./test-electron/runtest.ps1", 61 | "download-native": "node scripts/download-binaries.js", 62 | "semantic-release": "semantic-release" 63 | }, 64 | "consumedServices": { 65 | "status-bar": { 66 | "versions": { 67 | "^1.0.0": "consumeStatusBar" 68 | } 69 | } 70 | }, 71 | "release": { 72 | "extends": "@semantic-release/apm-config" 73 | }, 74 | "devDependencies": { 75 | "@actions/core": "^1.2.0", 76 | "@actions/github": "^1.1.0", 77 | "@semantic-release/apm-config": "^9.0.1", 78 | "axios": "^0.19.0", 79 | "eslint": "^6.7.2", 80 | "eslint-config-airbnb": "^18.0.1", 81 | "eslint-config-airbnb-base": "^14.0.0", 82 | "eslint-config-prettier": "^6.7.0", 83 | "eslint-plugin-import": "^2.19.1", 84 | "fs-extra": "^10.0.0", 85 | "git-tags": "^0.2.4", 86 | "node-powershell": "^4.0.0", 87 | "npm-watch": "^0.6.0", 88 | "onchange": "^6.1.0", 89 | "prettier": "^1.19.1", 90 | "semantic-release": "^18.0.1" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /scripts/atom-versions-fetcher.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Atom Elektron Version Checker v1.0 3 | 4 | ATOM_FOLDER="${PWD}/atom" 5 | 6 | if [ -d ${ATOM_FOLDER} ]; then 7 | echo "Atom repository found. Performing a pull..." 8 | cd atom 9 | git checkout master 10 | git pull 11 | else 12 | echo "${ATOM_FOLDER} repository not found" 13 | git clone https://github.com/atom/atom.git atom 14 | cd atom 15 | fi 16 | 17 | echo "" 18 | echo "Found significant branches:" 19 | echo "" 20 | 21 | declare -a ARRAY=(0) 22 | declare -a BRANCHES=(0) 23 | 24 | for BRANCH in $(git branch -a | grep remotes/origin/*); do 25 | TREATED_BRANCH_NAME="$(cut -d'/' -f3 <<<"$BRANCH")" 26 | WITHOUT_REMOTE_ORIGIN=${TREATED_BRANCH_NAME%remotes/origin/*} 27 | BRANCHES+=("${WITHOUT_REMOTE_ORIGIN}") 28 | done 29 | 30 | LATEST_VERSION_BRANCH_NAME="" 31 | LATEST_VERSION_NUMBER="" 32 | 33 | for BRANCH in "${BRANCHES[@]}"; do 34 | if [[ ${BRANCH:0:1} =~ ^[0-9]+$ ]]; then 35 | echo "${BRANCH}" 36 | VERSION=${BRANCH:0:4} 37 | if [[ "$VERSION" =~ ^[0-9]*[.][0-9]*$ ]]; then 38 | LATEST_VERSION_BRANCH_NAME="${BRANCH}" 39 | LATEST_VERSION_NUMBER="${VERSION}" 40 | fi 41 | fi 42 | done 43 | 44 | echo "" 45 | echo "Latest version: ${LATEST_VERSION_NUMBER} (probably)" 46 | LATEST_VERSION_BRANCH_NAME="remotes/origin/${LATEST_VERSION_BRANCH_NAME}" 47 | echo "Checking out the branch ${LATEST_VERSION_BRANCH_NAME}" 48 | 49 | git checkout ${LATEST_VERSION_BRANCH_NAME} 50 | 51 | grep ".*: .*" package.json | grep -iw electronVersion | cut -d: -f2 52 | 53 | OUTPUT=$(grep ".*: .*" package.json | grep -iw electronVersion | cut -d: -f2) 54 | ELECTRON_VERSION="${OUTPUT//[!0-9.]/}" 55 | 56 | echo "Upcoming Atom version will come with Electron@${ELECTRON_VERSION}" 57 | cd .. 58 | 59 | CURRENT_ATOM_ELECTRON=$(grep ".*: .*"https://raw.githubusercontent.com/atom/atom/master/package.json | grep -iw electronVersion | cut -d: -f2) 60 | CURRENT_ATOM_ELECTRON_VERSION="${OUTPUT//[!0-9.]/}" 61 | 62 | echo "" 63 | echo "Current Atom version is using Electron@${CURRENT_ATOM_ELECTRON_VERSION}" 64 | 65 | PYMAKR_FOLDER="${PWD}/pymakr" 66 | 67 | if [ -d ${PYMAKR_FOLDER} ]; then 68 | echo "Pymakr repository found. Performing a pull..." 69 | cd pymakr 70 | git checkout master 71 | git pull 72 | else 73 | echo "Pymakr repository not found" 74 | git clone https://github.com/pycom/pymakr-atom.git pymakr 75 | cd pymakr 76 | fi 77 | 78 | { 79 | ELECTRON_VERSION_LINE=$(grep "var electron_version" scripts/install.js | grep -iw 'var electron_version' | cut -d: -f2) 80 | CURRENT_ELECTRON_VERSION="${ELECTRON_VERSION_LINE//[!0-9.]/}" 81 | } || { 82 | CURRENT_ELECTRON_VERSION="ERROR" 83 | } 84 | 85 | echo "" 86 | 87 | if [ "$CURRENT_ELECTRON_VERSION" == "$ELECTRON_VERSION" ]; then 88 | RESULT="Pymakr's Elektron is synchronized with Atom ${LATEST_VERSION_NUMBER}!" 89 | else 90 | RESULT="Pymakr's Elektron is NOT synchronized with Atom ${LATEST_VERSION_NUMBER}!" 91 | fi 92 | 93 | echo "" 94 | echo "Elektron versions:" 95 | echo "Pymakr: ${CURRENT_ELECTRON_VERSION}" 96 | echo "Atom (master): ${CURRENT_ATOM_ELECTRON_VERSION}" 97 | echo "Atom ($LATEST_VERSION_NUMBER): ${ELECTRON_VERSION}" 98 | echo "" 99 | echo ${RESULT} 100 | 101 | echo "" 102 | cd .. 103 | ls 104 | echo "Downloading binaries for ${ELECTRON_VERSION}..." 105 | pwsh scripts/mp-download-atom.ps1 -ElectronVersions \"${ELECTRON_VERSION}\" 106 | 107 | 108 | # Sending the response to a slack bot 109 | if [ "$1" == "bot" ]; then 110 | BOT_ENDPOINT='####' # put the endpoint here 111 | PAYLOAD="{\"text\":\"${RESULT}\"}" 112 | curl --silent --output -X POST -H 'Content-type: application/json' --data "$PAYLOAD" ${BOT_ENDPOINT} 113 | fi 114 | 115 | exit 116 | -------------------------------------------------------------------------------- /scripts/compress.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import zlib 3 | import binascii 4 | 5 | args = sys.argv 6 | def compress(path,zipped_path): 7 | d = open(path,'rb').read() 8 | compressed_data = zlib.compress(d, 2) 9 | f = open(zipped_path,'wb') 10 | f.write(compressed_data) 11 | f.close() 12 | 13 | compress(args[1],args[2]) 14 | -------------------------------------------------------------------------------- /scripts/download-binaries.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const github = require('@actions/github'); 3 | const axios = require('axios'); 4 | 5 | const gitToken = core.getInput('git-token') || process.env.GITHUB_TOKEN; 6 | const octokit = new github.GitHub(gitToken); 7 | const shell = require('node-powershell'); 8 | 9 | const repo = { 10 | owner: 'atom', 11 | repo: 'atom', 12 | }; 13 | 14 | const ps = new shell({ 15 | executionPolicy: 'Bypass', 16 | noProfile: true, 17 | }); 18 | const fetchElectronVersion = async (tag) => { 19 | try { 20 | // Fetch package.json file (contains electron target) 21 | const response = await axios.get( 22 | `https://raw.githubusercontent.com/atom/atom/${tag}/package.json`, 23 | ); 24 | const version = response.data.electronVersion.toString(); 25 | core.info(`Atom ${tag} uses Electron v${version}`); 26 | return version; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | 32 | // gets binaries for current and nightly Atom version 33 | const getBinaries = async () => { 34 | const tags = ( 35 | await octokit.repos.listTags({ 36 | ...repo, 37 | per_page: 50, 38 | }) 39 | ).data.map((item) => item.name); 40 | 41 | const atomNightlyTag = tags[0]; 42 | let currentIndex = 1; 43 | let atomCurrentTag = tags[currentIndex]; 44 | while ( 45 | atomCurrentTag.includes('beta') || 46 | (atomCurrentTag == 'master' && currentIndex < 10) 47 | ) { 48 | currentIndex += 1; 49 | atomCurrentTag = tags[currentIndex]; 50 | } 51 | const atomNightlyElectron = await fetchElectronVersion(atomNightlyTag); 52 | const atomCurrentElectron = await fetchElectronVersion(atomCurrentTag); 53 | const electronVersions = []; 54 | electronVersions.push(atomCurrentElectron); 55 | if (atomCurrentElectron !== atomNightlyElectron) electronVersions.push(atomNightlyElectron); 56 | console.log('\n'); 57 | console.log(`Downloading binaries for ${electronVersions.join(', ')}`); 58 | ps.addCommand( 59 | 'scripts/mp-download-atom.ps1', 60 | [{ ElectronVersions: electronVersions }], 61 | ); 62 | 63 | ps.invoke() 64 | .then((output) => { 65 | console.log(output); 66 | ps.dispose(); 67 | }) 68 | .catch((err) => { 69 | console.log(err); 70 | ps.dispose(); 71 | }); 72 | }; 73 | 74 | getBinaries(); 75 | -------------------------------------------------------------------------------- /scripts/functions-versions.js: -------------------------------------------------------------------------------- 1 | const https = require('https'); 2 | const { exec } = require('child_process'); 3 | 4 | // params 5 | const url = 'https://api.github.com/repos/atom/atom/releases/latest'; 6 | const download_url_tmp = 'https://github.com/atom/atom/releases/download/v'; // add: / 7 | const path_latest = '';// "/atom/atom/releases/latest" 8 | const request = require('request'); 9 | 10 | const filenames = { 11 | win32: 'atom-windows.zip', win64: 'atom-x64-windows.zip', darwin: 'atom-mac.zip', linux: 'atom.x86_64.rpm', aix: 'atom.x86_64.rpm', 12 | }; 13 | 14 | module.exports = { 15 | getCurrentVersions(cb) { 16 | exec('atom --version', (error, stdout, stderr) => { 17 | const atom_version = stdout.substring(stdout.indexOf(':') + 2, stdout.indexOf('Electron') - 1); 18 | const electron_version = stdout.substring(stdout.indexOf('Electron') + 10, stdout.indexOf('Chrome') - 1); 19 | cb(atom_version, electron_version); 20 | }); 21 | }, 22 | 23 | getDownloadUrl(version) { 24 | const filename = this.getDownloadFileName(); 25 | return `${download_url_tmp + version}/${filename}`; 26 | }, 27 | 28 | loadLatest(cb) { 29 | getContent(url + path_latest, (data) => { 30 | const json_data = JSON.parse(data); 31 | if (json_data) { 32 | const version = json_data.name; 33 | cb(version); 34 | } else { 35 | cb(); 36 | } 37 | }); 38 | }, 39 | 40 | getDownloadFileName() { 41 | let plf = process.platform; 42 | if (plf == 'win32' && process.arch != 'ia32') { 43 | plf = 'win64'; 44 | } 45 | return filenames[plf]; 46 | }, 47 | versionBiggerThen(a, b) { 48 | let i; let 49 | diff; 50 | const regExStrip0 = /(\.0+)+$/; 51 | const segmentsA = a.replace(regExStrip0, '').split('.'); 52 | const segmentsB = b.replace(regExStrip0, '').split('.'); 53 | const l = Math.min(segmentsA.length, segmentsB.length); 54 | 55 | for (i = 0; i < l; i += 1) { 56 | diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); 57 | if (diff) { 58 | return diff; 59 | } 60 | } 61 | } 62 | return segmentsA.length - segmentsB.length; 63 | }, 64 | }; 65 | function getContent(url, cb) { 66 | const headers = { 67 | 'User-Agent': 'Super Agent/0.0.1', 68 | 'Content-Type': 'application/x-www-form-urlencoded', 69 | }; 70 | const options = { 71 | url, 72 | method: 'GET', 73 | headers, 74 | }; 75 | 76 | request(options, (error, res, body) => { 77 | const data = ''; 78 | cb(body); 79 | }); 80 | } 81 | -------------------------------------------------------------------------------- /scripts/post-install.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const rimraf = require('rimraf'); 3 | const path = require('path'); 4 | const os = require('os'); 5 | 6 | const dir = __dirname.replace('/scripts', '').replace('\\scripts', ''); 7 | const bindings_target = `${dir}/node_modules/@serialport/bindings/build/release`; 8 | const bindings_target_capital = `${dir}/node_modules/@serialport/bindings/build/Release`; 9 | 10 | 11 | function copyFileSync(source, target) { 12 | let targetFile = target; 13 | 14 | // if target is a directory a new file with the same name will be created 15 | if (fs.existsSync(target)) { 16 | if (fs.lstatSync(target).isDirectory()) { 17 | targetFile = path.join(target, path.basename(source)); 18 | } 19 | } 20 | 21 | fs.writeFileSync(targetFile, fs.readFileSync(source)); 22 | } 23 | 24 | function copyFolderRecursiveSync(source, target) { 25 | let files = []; 26 | 27 | // check if folder needs to be created or integrated 28 | const targetFolder = path.join(target, path.basename(source)); 29 | if (!fs.existsSync(targetFolder)) { 30 | fs.mkdirSync(targetFolder); 31 | } 32 | 33 | // copy 34 | if (fs.lstatSync(source).isDirectory()) { 35 | files = fs.readdirSync(source); 36 | files.forEach((file) => { 37 | const curSource = path.join(source, file); 38 | if (fs.lstatSync(curSource).isDirectory()) { 39 | copyFolderRecursiveSync(curSource, targetFolder); 40 | } else { 41 | copyFileSync(curSource, targetFolder); 42 | } 43 | }); 44 | } 45 | return true; 46 | } 47 | 48 | function postInstall() { 49 | try { 50 | rimraf.sync(bindings_target); 51 | rimraf.sync(bindings_target_capital); 52 | console.log( 53 | `\nCleaned the '${bindings_target}' \nfolder to prevent including native modules in the default location and breaking cross-platform portability.`, 54 | ); 55 | console.log( 56 | 'Copy all /native_modules into the /node_modules for cross platform packaging', 57 | ); 58 | copyFolderRecursiveSync( 59 | `${dir}/native_modules/@serialport`, 60 | `${dir}/node_modules`, 61 | ); 62 | if(os.platform() === 'win32') { 63 | console.log('win32 bindings file copy'); 64 | try { 65 | copyFolderRecursiveSync( 66 | `${dir}/native_modules/@serialport/bindings`, 67 | `${dir}/node_modules`, 68 | ); 69 | } catch (e) { 70 | console.log(e.message); 71 | } 72 | } 73 | 74 | console.log('Success.'); 75 | } catch (error) { 76 | console.log("Failed to copy bindings file, pymakr won't work"); 77 | console.log(error); 78 | } 79 | } 80 | 81 | postInstall(); 82 | -------------------------------------------------------------------------------- /scripts/restart-atom.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | IS_RUNNING=0 3 | pgrep -x Atom >/dev/null && IS_RUNNING=1 4 | 5 | if [ $IS_RUNNING == 1 ]; then 6 | echo "Detected changes. Restarting Atom..." 7 | killall Atom 8 | else 9 | echo "Detected changes. Opening Atom..." 10 | fi 11 | 12 | atom ~/.atom 13 | 14 | exit 15 | -------------------------------------------------------------------------------- /scripts/update-check.js: -------------------------------------------------------------------------------- 1 | const vtools = require('./functions-versions.js'); 2 | 3 | vtools.getCurrentVersions((atom_version, electron_version) => { 4 | console.log(`Atom current: ${atom_version}`); 5 | console.log(`Electron current: ${electron_version}`); 6 | vtools.loadLatest((atom_latest_version) => { 7 | console.log(`Atom Latest: ${atom_latest_version}`); 8 | if (vtools.versionBiggerThen(atom_latest_version, atom_version)) { 9 | console.log(`New version ${atom_latest_version} available! Download link:`); 10 | console.log(vtools.getDownloadUrl(atom_latest_version)); 11 | } 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /snippets/ble-connect-data.py: -------------------------------------------------------------------------------- 1 | from network import Bluetooth 2 | import time 3 | bt = Bluetooth() 4 | bt.start_scan(-1) 5 | 6 | while True: 7 | adv = bt.get_adv() 8 | if adv and bt.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL) == 'Heart Rate': 9 | try: 10 | conn = bt.connect(adv.mac) 11 | services = conn.services() 12 | for service in services: 13 | time.sleep(0.050) 14 | if type(service.uuid()) == bytes: 15 | print('Reading chars from service = {}'.format(service.uuid())) 16 | else: 17 | print('Reading chars from service = %x' % service.uuid()) 18 | chars = service.characteristics() 19 | for char in chars: 20 | if (char.properties() & Bluetooth.PROP_READ): 21 | print('char {} value = {}'.format(char.uuid(), char.read())) 22 | conn.disconnect() 23 | break 24 | except: 25 | pass 26 | else: 27 | time.sleep(0.050) 28 | -------------------------------------------------------------------------------- /snippets/index.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | export default class ConfigSnippets { 4 | static defaults(){ 5 | return { 6 | files: [ 7 | { 8 | name: "WiFi Simple", 9 | description: "Very basic router connection script", 10 | id: "wifi-simple" 11 | }, 12 | { 13 | name: "WiFi Static IP", 14 | description: "Connect to a router with a static IP", 15 | id: "wifi-static-ip" 16 | }, 17 | { 18 | name: "WiFi Multiple networks", 19 | description: "Extended WiFi script with static IP and multi network", 20 | id: "wifi-multi-network" 21 | }, 22 | { 23 | name: "Bluetooth Connect", 24 | description: "Connect and retrieve data from bluetooth device", 25 | id: "ble-connect-data" 26 | }, 27 | { 28 | name: "RGB LED Trafic light", 29 | description: "Switches the RGB LED between red orange and green", 30 | id: "rgb-led-traficlight" 31 | }, 32 | { 33 | name: "Pytrack", 34 | description: "Basic pytrack example", 35 | id: "pytrack" 36 | }, 37 | { 38 | name: "Pysense", 39 | description: "Basic pysense example", 40 | id: "pysense" 41 | }, 42 | { 43 | name: "Pyscan", 44 | description: "Basic pyscan example", 45 | id: "pyscan" 46 | }, 47 | { 48 | name: "LTE Cat-M1", 49 | description: "Connect over LTE Cat M1 to Google's web server over secure SSL:", 50 | id: "lte-cat-m1" 51 | }, 52 | { 53 | name: "LTE NB-IoT", 54 | description: "Narrow Band IoT example with Vodaphone", 55 | id: "lte-nb-iot" 56 | }, 57 | { 58 | name: "LTE get IMEI", 59 | description: "Returns your modules IMEI number", 60 | id: "lte-get-imei" 61 | }, 62 | { 63 | name: "Pyscan", 64 | description: "Basic pyscan example", 65 | id: "pyscan" 66 | }, 67 | { 68 | name: "Pyscan", 69 | description: "Basic pyscan example", 70 | id: "pyscan" 71 | }, 72 | ], 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /snippets/lte-cat-m1.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import ssl 3 | import time 4 | from network import LTE 5 | 6 | lte = LTE() # instantiate the LTE object 7 | lte.attach() # attach the cellular modem to a base station 8 | while not lte.isattached(): 9 | time.sleep(0.25) 10 | lte.connect() # start a data session and obtain an IP address 11 | while not lte.isconnected(): 12 | time.sleep(0.25) 13 | 14 | s = socket.socket() 15 | s = ssl.wrap_socket(s) 16 | s.connect(socket.getaddrinfo('www.google.com', 443)[0][-1]) 17 | s.send(b"GET / HTTP/1.0\r\n\r\n") 18 | print(s.recv(4096)) 19 | s.close() 20 | 21 | lte.disconnect() 22 | lte.dettach() 23 | -------------------------------------------------------------------------------- /snippets/lte-get-imei.py: -------------------------------------------------------------------------------- 1 | from network import LTE 2 | lte = LTE() 3 | lte.send_at_cmd('AT+CGSN=1') 4 | -------------------------------------------------------------------------------- /snippets/lte-nb-iot.py: -------------------------------------------------------------------------------- 1 | from network import LTE 2 | lte = LTE() 3 | lte.attach(band=20, apn="nb.inetd.gdsp") 4 | while not lte.isattached(): 5 | time.sleep(0.25) 6 | lte.connect() # start a data session and obtain an IP address 7 | while not lte.isconnected(): 8 | time.sleep(0.25) 9 | 10 | # now use socket as usual... 11 | -------------------------------------------------------------------------------- /snippets/pyscan.py: -------------------------------------------------------------------------------- 1 | from pyscan import Pyscan 2 | from MFRC630 import MFRC630 3 | import time 4 | import pycom 5 | import _thread 6 | 7 | VALID_CARDS = [[0x43, 0x95, 0xDD, 0xF8], 8 | [0x43, 0x95, 0xDD, 0xF9]] 9 | 10 | py = Pyscan() 11 | nfc = MFRC630(py) 12 | 13 | RGB_BRIGHTNESS = 0x8 14 | 15 | RGB_RED = (RGB_BRIGHTNESS << 16) 16 | RGB_GREEN = (RGB_BRIGHTNESS << 8) 17 | RGB_BLUE = (RGB_BRIGHTNESS) 18 | 19 | # Make sure heartbeat is disabled before setting RGB LED 20 | pycom.heartbeat(False) 21 | 22 | # Initialise the MFRC630 with some settings 23 | nfc.mfrc630_cmd_init() 24 | 25 | def check_uid(uid, len): 26 | return VALID_CARDS.count(uid[:len]) 27 | 28 | def discovery_loop(nfc, id): 29 | while True: 30 | # Send REQA for ISO14443A card type 31 | atqa = nfc.mfrc630_iso14443a_WUPA_REQA(nfc.MFRC630_ISO14443_CMD_REQA) 32 | if (atqa != 0): 33 | # A card has been detected, read UID 34 | uid = bytearray(10) 35 | uid_len = nfc.mfrc630_iso14443a_select(uid) 36 | if (uid_len > 0): 37 | if (check_uid(list(uid), uid_len)) > 0: 38 | pycom.rgbled(RGB_GREEN) 39 | else: 40 | pycom.rgbled(RGB_RED) 41 | else: 42 | # No card detected 43 | pycom.rgbled(RGB_BLUE) 44 | nfc.mfrc630_cmd_reset() 45 | time.sleep(.5) 46 | nfc.mfrc630_cmd_init() 47 | 48 | # This is the start of our main execution... start the thread 49 | _thread.start_new_thread(discovery_loop, (nfc, 0)) 50 | -------------------------------------------------------------------------------- /snippets/pysense.py: -------------------------------------------------------------------------------- 1 | from LIS2HH12 import LIS2HH12 2 | from pytrack import Pytrack 3 | py = Pytrack() 4 | acc = LIS2HH12() 5 | 6 | while True: 7 | pitch = acc.pitch() 8 | roll = acc.roll() 9 | print('{},{}'.format(pitch, roll)) 10 | time.sleep_ms(100) 11 | -------------------------------------------------------------------------------- /snippets/pytrack.py: -------------------------------------------------------------------------------- 1 | import machine 2 | import math 3 | import network 4 | import os 5 | import time 6 | import utime 7 | import gc 8 | from machine import RTC 9 | from machine import SD 10 | from L76GNSS import L76GNSS 11 | from pytrack import Pytrack 12 | 13 | time.sleep(2) 14 | gc.enable() 15 | 16 | # setup rtc 17 | rtc = machine.RTC() 18 | rtc.ntp_sync("pool.ntp.org") 19 | utime.sleep_ms(750) 20 | print('\nRTC Set from NTP to UTC:', rtc.now()) 21 | utime.timezone(7200) 22 | print('Adjusted from UTC to EST timezone', utime.localtime(), '\n') 23 | 24 | py = Pytrack() 25 | l76 = L76GNSS(py, timeout=30) 26 | 27 | # sd = SD() 28 | # os.mount(sd, '/sd') 29 | # f = open('/sd/gps-record.txt', 'w') 30 | 31 | while (True): 32 | coord = l76.coordinates() 33 | #f.write("{} - {}\n".format(coord, rtc.now())) 34 | print("{} - {} - {}".format(coord, rtc.now(), gc.mem_free())) 35 | -------------------------------------------------------------------------------- /snippets/rgb-led-traficlight.py: -------------------------------------------------------------------------------- 1 | import pycom 2 | import time 3 | 4 | pycom.heartbeat(False) 5 | for cycles in range(10): # stop after 10 cycles 6 | pycom.rgbled(0x007f00) # green 7 | time.sleep(5) 8 | pycom.rgbled(0x7f7f00) # yellow 9 | time.sleep(1.5) 10 | pycom.rgbled(0x7f0000) # red 11 | time.sleep(4) 12 | -------------------------------------------------------------------------------- /snippets/wifi-multi-network.py: -------------------------------------------------------------------------------- 1 | import os 2 | import machine 3 | 4 | uart = machine.UART(0, 115200) 5 | os.dupterm(uart) 6 | 7 | known_nets = { 8 | '': {'pwd': ''}, 9 | '': {'pwd': '', 'wlan_config': ('10.0.0.114', '255.255.0.0', '10.0.0.1', '10.0.0.1')}, # (ip, subnet_mask, gateway, DNS_server) 10 | } 11 | 12 | if machine.reset_cause() != machine.SOFT_RESET: 13 | from network import WLAN 14 | wl = WLAN() 15 | wl.mode(WLAN.STA) 16 | original_ssid = wl.ssid() 17 | original_auth = wl.auth() 18 | 19 | print("Scanning for known wifi nets") 20 | available_nets = wl.scan() 21 | nets = frozenset([e.ssid for e in available_nets]) 22 | 23 | known_nets_names = frozenset([key for key in known_nets]) 24 | net_to_use = list(nets & known_nets_names) 25 | try: 26 | net_to_use = net_to_use[0] 27 | net_properties = known_nets[net_to_use] 28 | pwd = net_properties['pwd'] 29 | sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] 30 | if 'wlan_config' in net_properties: 31 | wl.ifconfig(config=net_properties['wlan_config']) 32 | wl.connect(net_to_use, (sec, pwd), timeout=10000) 33 | while not wl.isconnected(): 34 | machine.idle() # save power while waiting 35 | print("Connected to "+net_to_use+" with IP address:" + wl.ifconfig()[0]) 36 | 37 | except Exception as e: 38 | print("Failed to connect to any known network, going into AP mode") 39 | wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT) 40 | -------------------------------------------------------------------------------- /snippets/wifi-simple.py: -------------------------------------------------------------------------------- 1 | from network import WLAN 2 | wlan = WLAN(mode=WLAN.STA) 3 | Now the device may proceed to scan for networks: 4 | 5 | nets = wlan.scan() 6 | for net in nets: 7 | if net.ssid == 'mywifi': 8 | print('Network found!') 9 | wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000) 10 | while not wlan.isconnected(): 11 | machine.idle() # save power while waiting 12 | print('WLAN connection succeeded!') 13 | break 14 | -------------------------------------------------------------------------------- /snippets/wifi-static-ip.py: -------------------------------------------------------------------------------- 1 | import machine 2 | from network import WLAN 3 | wlan = WLAN() # get current object, without changing the mode 4 | 5 | if machine.reset_cause() != machine.SOFT_RESET: 6 | wlan.init(mode=WLAN.STA) 7 | # configuration below MUST match your home router settings!! 8 | wlan.ifconfig(config=('192.168.178.107', '255.255.255.0', '192.168.178.1', '8.8.8.8')) 9 | 10 | if not wlan.isconnected(): 11 | # change the line below to match your network ssid, security and password 12 | wlan.connect('mywifi', auth=(WLAN.WPA2, 'mywifikey'), timeout=5000) 13 | while not wlan.isconnected(): 14 | machine.idle() # save power while waiting 15 | -------------------------------------------------------------------------------- /spec/pycom-sync-atom-spec.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import Pymakr from '../lib/pymakr'; 4 | 5 | // Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs. 6 | // 7 | // To run a specific `it` or `describe` block add an `f` to the front (e.g. `fit` 8 | // or `fdescribe`). Remove the `f` to unfocus the block. 9 | 10 | describe('Pymakr', () => { 11 | let workspaceElement, activationPromise; 12 | 13 | beforeEach(() => { 14 | workspaceElement = atom.views.getView(atom.workspace); 15 | activationPromise = atom.packages.activatePackage('pymakr'); 16 | }); 17 | 18 | // order: 19 | // - Open pymakr, check if element exists 20 | // - Start monitoring terminal output 21 | // - Autoconnected do device on USB? 22 | // - Disconnect and connect again 23 | // - Run a piece of code on the board 24 | // - Clear board flash 25 | // - Upload a file to the board (boot file with wifi connect) 26 | // - Download feature 27 | // - remove local file that was just uploaded 28 | // - Execute download 29 | // - Check local file for correct content 30 | // - Wifi connect 31 | // - Disable autoconnect 32 | // - Change config to correct IP address 33 | // - Check if automatically connected after config change 34 | // - Repeat download/upload/disconnect over wifi 35 | 36 | 37 | describe('pymakr open', () => { 38 | it('opens the terminal', () => { 39 | // Before the activation event the view is not on the DOM, and no panel 40 | // has been created 41 | expect(workspaceElement.querySelector('.pymakr')).toExist(); 42 | 43 | // // This is an activation event, triggering it will cause the package to be 44 | // // activated. 45 | // atom.commands.dispatch(workspaceElement, 'pymakr:toggle'); 46 | 47 | waitsForPromise(() => { 48 | return activationPromise; 49 | }); 50 | 51 | runs(() => { 52 | // expect(workspaceElement.querySelector('#pymakr')).toExist(); 53 | 54 | let pycomSyncAtomElement = workspaceElement.querySelector('.pymakr'); 55 | expect(pycomSyncAtomElement).toExist(); 56 | }); 57 | }); 58 | 59 | // 60 | it('connects to the device', () => { 61 | 62 | waitsFor(function() { 63 | // workspaceElement = atom.views.getView(atom.workspace); 64 | var title_el = workspaceElement.querySelector('.pymakr-title') 65 | if(title_el){ 66 | console.log(title_el.innerHTML) 67 | return title_el.innerHTML.indexOf(" Connected") > -1; 68 | } 69 | return false 70 | 71 | }, "Board to be connected", 10000); 72 | 73 | runs(() => { 74 | let connected = workspaceElement.querySelector('.pymakr-title').innerHTML.indexOf(" Connected") > -1; 75 | console.log(workspaceElement.querySelector('.pymakr-title').innerHTML) 76 | expect(connected).toEqual(true); 77 | }); 78 | }) 79 | 80 | 81 | // // This test shows you an integration test testing at the view level. 82 | // 83 | // // Attaching the workspaceElement to the DOM is required to allow the 84 | // // `toBeVisible()` matchers to work. Anything testing visibility or focus 85 | // // requires that the workspaceElement is on the DOM. Tests that attach the 86 | // // workspaceElement to the DOM are generally slower than those off DOM. 87 | // jasmine.attachToDOM(workspaceElement); 88 | // 89 | // expect(workspaceElement.querySelector('.pymakr')).not.toExist(); 90 | // 91 | // // This is an activation event, triggering it causes the package to be 92 | // // activated. 93 | // atom.commands.dispatch(workspaceElement, 'pymakr:toggle'); 94 | // 95 | // waitsForPromise(() => { 96 | // return activationPromise; 97 | // }); 98 | // 99 | // runs(() => { 100 | // // Now we can test for view visibility 101 | // let pycomSyncAtomElement = workspaceElement.querySelector('.pymakr'); 102 | // expect(pycomSyncAtomElement).toBeVisible(); 103 | // atom.commands.dispatch(workspaceElement, 'pymakr:toggle'); 104 | // expect(pycomSyncAtomElement).not.toBeVisible(); 105 | // }); 106 | // }); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /spec/pycom-sync-atom-view-spec.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | // import PycomSyncAtomView from '../lib/pymakr-view'; 4 | // 5 | // describe('PycomSyncAtomView', () => { 6 | // it('has one valid test', () => { 7 | // expect('life').toBe('easy'); 8 | // }); 9 | // }); 10 | -------------------------------------------------------------------------------- /styles/assets/logo-navy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/styles/assets/logo-navy.png -------------------------------------------------------------------------------- /styles/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/styles/assets/logo.png -------------------------------------------------------------------------------- /styles/assets/pybytes-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycom/pymakr-atom/95cc5ce273025c2751ae84d61b22bcc28d9b598f/styles/assets/pybytes-logo.png -------------------------------------------------------------------------------- /styles/assets/pycom-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test-electron/bindings_1.5.0/LICENSE.md: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test-electron/bindings_1.5.0/README.md: -------------------------------------------------------------------------------- 1 | node-bindings 2 | ============= 3 | ### Helper module for loading your native module's `.node` file 4 | 5 | This is a helper module for authors of Node.js native addon modules. 6 | It is basically the "swiss army knife" of `require()`ing your native module's 7 | `.node` file. 8 | 9 | Throughout the course of Node's native addon history, addons have ended up being 10 | compiled in a variety of different places, depending on which build tool and which 11 | version of node was used. To make matters worse, now the `gyp` build tool can 12 | produce either a __Release__ or __Debug__ build, each being built into different 13 | locations. 14 | 15 | This module checks _all_ the possible locations that a native addon would be built 16 | at, and returns the first one that loads successfully. 17 | 18 | 19 | Installation 20 | ------------ 21 | 22 | Install with `npm`: 23 | 24 | ``` bash 25 | $ npm install --save bindings 26 | ``` 27 | 28 | Or add it to the `"dependencies"` section of your `package.json` file. 29 | 30 | 31 | Example 32 | ------- 33 | 34 | `require()`ing the proper bindings file for the current node version, platform 35 | and architecture is as simple as: 36 | 37 | ``` js 38 | var bindings = require('bindings')('binding.node') 39 | 40 | // Use your bindings defined in your C files 41 | bindings.your_c_function() 42 | ``` 43 | 44 | 45 | Nice Error Output 46 | ----------------- 47 | 48 | When the `.node` file could not be loaded, `node-bindings` throws an Error with 49 | a nice error message telling you exactly what was tried. You can also check the 50 | `err.tries` Array property. 51 | 52 | ``` 53 | Error: Could not load the bindings file. Tried: 54 | → /Users/nrajlich/ref/build/binding.node 55 | → /Users/nrajlich/ref/build/Debug/binding.node 56 | → /Users/nrajlich/ref/build/Release/binding.node 57 | → /Users/nrajlich/ref/out/Debug/binding.node 58 | → /Users/nrajlich/ref/Debug/binding.node 59 | → /Users/nrajlich/ref/out/Release/binding.node 60 | → /Users/nrajlich/ref/Release/binding.node 61 | → /Users/nrajlich/ref/build/default/binding.node 62 | → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node 63 | at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13) 64 | at Object. (/Users/nrajlich/ref/lib/ref.js:5:47) 65 | at Module._compile (module.js:449:26) 66 | at Object.Module._extensions..js (module.js:467:10) 67 | at Module.load (module.js:356:32) 68 | at Function.Module._load (module.js:312:12) 69 | ... 70 | ``` 71 | 72 | The searching for the `.node` file will originate from the first directory in which has a `package.json` file is found. 73 | 74 | License 75 | ------- 76 | 77 | (The MIT License) 78 | 79 | Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> 80 | 81 | Permission is hereby granted, free of charge, to any person obtaining 82 | a copy of this software and associated documentation files (the 83 | 'Software'), to deal in the Software without restriction, including 84 | without limitation the rights to use, copy, modify, merge, publish, 85 | distribute, sublicense, and/or sell copies of the Software, and to 86 | permit persons to whom the Software is furnished to do so, subject to 87 | the following conditions: 88 | 89 | The above copyright notice and this permission notice shall be 90 | included in all copies or substantial portions of the Software. 91 | 92 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 93 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 94 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 95 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 96 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 97 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 98 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 99 | -------------------------------------------------------------------------------- /test-electron/bindings_1.5.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bindings", 3 | "description": "Helper module for loading your native module's .node file", 4 | "keywords": [ 5 | "native", 6 | "addon", 7 | "bindings", 8 | "gyp", 9 | "waf", 10 | "c", 11 | "c++" 12 | ], 13 | "version": "1.5.0", 14 | "author": "Nathan Rajlich (http://tootallnate.net)", 15 | "repository": { 16 | "type": "git", 17 | "url": "git://github.com/TooTallNate/node-bindings.git" 18 | }, 19 | "main": "./bindings.js", 20 | "bugs": { 21 | "url": "https://github.com/TooTallNate/node-bindings/issues" 22 | }, 23 | "homepage": "https://github.com/TooTallNate/node-bindings", 24 | "license": "MIT", 25 | "dependencies": { 26 | "file-uri-to-path": "1.0.0" 27 | } 28 | 29 | ,"_resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" 30 | ,"_integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==" 31 | ,"_from": "bindings@1.5.0" 32 | } -------------------------------------------------------------------------------- /test-electron/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable node/no-missing-require,no-unused-vars,node/no-unpublished-require,node/no-extraneous-require */ 2 | const app = require('electron').app 3 | 4 | console.log( `electron: ${process.versions.electron}, ABI: ${process.versions.modules}, platform:${process.platform}, arch: ${process.arch}`) 5 | console.log( ` [node/electron]-v${process.versions.modules}-${process.platform}-${process.arch}`) 6 | try { 7 | // will seek 'upwards' to find the the serialport configured in the project above. 8 | const serialport = require('serialport') 9 | console.log(`loaded serialport OK`) 10 | app.exit(0) 11 | //console.log( JSON.stringify(process.arch)) 12 | } catch (e) { 13 | console.error('Error loading serialport') 14 | console.error(e) 15 | //console.error(e.stack) 16 | app.exit(-1) 17 | } 18 | 19 | app.quit() 20 | -------------------------------------------------------------------------------- /test-electron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-test", 3 | "version": "1.0.0", 4 | "description": "test serialport under electron", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Jos Verlinde", 10 | "license": "MIT", 11 | "dependencies": { 12 | "electron": "^5.0.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test-electron/runtest.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | param( 3 | $electron_version = '5.0.13' 4 | ) 5 | # '4.2.5','5.0.10','6.1.2' 6 | 7 | # ######################################################################################################### 8 | # Setup 9 | # ######################################################################################################### 10 | 11 | $root_folder = Join-Path $PSScriptRoot -ChildPath '..' 12 | $test_folder = $PSScriptRoot 13 | cd $root_folder 14 | 15 | # Ensure electron_version is a list 16 | if (!$electron_version.GetType().isArray) { 17 | $electron_version = $electron_version -split ',' 18 | } 19 | 20 | 21 | function ActionFail ($msg) { 22 | # Fails Github Action and reports error message 23 | # Useful for Github Action failure annotations 24 | Write-Host "::error::$msg" 25 | exit(1) 26 | } 27 | 28 | 29 | foreach ($version in $electron_version) { 30 | write-host "get ready to test on electron $version" 31 | 32 | # Root Project 33 | # write-host "Root Project: /node_modules/*" 34 | # Remove-Item $root_folder/node_modules/* -Recurse -Force -ErrorAction SilentlyContinue 35 | 36 | #--- Test project 37 | cd $test_folder 38 | # test folder should be npm initialised as a nodejs project 39 | write-host "Test Project: Delete /test-electron/node_modules/*" 40 | 41 | # Clean out the test/node_modules to avoid interrerence with other/earlier installs 42 | Remove-Item $test_folder/node_modules/* -Recurse -Force -ErrorAction SilentlyContinue 43 | 44 | #npm install 45 | write-host "TEST Project: install electron version $version" 46 | npm install electron@$version 47 | 48 | #sanity check 49 | npx electron --version 50 | 51 | # --- Root Project 52 | cd $root_folder 53 | 54 | Write-Host "Root Project: Prep for CI Install (npm ci)" 55 | npm ci 56 | npm prune 57 | 58 | # also make sure that the native modules are in place for the test 59 | # No need top copy twice if root project has ta postinstall script 60 | # &$root_folder/scripts/mp-download.ps1 -copyonly 61 | 62 | #--- Test project 63 | cd $test_folder 64 | 65 | # use a version of bindings module that provides some more output on what is loaded 66 | # todo: check that the root project is indeed using the same version or build a path version 67 | # hardcoded for bindings@1.5.0 68 | copy-item $test_folder/bindings_1.5.0/bindings.js $root_folder/node_modules/bindings/bindings.js -force -Verbose 69 | 70 | write-host "run test app" 71 | # &npx electron test/index.js 72 | #npm run test 73 | npx electron ./index.js 74 | if ($LASTEXITCODE -ne 0 ) { 75 | #--- Root Project 76 | cd $root_folder 77 | ActionFail "serial port cannot be loaded, try to re-build" 78 | } 79 | else { 80 | #--- Root Project 81 | cd $root_folder 82 | } 83 | 84 | } 85 | #finally 86 | exit(0) 87 | --------------------------------------------------------------------------------