├── .gitignore ├── .pylintrc ├── .travis.yml ├── AUTHORS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── aa.jpg ├── app ├── .gitignore ├── .jscsrc ├── Gruntfile.js ├── bower.json ├── css │ └── main.css ├── images │ ├── beagleterm-128.png │ ├── beagleterm-16.png │ ├── beagleterm-32.png │ └── beagleterm-48.png ├── index.html ├── js │ ├── background.js │ ├── draw_ui.js │ ├── index.js │ └── lib │ │ ├── hterm_all.js │ │ └── hterm_all.min.js ├── manifest.json └── package.json └── tools └── packing.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .DS_Store 3 | /build 4 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | # This file comes from Chromium depot_tools project. 2 | 3 | [MASTER] 4 | 5 | # Specify a configuration file. 6 | #rcfile= 7 | 8 | # Python code to execute, usually for sys.path manipulation such as 9 | # pygtk.require(). 10 | #init-hook= 11 | 12 | # Profiled execution. 13 | profile=no 14 | 15 | # Add files or directories to the blacklist. They should be base names, not 16 | # paths. 17 | ignore=CVS 18 | 19 | # Pickle collected data for later comparisons. 20 | persistent=yes 21 | 22 | # List of plugins (as comma separated values of python modules names) to load, 23 | # usually to register additional checkers. 24 | load-plugins= 25 | 26 | 27 | [MESSAGES CONTROL] 28 | 29 | # Enable the message, report, category or checker with the given id(s). You can 30 | # either give multiple identifier separated by comma (,) or put this option 31 | # multiple time. 32 | #enable= 33 | 34 | # Disable the message, report, category or checker with the given id(s). You 35 | # can either give multiple identifier separated by comma (,) or put this option 36 | # multiple time (only on the command line, not in the configuration file where 37 | # it should appear only once). 38 | # CHANGED: 39 | # C0103: Invalid name "" 40 | # C0111: Missing docstring 41 | # C0302: Too many lines in module (N) 42 | # I0010: Unable to consider inline option '' 43 | # I0011: Locally disabling WNNNN 44 | # 45 | # R0801: Similar lines in N files 46 | # R0901: Too many ancestors (8/7) 47 | # R0902: Too many instance attributes (N/7) 48 | # R0903: Too few public methods (N/2) 49 | # R0904: Too many public methods (N/20) 50 | # R0911: Too many return statements (N/6) 51 | # R0912: Too many branches (N/12) 52 | # R0913: Too many arguments (N/5) 53 | # R0914: Too many local variables (N/15) 54 | # R0915: Too many statements (N/50) 55 | # R0921: Abstract class not referenced 56 | # R0922: Abstract class is only referenced 1 times 57 | # W0122: Use of the exec statement 58 | # W0141: Used builtin function '' 59 | # W0142: Used * or ** magic 60 | # W0402: Uses of a deprecated module 'string' 61 | # W0404: 41: Reimport 'XX' (imported line NN) 62 | # W0511: TODO 63 | # W0603: Using the global statement 64 | # W0703: Catch "Exception" 65 | # W1201: Specify string format arguments as logging function parameters 66 | # 67 | # These should get enabled, but the codebase has too many violations currently. 68 | # bad-continuation 69 | # anomalous-backslash-in-string 70 | # bad-context-manager 71 | # bad-indentation 72 | # bad-str-strip-call 73 | # bad-whitespace 74 | # cell-var-from-loop 75 | # deprecated-lambda 76 | # eval-used 77 | # function-redefined 78 | # import-error 79 | # locally-enabled 80 | # missing-final-newline 81 | # no-init 82 | # no-name-in-module 83 | # no-self-use 84 | # not-callable 85 | # old-style-class 86 | # protected-access 87 | # superfluous-parens 88 | # super-on-old-class 89 | # too-many-function-args 90 | # trailing-whitespace 91 | # unnecessary-semicolon 92 | # unpacking-non-sequence 93 | # unused-import 94 | # useless-else-on-loop 95 | disable=C0103,C0111,C0302,I0010,I0011,R0801,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0921,R0922,W0122,W0141,W0142,W0402,W0404,W0511,W0603,W0703,W1201,bad-continuation,anomalous-backslash-in-string,bad-context-manager,bad-indentation,bad-str-strip-call,bad-whitespace,cell-var-from-loop,deprecated-lambda,eval-used,function-redefined,import-error,locally-enabled,missing-final-newline,no-init,no-name-in-module,no-self-use,not-callable,old-style-class,protected-access,superfluous-parens,super-on-old-class,too-many-function-args,trailing-whitespace,unnecessary-semicolon,unpacking-non-sequence,unused-import,useless-else-on-loop 96 | 97 | 98 | [REPORTS] 99 | 100 | # Set the output format. Available formats are text, parseable, colorized, msvs 101 | # (visual studio) and html 102 | output-format=text 103 | 104 | # Put messages in a separate file for each module / package specified on the 105 | # command line instead of printing them on stdout. Reports (if any) will be 106 | # written in a file name "pylint_global.[txt|html]". 107 | files-output=no 108 | 109 | # Tells whether to display a full report or only the messages 110 | # CHANGED: 111 | reports=no 112 | 113 | # Python expression which should return a note less than 10 (10 is the highest 114 | # note). You have access to the variables errors warning, statement which 115 | # respectively contain the number of errors / warnings messages and the total 116 | # number of statements analyzed. This is used by the global evaluation report 117 | # (RP0004). 118 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 119 | 120 | # Add a comment according to your evaluation note. This is used by the global 121 | # evaluation report (RP0004). 122 | comment=no 123 | 124 | 125 | [VARIABLES] 126 | 127 | # Tells whether we should check for unused import in __init__ files. 128 | init-import=no 129 | 130 | # A regular expression matching the beginning of the name of dummy variables 131 | # (i.e. not used). 132 | dummy-variables-rgx=_|dummy 133 | 134 | # List of additional names supposed to be defined in builtins. Remember that 135 | # you should avoid to define new builtins when possible. 136 | additional-builtins= 137 | 138 | 139 | [TYPECHECK] 140 | 141 | # Tells whether missing members accessed in mixin class should be ignored. A 142 | # mixin class is detected if its name ends with "mixin" (case insensitive). 143 | ignore-mixin-members=yes 144 | 145 | # List of classes names for which member attributes should not be checked 146 | # (useful for classes with attributes dynamically set). 147 | ignored-classes=SQLObject,twisted.internet.reactor,hashlib,google.appengine.api.memcache 148 | 149 | # When zope mode is activated, add a predefined set of Zope acquired attributes 150 | # to generated-members. 151 | zope=no 152 | 153 | # List of members which are set dynamically and missed by pylint inference 154 | # system, and so shouldn't trigger E0201 when accessed. Python regular 155 | # expressions are accepted. 156 | generated-members=REQUEST,acl_users,aq_parent,multiprocessing.managers.SyncManager 157 | 158 | 159 | [MISCELLANEOUS] 160 | 161 | # List of note tags to take in consideration, separated by a comma. 162 | notes=FIXME,XXX,TODO 163 | 164 | 165 | [SIMILARITIES] 166 | 167 | # Minimum lines number of a similarity. 168 | min-similarity-lines=4 169 | 170 | # Ignore comments when computing similarities. 171 | ignore-comments=yes 172 | 173 | # Ignore docstrings when computing similarities. 174 | ignore-docstrings=yes 175 | 176 | 177 | [FORMAT] 178 | 179 | # Maximum number of characters on a single line. 180 | max-line-length=80 181 | 182 | # Maximum number of lines in a module 183 | max-module-lines=1000 184 | 185 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 186 | # tab). 187 | # CHANGED: 188 | indent-string=' ' 189 | 190 | 191 | [BASIC] 192 | 193 | # Required attributes for module, separated by a comma 194 | required-attributes= 195 | 196 | # List of builtins function names that should not be used, separated by a comma 197 | bad-functions=map,filter,apply,input 198 | 199 | # Regular expression which should only match correct module names 200 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 201 | 202 | # Regular expression which should only match correct module level names 203 | const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 204 | 205 | # Regular expression which should only match correct class names 206 | class-rgx=[A-Z_][a-zA-Z0-9]+$ 207 | 208 | # Regular expression which should only match correct function names 209 | function-rgx=[a-z_][a-z0-9_]{2,30}$ 210 | 211 | # Regular expression which should only match correct method names 212 | method-rgx=[a-z_][a-z0-9_]{2,30}$ 213 | 214 | # Regular expression which should only match correct instance attribute names 215 | attr-rgx=[a-z_][a-z0-9_]{2,30}$ 216 | 217 | # Regular expression which should only match correct argument names 218 | argument-rgx=[a-z_][a-z0-9_]{2,30}$ 219 | 220 | # Regular expression which should only match correct variable names 221 | variable-rgx=[a-z_][a-z0-9_]{2,30}$ 222 | 223 | # Regular expression which should only match correct list comprehension / 224 | # generator expression variable names 225 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 226 | 227 | # Good variable names which should always be accepted, separated by a comma 228 | good-names=i,j,k,ex,Run,_ 229 | 230 | # Bad variable names which should always be refused, separated by a comma 231 | bad-names=foo,bar,baz,toto,tutu,tata 232 | 233 | # Regular expression which should only match functions or classes name which do 234 | # not require a docstring 235 | no-docstring-rgx=__.*__ 236 | 237 | 238 | [DESIGN] 239 | 240 | # Maximum number of arguments for function / method 241 | max-args=5 242 | 243 | # Argument names that match this expression will be ignored. Default to name 244 | # with leading underscore 245 | ignored-argument-names=_.* 246 | 247 | # Maximum number of locals for function / method body 248 | max-locals=15 249 | 250 | # Maximum number of return / yield for function / method body 251 | max-returns=6 252 | 253 | # Maximum number of branch for function / method body 254 | max-branchs=12 255 | 256 | # Maximum number of statements in function / method body 257 | max-statements=50 258 | 259 | # Maximum number of parents for a class (see R0901). 260 | max-parents=7 261 | 262 | # Maximum number of attributes for a class (see R0902). 263 | max-attributes=7 264 | 265 | # Minimum number of public methods for a class (see R0903). 266 | min-public-methods=2 267 | 268 | # Maximum number of public methods for a class (see R0904). 269 | max-public-methods=20 270 | 271 | 272 | [CLASSES] 273 | 274 | # List of interface methods to ignore, separated by a comma. This is used for 275 | # instance to not check methods defines in Zope's Interface base class. 276 | ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by 277 | 278 | # List of method names used to declare (i.e. assign) instance attributes. 279 | defining-attr-methods=__init__,__new__,setUp 280 | 281 | # List of valid names for the first argument in a class method. 282 | valid-classmethod-first-arg=cls 283 | 284 | 285 | [IMPORTS] 286 | 287 | # Deprecated modules which should not be used, separated by a comma 288 | deprecated-modules=regsub,string,TERMIOS,Bastion,rexec 289 | 290 | # Create a graph of every (i.e. internal and external) dependencies in the 291 | # given file (report RP0402 must not be disabled) 292 | import-graph= 293 | 294 | # Create a graph of external dependencies in the given file (report RP0402 must 295 | # not be disabled) 296 | ext-import-graph= 297 | 298 | # Create a graph of internal dependencies in the given file (report RP0402 must 299 | # not be disabled) 300 | int-import-graph= 301 | 302 | 303 | [EXCEPTIONS] 304 | 305 | # Exceptions that will emit a warning when being caught. Defaults to 306 | # "Exception" 307 | overgeneral-exceptions=Exception 308 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | 5 | install: 6 | - npm install grunt-cli -g 7 | - npm install bower -g 8 | - sudo pip install pylint 9 | 10 | before_script: 11 | - pylint --version 12 | 13 | script: 14 | - pylint tools/packing.py 15 | - cd app && npm install && grunt test 16 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people that have contributed to BeagleTerm project. 2 | # Names should be added to the list like so: 3 | # 4 | # Name 5 | 6 | Emanuele Ziglioli 7 | Jungil Han 8 | Sungguk Lim 9 | Tyler Hughes <> 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | CONTRIBUTING to BeagleTerm 2 | ========================== 3 | 4 | ## Coding style 5 | 6 | * JS follows the [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml) 7 | * HTML and CSS follow the [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.xml) 8 | * Python follows the [PEP-8](https://www.python.org/dev/peps/pep-0008/) except: 9 | - Use two-space indentation instead of four-space indentation. 10 | - Use `CamelCase()` method and function names instead of `unix_hacker_style()` names. 11 | 12 | ## Languages 13 | 14 | * Use HTML, CSS, JS and Python. 15 | * Shell script is not allowed. 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Sungguk Lim. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | * Neither the name of Sungguk Lim. nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Beagle Term for Serial Communication 2 | ====================================== 3 | [![Build Status -](https://travis-ci.org/beagleterm/beagle-term.svg?branch=master)](https://travis-ci.org/beagleterm/beagle-term) 4 | 5 | ![beagleterm#1](https://lh4.googleusercontent.com/-uQd3jpSrk4w/UHwzxcomb6I/AAAAAAAAGWU/10HMI257zcQ/s580/beagleterm.png) 6 | 7 | 8 | 9 | Install 10 | --------- 11 | Now you can download directly from Chrome Web Store. 12 | * https://chrome.google.com/webstore/detail/beagle-term/gkdofhllgfohlddimiiildbgoggdpoea 13 | 14 | Dev 15 | --- 16 | * `cd app` and run `npm install` to get dependencies. 17 | * Load `/app` as unpacked extension. 18 | * Saved changes and refreshing the app on `chrome://extension`. 19 | * Running the `grunt` command will use jshint to check for any bugs in the project's code. 20 | 21 | This application .. 22 | ---------------------- 23 | * is a kind of Chrome packaged app. 24 | * Supports RS232 (Serial) 25 | * Even supports VT100 26 | * No browser plugins required! 27 | * [Demo Video](http://youtu.be/V6lQcjd6fHs) 28 | 29 | License 30 | ---------- 31 | * BSD license. 32 | 33 | Community 34 | --------- 35 | Join us in our [slack room](https://beagleterm.herokuapp.com/) 36 | -------------------------------------------------------------------------------- /aa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beagleterm/beagle-term/40399af489cc6e23d928884598d95c8e14d19420/aa.jpg -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | *.swo 2 | *.swp 3 | *~ 4 | bower_components/ 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /app/.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "google" 3 | } 4 | -------------------------------------------------------------------------------- /app/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: '', 6 | jshint: { 7 | all: { 8 | src: ['js/*.js'] 9 | } 10 | }, 11 | jscs: { 12 | src: ['Gruntfile.js', 'js/*.js'], 13 | options: { 14 | config: '.jscsrc', 15 | fix: true 16 | } 17 | }, 18 | watch: { 19 | files: ['js/index.js', 'js/background.js'], 20 | tasks: ['jshint', 'jscs'] 21 | } 22 | }); 23 | 24 | grunt.loadNpmTasks('grunt-contrib-jshint'); 25 | grunt.loadNpmTasks('grunt-contrib-watch'); 26 | grunt.loadNpmTasks('grunt-jscs'); 27 | 28 | // Default task. 29 | grunt.registerTask('default', ['jshint', 'jscs', 'watch']); 30 | 31 | // Test task 32 | grunt.registerTask('test', ['jshint', 'jscs']); 33 | }; 34 | -------------------------------------------------------------------------------- /app/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beagleterm", 3 | "homepage": "https://github.com/beagleterm/beagle-term", 4 | "dependencies": { 5 | "bootstrap": "^3.3.7" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/css/main.css: -------------------------------------------------------------------------------- 1 | #terminal { 2 | background-color: #1E1E1E; 3 | width: 100%; 4 | min-height: 100vh; 5 | margin: 0; 6 | padding: 0; 7 | color: #B2B2B2; 8 | } 9 | -------------------------------------------------------------------------------- /app/images/beagleterm-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beagleterm/beagle-term/40399af489cc6e23d928884598d95c8e14d19420/app/images/beagleterm-128.png -------------------------------------------------------------------------------- /app/images/beagleterm-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beagleterm/beagle-term/40399af489cc6e23d928884598d95c8e14d19420/app/images/beagleterm-16.png -------------------------------------------------------------------------------- /app/images/beagleterm-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beagleterm/beagle-term/40399af489cc6e23d928884598d95c8e14d19420/app/images/beagleterm-32.png -------------------------------------------------------------------------------- /app/images/beagleterm-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beagleterm/beagle-term/40399af489cc6e23d928884598d95c8e14d19420/app/images/beagleterm-48.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | BeagleTerm 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /app/js/background.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Sungguk Lim. Please see the AUTHORS file for details. 2 | // All rights reserved. Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | chrome.app.runtime.onLaunched.addListener(function() { 6 | new BeagleWindow(); 7 | }); 8 | 9 | var BeagleWindow = function() { 10 | var connectedSerialId = 0; 11 | chrome.app.window.create( 12 | 'index.html', 13 | { 14 | outerBounds: { 15 | width: 1024, 16 | height: 768 17 | } 18 | }, 19 | function(window) { 20 | window.contentWindow.AddConnectedSerialId = function(id) { 21 | connectedSerialId = id; 22 | }; 23 | window.onClosed.addListener(function() { 24 | chrome.serial.disconnect(connectedSerialId, function() { 25 | }); 26 | }); 27 | } 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /app/js/draw_ui.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, Sungguk Lim. Please see the AUTHORS file for details. 2 | // All rights reserved. Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | function DrawUi() {} 6 | 7 | DrawUi.prototype = { 8 | ShowSettingsDialog: function() { 9 | $('#settingsModal').modal('show'); 10 | }, 11 | 12 | /** 13 | * Called when Hterm terminmal is finished to load. 14 | * Every ui configuration(e.g. foo_button.focus() should be in here) 15 | */ 16 | OnHtermReady: function() { 17 | $('.modal-footer button').focus(); 18 | this.registerConnectBtnEvent_(); 19 | }, 20 | 21 | /** 22 | * @private 23 | */ 24 | registerConnectBtnEvent_: function() { 25 | var connectBtn = document.querySelector('#connectBtn'); 26 | connectBtn.addEventListener('click', function(event) { 27 | // Get the serial port (i.e. COM1, COM2, COM3, etc.) 28 | var portSelect = document.querySelector('#portDropdown'); 29 | var port = portSelect.options[portSelect.selectedIndex].value; 30 | 31 | // Get the baud rate (i.e. 9600, 38400, 57600, 115200, etc. ) 32 | var baudSelect = document.querySelector('#bitrateDropdown'); 33 | var bitrate = Number(baudSelect.options[baudSelect.selectedIndex].value); 34 | 35 | // Get the data bit (i.e. "seven" or "eight") 36 | var databitSelect = document.querySelector('#databitDropdown'); 37 | var databit = databitSelect.options[databitSelect.selectedIndex].value; 38 | 39 | // Get the parity bit (i.e. "no", "odd", or "even") 40 | var paritySelect = document.querySelector('#parityDropdown'); 41 | var parity = paritySelect.options[paritySelect.selectedIndex].value; 42 | 43 | // Get the stop bit (i.e. "one" or "two") 44 | var stopbitSelect = document.querySelector('#stopbitDropdown'); 45 | var stopbit = stopbitSelect.options[stopbitSelect.selectedIndex].value; 46 | 47 | // Get the flow control value (i.e. true or false) 48 | var fcSelect = document.querySelector('#flowControlDropdown'); 49 | var flowControlValue = fcSelect.options[fcSelect.selectedIndex].value; 50 | var flowControl = (flowControlValue === 'true'); 51 | 52 | // Format is ... 53 | // settings = Object {bitrate: 14400, dataBits: "eight", parityBit: "odd", 54 | // stopBits: "two", ctsFlowControl: true} 55 | var settings = { 56 | bitrate: bitrate, 57 | dataBits: databit, 58 | parityBit: parity, 59 | stopBits: stopbit, 60 | ctsFlowControl: flowControl 61 | }; 62 | 63 | chrome.storage.local.set(settings); 64 | 65 | chrome.serial.connect(port, { 66 | 'bitrate': settings.bitrate, 67 | 'dataBits': settings.dataBits, 68 | 'parityBit': settings.parityBit, 69 | 'stopBits': settings.stopBits, 70 | 'ctsFlowControl': settings.ctsFlowControl 71 | }, function(openInfo) { 72 | if (openInfo === undefined) { 73 | inputOutput.println('Unable to connect to device with value' + 74 | settings.toString()); 75 | // TODO: Open 'connection dialog' again. 76 | return; 77 | } 78 | 79 | inputOutput.println('Device found on ' + port + 80 | ' via Connection ID ' + openInfo.connectionId); 81 | self.connectionId = openInfo.connectionId; 82 | AddConnectedSerialId(openInfo.connectionId); 83 | chrome.serial.onReceive.addListener(function(info) { 84 | if (info && info.data) { 85 | inputOutput.print(ab2str(info.data)); 86 | } 87 | }); 88 | }); 89 | }); 90 | } 91 | }; 92 | -------------------------------------------------------------------------------- /app/js/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Sungguk Lim. Please see the AUTHORS file for details. 2 | // All rights reserved. Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | var inputOutput; 6 | var self; 7 | 8 | var UI_INSTANCE = new DrawUi(); 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | UI_INSTANCE.ShowSettingsDialog(); 12 | }, false); 13 | 14 | /* 15 | * Utility functions 16 | * 17 | * TODO: Extract to another file 18 | */ 19 | 20 | // Converts ArrayBuffer to String. 21 | var ab2str = function(buf) { 22 | var bufView = new Uint8Array(buf); 23 | var unis = []; 24 | for (var i = 0; i < bufView.length; i++) { 25 | unis.push(bufView[i]); 26 | } 27 | return String.fromCharCode.apply(null, unis); 28 | }; 29 | 30 | // Converts String to ArrayBuffer. 31 | var str2ab = function(str) { 32 | var buf = new ArrayBuffer(str.length); 33 | var bufView = new Uint8Array(buf); 34 | for (var i = 0; i < str.length; i++) { 35 | bufView[i] = str.charCodeAt(i); 36 | } 37 | return buf; 38 | }; 39 | 40 | var getIndexByValue = function(element, value) { 41 | var list = element.options; 42 | for (var i = 0; i < list.length; i++) { 43 | if (list[i].value === value) { 44 | return i; 45 | } 46 | } 47 | }; 48 | 49 | var Crosh = function(argv) { 50 | this.argv_ = argv; 51 | this.io = null; 52 | this.keyboard_ = null; 53 | this.pid_ = -1; 54 | this.connectionId = -1; 55 | this.portInfo_ = null; 56 | this.run = function() { 57 | this.io = this.argv_.io.push(); 58 | 59 | this.io.onVTKeystroke = this.sendString_.bind(this, true /* fromKeyboard */); 60 | this.io.sendString = this.sendString_.bind(this, false /* fromKeyboard */); 61 | this.io.println('Beagle Term. https://github.com/beagleterm/beagle-term'); 62 | inputOutput = this.io; 63 | self = this; 64 | 65 | chrome.serial.getDevices(function(ports) { 66 | if (ports.length > 0) { 67 | ports.forEach(function(portNames) { 68 | var portPicker = document.querySelector('#portDropdown'); 69 | var portName = portNames.path; 70 | portPicker.innerHTML = portPicker.innerHTML + ''; 72 | }); 73 | } 74 | }); 75 | 76 | // TODO: Pass json object instead of each element('bitrate', 'dataBits' ..) 77 | chrome.storage.local.get('bitrate', function(result) { 78 | var bitrateSelectElement = document.querySelector('#bitrateDropdown'); 79 | 80 | if (result.bitrate !== undefined) { 81 | bitrateSelectElement.selectedIndex = 82 | getIndexByValue(bitrateSelectElement, result.bitrate.toString()); 83 | } else { 84 | bitrateSelectElement.selectedIndex = 85 | getIndexByValue(bitrateSelectElement, '115200'); 86 | } 87 | }); 88 | 89 | chrome.storage.local.get('dataBits', function(result) { 90 | var databitSelectElement = document.querySelector('#databitDropdown'); 91 | 92 | if (result.dataBits !== undefined) { 93 | databitSelectElement.selectedIndex = 94 | getIndexByValue(databitSelectElement, result.dataBits); 95 | } else { 96 | databitSelectElement.selectedIndex = 97 | getIndexByValue(databitSelectElement, 'eight'); 98 | } 99 | }); 100 | 101 | chrome.storage.local.get('parityBit', function(result) { 102 | var paritybitSelectElement = document.querySelector('#parityDropdown'); 103 | 104 | if (result.parityBit !== undefined) { 105 | paritybitSelectElement.selectedIndex = 106 | getIndexByValue(paritybitSelectElement, result.parityBit); 107 | } else { 108 | paritybitSelectElement.selectedIndex = 109 | getIndexByValue(paritybitSelectElement, 'no'); 110 | } 111 | }); 112 | 113 | chrome.storage.local.get('stopBits', function(result) { 114 | var stopbitSelectElement = document.querySelector('#stopbitDropdown'); 115 | if (result.stopBits !== undefined) { 116 | stopbitSelectElement.selectedIndex = 117 | getIndexByValue(stopbitSelectElement, result.stopBits); 118 | } else { 119 | stopbitSelectElement.selectedIndex = 120 | getIndexByValue(stopbitSelectElement, 'one'); 121 | } 122 | }); 123 | 124 | chrome.storage.local.get('ctsFlowControl', function(result) { 125 | var fcSelectElement = document.querySelector('#flowControlDropdown'); 126 | if (result.ctsFlowControl !== undefined) { 127 | fcSelectElement.selectedIndex = 128 | getIndexByValue(fcSelectElement, result.ctsFlowControl.toString()); 129 | } else { 130 | fcSelectElement.selectedIndex = 131 | getIndexByValue(fcSelectElement, 'false'); 132 | } 133 | }); 134 | }; 135 | 136 | this.sendString_ = function(fromKeyboard, string) { 137 | chrome.serial.send(self.connectionId, str2ab(string), function() { }); 138 | }; 139 | 140 | this.exit = function(code) { 141 | }; 142 | }; 143 | 144 | window.onload = function() { 145 | hterm.defaultStorage = new lib.Storage.Chrome(chrome.storage.sync); 146 | var t = new hterm.Terminal('opt_profileName'); 147 | t.decorate(document.querySelector('#terminal')); 148 | 149 | t.onTerminalReady = function() { 150 | UI_INSTANCE.OnHtermReady(); 151 | t.runCommandClass(Crosh, document.location.hash.substr(1)); 152 | return true; 153 | }; 154 | }; 155 | -------------------------------------------------------------------------------- /app/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "minimum_chrome_version": "25", 3 | "manifest_version": 2, 4 | "name": "Beagle Term", 5 | "version": "1.8.3", 6 | "icons": { 7 | "128": "images/beagleterm-128.png", 8 | "48": "images/beagleterm-48.png", 9 | "32": "images/beagleterm-32.png", 10 | "16": "images/beagleterm-16.png" 11 | }, 12 | "description": "Beagle Term is serial terminal emulator.", 13 | "offline_enabled": true, 14 | "permissions": [ 15 | "serial", 16 | "storage" 17 | ], 18 | "app": { 19 | "background": { 20 | "scripts": ["js/background.js"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beagleterm", 3 | "version": "1.7.0", 4 | "description": "![Try it now in CWS](https://raw.github.com/GoogleChrome/chrome-app-samples/master/tryitnowbutton.png \"Click here to install this sample from the Chrome Web Store\")", 5 | "private": true, 6 | "main": "main.js", 7 | "scripts": { 8 | "postinstall": "bower install && find . -name \"*.pem\" -type f -delete" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/beagleterm/beagle-term.git" 13 | }, 14 | "author": "", 15 | "license": "BSD", 16 | "bugs": { 17 | "url": "https://github.com/beagleterm/beagle-term/issues" 18 | }, 19 | "homepage": "https://github.com/beagleterm/beagle-term", 20 | "devDependencies": { 21 | "grunt": "^1.0.1", 22 | "grunt-contrib-jshint": "^1.0.0", 23 | "grunt-contrib-watch": "^1.0.0", 24 | "grunt-jscs": "^3.0.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tools/packing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import shutil 5 | import subprocess 6 | from contextlib import contextmanager 7 | 8 | SOURCE_DIR = os.path.join(os.getcwd(), 'app') 9 | BUILD_DIR = os.path.join(os.getcwd(), 'build') 10 | 11 | @contextmanager 12 | def pushd(path): 13 | currentDir = os.getcwd() 14 | os.chdir(path) 15 | yield 16 | os.chdir(currentDir) 17 | 18 | def printInfo(message): 19 | print os.path.basename(__file__) + ' >> ' + message 20 | 21 | def installDependencies(): 22 | printInfo('Start bower install') 23 | with pushd('app'): 24 | subprocess.check_call('bower install', shell=True) 25 | 26 | def copy(src, des): 27 | printInfo('Copying ' + src + ' to ' + des) 28 | if os.path.isdir(src): 29 | shutil.copytree(src, des) 30 | else: 31 | if not os.path.exists(os.path.dirname(des)): 32 | os.makedirs(os.path.dirname(des)) 33 | shutil.copy2(src, des) 34 | 35 | def _zip(destFile): 36 | printInfo('Start zipping build directory') 37 | shutil.make_archive(destFile, 'zip', BUILD_DIR) 38 | printInfo('Created ' + destFile + '.zip') 39 | 40 | def copyDeployFiles(): 41 | if (os.path.exists(BUILD_DIR)): 42 | printInfo('Deleting existing ' + str(BUILD_DIR)) 43 | shutil.rmtree(BUILD_DIR) 44 | printInfo('Creating ' + str(BUILD_DIR)) 45 | os.makedirs(BUILD_DIR) 46 | 47 | copy_list = ['index.html', 'manifest.json', 'js/index.js', 'js/background.js', 48 | 'js/lib/hterm_all.min.js', 'css/main.css', 'images', 49 | 'bower_components/jquery/dist/jquery.min.js', 50 | 'bower_components/bootstrap/dist/js/bootstrap.min.js', 51 | 'bower_components/bootstrap/dist/css/bootstrap.min.css'] 52 | 53 | for single_file in copy_list: 54 | source_path = os.path.join(SOURCE_DIR, single_file) 55 | target_path = os.path.join(BUILD_DIR, single_file) 56 | copy(source_path, target_path) 57 | 58 | def main(): 59 | installDependencies() 60 | copyDeployFiles() 61 | # TODO: Minify js/index.js, js/background.js 62 | _zip('archive') 63 | 64 | if __name__ == '__main__': 65 | main() 66 | --------------------------------------------------------------------------------