From cf695e71d4180ef4f8518927bec37cee165e0cd0 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 10:49:49 -0700 Subject: [PATCH 01/38] Initial commit --- LICENSE | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 + 2 files changed, 343 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..22fbe5d --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c69f18f --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +ev3dev-NodeJS +============= + +EV3dev API language bindings for NodeJS From f4f32c1e6185cbcbd0584bb167b92589a3edc32a Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 10:51:09 -0700 Subject: [PATCH 02/38] Initial commit. Includes basic infrastructure and reading of motor properties. --- .gitignore | 1 + EV3Base.ts | 65 +++ Motor.ts | 34 ++ node.d.ts | 1296 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1396 insertions(+) create mode 100644 .gitignore create mode 100644 EV3Base.ts create mode 100644 Motor.ts create mode 100644 node.d.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c43fe6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.js \ No newline at end of file diff --git a/EV3Base.ts b/EV3Base.ts new file mode 100644 index 0000000..9483ff9 --- /dev/null +++ b/EV3Base.ts @@ -0,0 +1,65 @@ +/// +var fs = require("fs"); +var path = require('path'); + +module FilePathConstructor { + var motorDeviceDir: string = '/sys/class/tacho-motor/'; + var motorDirName: string = 'out{0}:motor:tacho'; + + export function motor(port: MotorPort) { + return path.join(motorDeviceDir, motorDirName.format(MotorPort[port]), '/'); + } + + export function motorProperty(port: MotorPort, property: MotorProperty) { + return path.join(motor(port), MotorProperty[property]); + } +} + +interface String { + format(...args: any[]): string +} + +String.prototype.format = function () { + var args = arguments; + return this.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != 'undefined' + ? args[number] + : match + ; + }); +}; + +enum MotorPort { + A, B, C, D +} + +enum MotorProperty { + device, + state, + target_speed, + direction, + stop_mode, + target_steer, + mode, + subsystem, + target_tacho, + power, + tacho, + target_time, + ramp_mode, + tacho_mode, + target_total_count, + regulation_mode, + target_power, + time, + run, + target_ramp_down_count, + type, + speed, + target_ramp_up_count, + uevent +} + +module.exports.FilePathConstructor = FilePathConstructor; +module.exports.MotorPort = MotorPort; +module.exports.MotorProperty = MotorProperty; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts new file mode 100644 index 0000000..e2ed828 --- /dev/null +++ b/Motor.ts @@ -0,0 +1,34 @@ +/// +/// + +var fs = require("fs"); +var base = require("./EV3Base.js"); + +var FilePathConstructor = base.FilePathConstructor; +var MotorPort = base.MotorPort; +var MotorProperty = base.MotorProperty; + +class Motor { + private port: MotorPort + + get speed(): number { + return parseInt(this.readProperty(MotorProperty.speed)); + } + + get position(): number { + var propertyPath: string = FilePathConstructor.motorProperty(this.port, MotorProperty.position); + return parseInt(fs.readFileSync(propertyPath).toString()); + } + + private readProperty(property: MotorProperty): string { + var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); + return fs.readFileSync(propertyPath).toString().match(/[0-9]+/)[0]; + } + + constructor(port: MotorPort) { + this.port = port; + } +} + +module.exports = Motor; +module.exports.MotorPort = base.MotorPort; \ No newline at end of file diff --git a/node.d.ts b/node.d.ts new file mode 100644 index 0000000..a508ef5 --- /dev/null +++ b/node.d.ts @@ -0,0 +1,1296 @@ +// Type definitions for Node.js v0.10.1 +// Project: http://nodejs.org/ +// Definitions by: Microsoft TypeScript , DefinitelyTyped +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/************************************************ +* * +* Node.js v0.10.1 API * +* * +************************************************/ + +/************************************************ +* * +* GLOBAL * +* * +************************************************/ +declare var process: NodeJS.Process; +declare var global: any; + +declare var __filename: string; +declare var __dirname: string; + +declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; +declare function clearTimeout(timeoutId: NodeJS.Timer): void; +declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; +declare function clearInterval(intervalId: NodeJS.Timer): void; +declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; +declare function clearImmediate(immediateId: any): void; + +declare var require: { + (id: string): any; + resolve(id:string): string; + cache: any; + extensions: any; + main: any; +}; + +declare var module: { + exports: any; + require(id: string): any; + id: string; + filename: string; + loaded: boolean; + parent: any; + children: any[]; +}; + +// Same as module.exports +declare var exports: any; +declare var SlowBuffer: { + new (str: string, encoding?: string): Buffer; + new (size: number): Buffer; + new (array: any[]): Buffer; + prototype: Buffer; + isBuffer(obj: any): boolean; + byteLength(string: string, encoding?: string): number; + concat(list: Buffer[], totalLength?: number): Buffer; +}; + + +// Buffer class +interface Buffer extends NodeBuffer {} +declare var Buffer: { + new (str: string, encoding?: string): Buffer; + new (size: number): Buffer; + new (array: any[]): Buffer; + prototype: Buffer; + isBuffer(obj: any): boolean; + byteLength(string: string, encoding?: string): number; + concat(list: Buffer[], totalLength?: number): Buffer; +}; + +/************************************************ +* * +* GLOBAL INTERFACES * +* * +************************************************/ +declare module NodeJS { + export interface ErrnoException extends Error { + errno?: any; + code?: string; + path?: string; + syscall?: string; + } + + export interface EventEmitter { + addListener(event: string, listener: Function): EventEmitter; + on(event: string, listener: Function): EventEmitter; + once(event: string, listener: Function): EventEmitter; + removeListener(event: string, listener: Function): EventEmitter; + removeAllListeners(event?: string): EventEmitter; + setMaxListeners(n: number): void; + listeners(event: string): Function[]; + emit(event: string, ...args: any[]): boolean; + } + + export interface ReadableStream extends EventEmitter { + readable: boolean; + read(size?: number): any; + setEncoding(encoding: string): void; + pause(): void; + resume(): void; + pipe(destination: T, options?: { end?: boolean; }): T; + unpipe(destination?: T): void; + unshift(chunk: string): void; + unshift(chunk: Buffer): void; + wrap(oldStream: ReadableStream): ReadableStream; + } + + export interface WritableStream extends EventEmitter { + writable: boolean; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export interface ReadWriteStream extends ReadableStream, WritableStream {} + + export interface Process extends EventEmitter { + stdout: WritableStream; + stderr: WritableStream; + stdin: ReadableStream; + argv: string[]; + execPath: string; + abort(): void; + chdir(directory: string): void; + cwd(): string; + env: any; + exit(code?: number): void; + getgid(): number; + setgid(id: number): void; + setgid(id: string): void; + getuid(): number; + setuid(id: number): void; + setuid(id: string): void; + version: string; + versions: { + http_parser: string; + node: string; + v8: string; + ares: string; + uv: string; + zlib: string; + openssl: string; + }; + config: { + target_defaults: { + cflags: any[]; + default_configuration: string; + defines: string[]; + include_dirs: string[]; + libraries: string[]; + }; + variables: { + clang: number; + host_arch: string; + node_install_npm: boolean; + node_install_waf: boolean; + node_prefix: string; + node_shared_openssl: boolean; + node_shared_v8: boolean; + node_shared_zlib: boolean; + node_use_dtrace: boolean; + node_use_etw: boolean; + node_use_openssl: boolean; + target_arch: string; + v8_no_strict_aliasing: number; + v8_use_snapshot: boolean; + visibility: string; + }; + }; + kill(pid: number, signal?: string): void; + pid: number; + title: string; + arch: string; + platform: string; + memoryUsage(): { rss: number; heapTotal: number; heapUsed: number; }; + nextTick(callback: Function): void; + umask(mask?: number): number; + uptime(): number; + hrtime(time?:number[]): number[]; + + // Worker + send?(message: any, sendHandle?: any): void; + } + + export interface Timer { + ref() : void; + unref() : void; + } +} + +/** + * @deprecated + */ +interface NodeBuffer { + [index: number]: number; + write(string: string, offset?: number, length?: number, encoding?: string): number; + toString(encoding?: string, start?: number, end?: number): string; + toJSON(): any; + length: number; + copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; + slice(start?: number, end?: number): Buffer; + readUInt8(offset: number, noAsset?: boolean): number; + readUInt16LE(offset: number, noAssert?: boolean): number; + readUInt16BE(offset: number, noAssert?: boolean): number; + readUInt32LE(offset: number, noAssert?: boolean): number; + readUInt32BE(offset: number, noAssert?: boolean): number; + readInt8(offset: number, noAssert?: boolean): number; + readInt16LE(offset: number, noAssert?: boolean): number; + readInt16BE(offset: number, noAssert?: boolean): number; + readInt32LE(offset: number, noAssert?: boolean): number; + readInt32BE(offset: number, noAssert?: boolean): number; + readFloatLE(offset: number, noAssert?: boolean): number; + readFloatBE(offset: number, noAssert?: boolean): number; + readDoubleLE(offset: number, noAssert?: boolean): number; + readDoubleBE(offset: number, noAssert?: boolean): number; + writeUInt8(value: number, offset: number, noAssert?: boolean): void; + writeUInt16LE(value: number, offset: number, noAssert?: boolean): void; + writeUInt16BE(value: number, offset: number, noAssert?: boolean): void; + writeUInt32LE(value: number, offset: number, noAssert?: boolean): void; + writeUInt32BE(value: number, offset: number, noAssert?: boolean): void; + writeInt8(value: number, offset: number, noAssert?: boolean): void; + writeInt16LE(value: number, offset: number, noAssert?: boolean): void; + writeInt16BE(value: number, offset: number, noAssert?: boolean): void; + writeInt32LE(value: number, offset: number, noAssert?: boolean): void; + writeInt32BE(value: number, offset: number, noAssert?: boolean): void; + writeFloatLE(value: number, offset: number, noAssert?: boolean): void; + writeFloatBE(value: number, offset: number, noAssert?: boolean): void; + writeDoubleLE(value: number, offset: number, noAssert?: boolean): void; + writeDoubleBE(value: number, offset: number, noAssert?: boolean): void; + fill(value: any, offset?: number, end?: number): void; +} + +/************************************************ +* * +* MODULES * +* * +************************************************/ +declare module "buffer" { + export var INSPECT_MAX_BYTES: number; +} + +declare module "querystring" { + export function stringify(obj: any, sep?: string, eq?: string): string; + export function parse(str: string, sep?: string, eq?: string, options?: { maxKeys?: number; }): any; + export function escape(): any; + export function unescape(): any; +} + +declare module "events" { + export class EventEmitter implements NodeJS.EventEmitter { + static listenerCount(emitter: EventEmitter, event: string): number; + + addListener(event: string, listener: Function): EventEmitter; + on(event: string, listener: Function): EventEmitter; + once(event: string, listener: Function): EventEmitter; + removeListener(event: string, listener: Function): EventEmitter; + removeAllListeners(event?: string): EventEmitter; + setMaxListeners(n: number): void; + listeners(event: string): Function[]; + emit(event: string, ...args: any[]): boolean; + } +} + +declare module "http" { + import events = require("events"); + import net = require("net"); + import stream = require("stream"); + + export interface Server extends events.EventEmitter { + listen(port: number, hostname?: string, backlog?: number, callback?: Function): Server; + listen(path: string, callback?: Function): Server; + listen(handle: any, listeningListener?: Function): Server; + close(cb?: any): Server; + address(): { port: number; family: string; address: string; }; + maxHeadersCount: number; + } + export interface ServerRequest extends events.EventEmitter, stream.Readable { + method: string; + url: string; + headers: any; + trailers: string; + httpVersion: string; + setEncoding(encoding?: string): void; + pause(): void; + resume(): void; + connection: net.Socket; + } + export interface ServerResponse extends events.EventEmitter, stream.Writable { + // Extended base methods + write(buffer: Buffer): boolean; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + write(str: string, encoding?: string, fd?: string): boolean; + + writeContinue(): void; + writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void; + writeHead(statusCode: number, headers?: any): void; + statusCode: number; + setHeader(name: string, value: string): void; + sendDate: boolean; + getHeader(name: string): string; + removeHeader(name: string): void; + write(chunk: any, encoding?: string): any; + addTrailers(headers: any): void; + + // Extended base methods + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + end(data?: any, encoding?: string): void; + } + export interface ClientRequest extends events.EventEmitter, stream.Writable { + // Extended base methods + write(buffer: Buffer): boolean; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + write(str: string, encoding?: string, fd?: string): boolean; + + write(chunk: any, encoding?: string): void; + abort(): void; + setTimeout(timeout: number, callback?: Function): void; + setNoDelay(noDelay?: boolean): void; + setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; + + // Extended base methods + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + end(data?: any, encoding?: string): void; + } + export interface ClientResponse extends events.EventEmitter, stream.Readable { + statusCode: number; + httpVersion: string; + headers: any; + trailers: any; + setEncoding(encoding?: string): void; + pause(): void; + resume(): void; + } + export interface Agent { maxSockets: number; sockets: any; requests: any; } + + export var STATUS_CODES: { + [errorCode: number]: string; + [errorCode: string]: string; + }; + export function createServer(requestListener?: (request: ServerRequest, response: ServerResponse) =>void ): Server; + export function createClient(port?: number, host?: string): any; + export function request(options: any, callback?: Function): ClientRequest; + export function get(options: any, callback?: Function): ClientRequest; + export var globalAgent: Agent; +} + +declare module "cluster" { + import child = require("child_process"); + import events = require("events"); + + export interface ClusterSettings { + exec?: string; + args?: string[]; + silent?: boolean; + } + + export class Worker extends events.EventEmitter { + id: string; + process: child.ChildProcess; + suicide: boolean; + send(message: any, sendHandle?: any): void; + kill(signal?: string): void; + destroy(signal?: string): void; + disconnect(): void; + } + + export var settings: ClusterSettings; + export var isMaster: boolean; + export var isWorker: boolean; + export function setupMaster(settings?: ClusterSettings): void; + export function fork(env?: any): Worker; + export function disconnect(callback?: Function): void; + export var worker: Worker; + export var workers: Worker[]; + + // Event emitter + export function addListener(event: string, listener: Function): void; + export function on(event: string, listener: Function): any; + export function once(event: string, listener: Function): void; + export function removeListener(event: string, listener: Function): void; + export function removeAllListeners(event?: string): void; + export function setMaxListeners(n: number): void; + export function listeners(event: string): Function[]; + export function emit(event: string, ...args: any[]): boolean; +} + +declare module "zlib" { + import stream = require("stream"); + export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } + + export interface Gzip extends stream.Transform { } + export interface Gunzip extends stream.Transform { } + export interface Deflate extends stream.Transform { } + export interface Inflate extends stream.Transform { } + export interface DeflateRaw extends stream.Transform { } + export interface InflateRaw extends stream.Transform { } + export interface Unzip extends stream.Transform { } + + export function createGzip(options?: ZlibOptions): Gzip; + export function createGunzip(options?: ZlibOptions): Gunzip; + export function createDeflate(options?: ZlibOptions): Deflate; + export function createInflate(options?: ZlibOptions): Inflate; + export function createDeflateRaw(options?: ZlibOptions): DeflateRaw; + export function createInflateRaw(options?: ZlibOptions): InflateRaw; + export function createUnzip(options?: ZlibOptions): Unzip; + + export function deflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + export function deflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + export function gzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + export function gunzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + export function inflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + export function inflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + export function unzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; + + // Constants + export var Z_NO_FLUSH: number; + export var Z_PARTIAL_FLUSH: number; + export var Z_SYNC_FLUSH: number; + export var Z_FULL_FLUSH: number; + export var Z_FINISH: number; + export var Z_BLOCK: number; + export var Z_TREES: number; + export var Z_OK: number; + export var Z_STREAM_END: number; + export var Z_NEED_DICT: number; + export var Z_ERRNO: number; + export var Z_STREAM_ERROR: number; + export var Z_DATA_ERROR: number; + export var Z_MEM_ERROR: number; + export var Z_BUF_ERROR: number; + export var Z_VERSION_ERROR: number; + export var Z_NO_COMPRESSION: number; + export var Z_BEST_SPEED: number; + export var Z_BEST_COMPRESSION: number; + export var Z_DEFAULT_COMPRESSION: number; + export var Z_FILTERED: number; + export var Z_HUFFMAN_ONLY: number; + export var Z_RLE: number; + export var Z_FIXED: number; + export var Z_DEFAULT_STRATEGY: number; + export var Z_BINARY: number; + export var Z_TEXT: number; + export var Z_ASCII: number; + export var Z_UNKNOWN: number; + export var Z_DEFLATED: number; + export var Z_NULL: number; +} + +declare module "os" { + export function tmpDir(): string; + export function hostname(): string; + export function type(): string; + export function platform(): string; + export function arch(): string; + export function release(): string; + export function uptime(): number; + export function loadavg(): number[]; + export function totalmem(): number; + export function freemem(): number; + export function cpus(): { model: string; speed: number; times: { user: number; nice: number; sys: number; idle: number; irq: number; }; }[]; + export function networkInterfaces(): any; + export var EOL: string; +} + +declare module "https" { + import tls = require("tls"); + import events = require("events"); + import http = require("http"); + + export interface ServerOptions { + pfx?: any; + key?: any; + passphrase?: string; + cert?: any; + ca?: any; + crl?: any; + ciphers?: string; + honorCipherOrder?: boolean; + requestCert?: boolean; + rejectUnauthorized?: boolean; + NPNProtocols?: any; + SNICallback?: (servername: string) => any; + } + + export interface RequestOptions { + host?: string; + hostname?: string; + port?: number; + path?: string; + method?: string; + headers?: any; + auth?: string; + agent?: any; + pfx?: any; + key?: any; + passphrase?: string; + cert?: any; + ca?: any; + ciphers?: string; + rejectUnauthorized?: boolean; + } + + export interface Agent { + maxSockets: number; + sockets: any; + requests: any; + } + export var Agent: { + new (options?: RequestOptions): Agent; + }; + export interface Server extends tls.Server { } + export function createServer(options: ServerOptions, requestListener?: Function): Server; + export function request(options: RequestOptions, callback?: (res: events.EventEmitter) =>void ): http.ClientRequest; + export function get(options: RequestOptions, callback?: (res: events.EventEmitter) =>void ): http.ClientRequest; + export var globalAgent: Agent; +} + +declare module "punycode" { + export function decode(string: string): string; + export function encode(string: string): string; + export function toUnicode(domain: string): string; + export function toASCII(domain: string): string; + export var ucs2: ucs2; + interface ucs2 { + decode(string: string): string; + encode(codePoints: number[]): string; + } + export var version: any; +} + +declare module "repl" { + import stream = require("stream"); + import events = require("events"); + + export interface ReplOptions { + prompt?: string; + input?: NodeJS.ReadableStream; + output?: NodeJS.WritableStream; + terminal?: boolean; + eval?: Function; + useColors?: boolean; + useGlobal?: boolean; + ignoreUndefined?: boolean; + writer?: Function; + } + export function start(options: ReplOptions): events.EventEmitter; +} + +declare module "readline" { + import events = require("events"); + import stream = require("stream"); + + export interface ReadLine extends events.EventEmitter { + setPrompt(prompt: string, length: number): void; + prompt(preserveCursor?: boolean): void; + question(query: string, callback: Function): void; + pause(): void; + resume(): void; + close(): void; + write(data: any, key?: any): void; + } + export interface ReadLineOptions { + input: NodeJS.ReadableStream; + output: NodeJS.WritableStream; + completer?: Function; + terminal?: boolean; + } + export function createInterface(options: ReadLineOptions): ReadLine; +} + +declare module "vm" { + export interface Context { } + export interface Script { + runInThisContext(): void; + runInNewContext(sandbox?: Context): void; + } + export function runInThisContext(code: string, filename?: string): void; + export function runInNewContext(code: string, sandbox?: Context, filename?: string): void; + export function runInContext(code: string, context: Context, filename?: string): void; + export function createContext(initSandbox?: Context): Context; + export function createScript(code: string, filename?: string): Script; +} + +declare module "child_process" { + import events = require("events"); + import stream = require("stream"); + + export interface ChildProcess extends events.EventEmitter { + stdin: stream.Writable; + stdout: stream.Readable; + stderr: stream.Readable; + pid: number; + kill(signal?: string): void; + send(message: any, sendHandle: any): void; + disconnect(): void; + } + + export function spawn(command: string, args?: string[], options?: { + cwd?: string; + stdio?: any; + custom?: any; + env?: any; + detached?: boolean; + }): ChildProcess; + export function exec(command: string, options: { + cwd?: string; + stdio?: any; + customFds?: any; + env?: any; + encoding?: string; + timeout?: number; + maxBuffer?: number; + killSignal?: string; + }, callback: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; + export function exec(command: string, callback: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; + export function execFile(file: string, args: string[], options: { + cwd?: string; + stdio?: any; + customFds?: any; + env?: any; + encoding?: string; + timeout?: number; + maxBuffer?: string; + killSignal?: string; + }, callback: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; + export function fork(modulePath: string, args?: string[], options?: { + cwd?: string; + env?: any; + encoding?: string; + }): ChildProcess; +} + +declare module "url" { + export interface Url { + href: string; + protocol: string; + auth: string; + hostname: string; + port: string; + host: string; + pathname: string; + search: string; + query: string; + slashes: boolean; + hash?: string; + path?: string; + } + + export interface UrlOptions { + protocol?: string; + auth?: string; + hostname?: string; + port?: string; + host?: string; + pathname?: string; + search?: string; + query?: any; + hash?: string; + path?: string; + } + + export function parse(urlStr: string, parseQueryString?: boolean , slashesDenoteHost?: boolean ): Url; + export function format(url: UrlOptions): string; + export function resolve(from: string, to: string): string; +} + +declare module "dns" { + export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) =>void ): string; + export function lookup(domain: string, callback: (err: Error, address: string, family: number) =>void ): string; + export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolve(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolve4(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolve6(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; + export function reverse(ip: string, callback: (err: Error, domains: string[]) =>void ): string[]; +} + +declare module "net" { + import stream = require("stream"); + + export interface Socket extends stream.Duplex { + // Extended base methods + write(buffer: Buffer): boolean; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + write(str: string, encoding?: string, fd?: string): boolean; + + connect(port: number, host?: string, connectionListener?: Function): void; + connect(path: string, connectionListener?: Function): void; + bufferSize: number; + setEncoding(encoding?: string): void; + write(data: any, encoding?: string, callback?: Function): void; + destroy(): void; + pause(): void; + resume(): void; + setTimeout(timeout: number, callback?: Function): void; + setNoDelay(noDelay?: boolean): void; + setKeepAlive(enable?: boolean, initialDelay?: number): void; + address(): { port: number; family: string; address: string; }; + remoteAddress: string; + remotePort: number; + bytesRead: number; + bytesWritten: number; + + // Extended base methods + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + end(data?: any, encoding?: string): void; + } + + export var Socket: { + new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket; + }; + + export interface Server extends Socket { + listen(port: number, host?: string, backlog?: number, listeningListener?: Function): Server; + listen(path: string, listeningListener?: Function): Server; + listen(handle: any, listeningListener?: Function): Server; + close(callback?: Function): Server; + address(): { port: number; family: string; address: string; }; + maxConnections: number; + connections: number; + } + export function createServer(connectionListener?: (socket: Socket) =>void ): Server; + export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) =>void ): Server; + export function connect(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; + export function connect(port: number, host?: string, connectionListener?: Function): Socket; + export function connect(path: string, connectionListener?: Function): Socket; + export function createConnection(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; + export function createConnection(port: number, host?: string, connectionListener?: Function): Socket; + export function createConnection(path: string, connectionListener?: Function): Socket; + export function isIP(input: string): number; + export function isIPv4(input: string): boolean; + export function isIPv6(input: string): boolean; +} + +declare module "dgram" { + import events = require("events"); + + export function createSocket(type: string, callback?: Function): Socket; + + interface Socket extends events.EventEmitter { + send(buf: Buffer, offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; + bind(port: number, address?: string, callback?: () => void): void; + close(): void; + address: { address: string; family: string; port: number; }; + setBroadcast(flag: boolean): void; + setMulticastTTL(ttl: number): void; + setMulticastLoopback(flag: boolean): void; + addMembership(multicastAddress: string, multicastInterface?: string): void; + dropMembership(multicastAddress: string, multicastInterface?: string): void; + } +} + +declare module "fs" { + import stream = require("stream"); + import events = require("events"); + + interface Stats { + isFile(): boolean; + isDirectory(): boolean; + isBlockDevice(): boolean; + isCharacterDevice(): boolean; + isSymbolicLink(): boolean; + isFIFO(): boolean; + isSocket(): boolean; + dev: number; + ino: number; + mode: number; + nlink: number; + uid: number; + gid: number; + rdev: number; + size: number; + blksize: number; + blocks: number; + atime: Date; + mtime: Date; + ctime: Date; + } + + interface FSWatcher extends events.EventEmitter { + close(): void; + } + + export interface ReadStream extends stream.Readable {} + export interface WriteStream extends stream.Writable {} + + export function rename(oldPath: string, newPath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function renameSync(oldPath: string, newPath: string): void; + export function truncate(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function truncate(path: string, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function truncateSync(path: string, len?: number): void; + export function ftruncate(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function ftruncate(fd: number, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function ftruncateSync(fd: number, len?: number): void; + export function chown(path: string, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function chownSync(path: string, uid: number, gid: number): void; + export function fchown(fd: number, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function fchownSync(fd: number, uid: number, gid: number): void; + export function lchown(path: string, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function lchownSync(path: string, uid: number, gid: number): void; + export function chmod(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function chmod(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function chmodSync(path: string, mode: number): void; + export function chmodSync(path: string, mode: string): void; + export function fchmod(fd: number, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function fchmod(fd: number, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function fchmodSync(fd: number, mode: number): void; + export function fchmodSync(fd: number, mode: string): void; + export function lchmod(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function lchmod(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function lchmodSync(path: string, mode: number): void; + export function lchmodSync(path: string, mode: string): void; + export function stat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; + export function lstat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; + export function fstat(fd: number, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; + export function statSync(path: string): Stats; + export function lstatSync(path: string): Stats; + export function fstatSync(fd: number): Stats; + export function link(srcpath: string, dstpath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function linkSync(srcpath: string, dstpath: string): void; + export function symlink(srcpath: string, dstpath: string, type?: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function symlinkSync(srcpath: string, dstpath: string, type?: string): void; + export function readlink(path: string, callback?: (err: NodeJS.ErrnoException, linkString: string) => any): void; + export function readlinkSync(path: string): string; + export function realpath(path: string, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; + export function realpath(path: string, cache: {[path: string]: string}, callback: (err: NodeJS.ErrnoException, resolvedPath: string) =>any): void; + export function realpathSync(path: string, cache?: {[path: string]: string}): string; + export function unlink(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function unlinkSync(path: string): void; + export function rmdir(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function rmdirSync(path: string): void; + export function mkdir(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function mkdir(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function mkdir(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function mkdirSync(path: string, mode?: number): void; + export function mkdirSync(path: string, mode?: string): void; + export function readdir(path: string, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void; + export function readdirSync(path: string): string[]; + export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function closeSync(fd: number): void; + export function open(path: string, flags: string, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; + export function open(path: string, flags: string, mode: number, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; + export function open(path: string, flags: string, mode: string, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; + export function openSync(path: string, flags: string, mode?: number): number; + export function openSync(path: string, flags: string, mode?: string): number; + export function utimes(path: string, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function utimes(path: string, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function utimesSync(path: string, atime: number, mtime: number): void; + export function utimesSync(path: string, atime: Date, mtime: Date): void; + export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function futimes(fd: number, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function futimesSync(fd: number, atime: number, mtime: number): void; + export function futimesSync(fd: number, atime: Date, mtime: Date): void; + export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; + export function fsyncSync(fd: number): void; + export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; + export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; + export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void; + export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; + export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void; + export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void; + export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; + export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void ): void; + export function readFileSync(filename: string, encoding: string): string; + export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; + export function readFileSync(filename: string, options?: { flag?: string; }): Buffer; + export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; + export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; + export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; + export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; + export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; + export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; + export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; + export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; + export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void; + export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void; + export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void; + export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher; + export function watch(filename: string, options: { persistent?: boolean; }, listener?: (event: string, filename: string) => any): FSWatcher; + export function exists(path: string, callback?: (exists: boolean) => void): void; + export function existsSync(path: string): boolean; + export function createReadStream(path: string, options?: { + flags?: string; + encoding?: string; + fd?: string; + mode?: number; + bufferSize?: number; + }): ReadStream; + export function createReadStream(path: string, options?: { + flags?: string; + encoding?: string; + fd?: string; + mode?: string; + bufferSize?: number; + }): ReadStream; + export function createWriteStream(path: string, options?: { + flags?: string; + encoding?: string; + string?: string; + }): WriteStream; +} + +declare module "path" { + export function normalize(p: string): string; + export function join(...paths: any[]): string; + export function resolve(...pathSegments: any[]): string; + export function relative(from: string, to: string): string; + export function dirname(p: string): string; + export function basename(p: string, ext?: string): string; + export function extname(p: string): string; + export var sep: string; +} + +declare module "string_decoder" { + export interface NodeStringDecoder { + write(buffer: Buffer): string; + detectIncompleteChar(buffer: Buffer): number; + } + export var StringDecoder: { + new (encoding: string): NodeStringDecoder; + }; +} + +declare module "tls" { + import crypto = require("crypto"); + import net = require("net"); + import stream = require("stream"); + + var CLIENT_RENEG_LIMIT: number; + var CLIENT_RENEG_WINDOW: number; + + export interface TlsOptions { + pfx?: any; //string or buffer + key?: any; //string or buffer + passphrase?: string; + cert?: any; + ca?: any; //string or buffer + crl?: any; //string or string array + ciphers?: string; + honorCipherOrder?: any; + requestCert?: boolean; + rejectUnauthorized?: boolean; + NPNProtocols?: any; //array or Buffer; + SNICallback?: (servername: string) => any; + } + + export interface ConnectionOptions { + host?: string; + port?: number; + socket?: net.Socket; + pfx?: any; //string | Buffer + key?: any; //string | Buffer + passphrase?: string; + cert?: any; //string | Buffer + ca?: any; //Array of string | Buffer + rejectUnauthorized?: boolean; + NPNProtocols?: any; //Array of string | Buffer + servername?: string; + } + + export interface Server extends net.Server { + // Extended base methods + listen(port: number, host?: string, backlog?: number, listeningListener?: Function): Server; + listen(path: string, listeningListener?: Function): Server; + listen(handle: any, listeningListener?: Function): Server; + + listen(port: number, host?: string, callback?: Function): Server; + close(): Server; + address(): { port: number; family: string; address: string; }; + addContext(hostName: string, credentials: { + key: string; + cert: string; + ca: string; + }): void; + maxConnections: number; + connections: number; + } + + export interface ClearTextStream extends stream.Duplex { + authorized: boolean; + authorizationError: Error; + getPeerCertificate(): any; + getCipher: { + name: string; + version: string; + }; + address: { + port: number; + family: string; + address: string; + }; + remoteAddress: string; + remotePort: number; + } + + export interface SecurePair { + encrypted: any; + cleartext: any; + } + + export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) =>void ): Server; + export function connect(options: TlsOptions, secureConnectionListener?: () =>void ): ClearTextStream; + export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; + export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; + export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; +} + +declare module "crypto" { + export interface CredentialDetails { + pfx: string; + key: string; + passphrase: string; + cert: string; + ca: any; //string | string array + crl: any; //string | string array + ciphers: string; + } + export interface Credentials { context?: any; } + export function createCredentials(details: CredentialDetails): Credentials; + export function createHash(algorithm: string): Hash; + export function createHmac(algorithm: string, key: string): Hmac; + interface Hash { + update(data: any, input_encoding?: string): Hash; + digest(encoding?: string): string; + } + interface Hmac { + update(data: any, input_encoding?: string): Hmac; + digest(encoding?: string): string; + } + export function createCipher(algorithm: string, password: any): Cipher; + export function createCipheriv(algorithm: string, key: any, iv: any): Cipher; + interface Cipher { + update(data: any, input_encoding?: string, output_encoding?: string): string; + final(output_encoding?: string): string; + setAutoPadding(auto_padding: boolean): void; + createDecipher(algorithm: string, password: any): Decipher; + createDecipheriv(algorithm: string, key: any, iv: any): Decipher; + } + interface Decipher { + update(data: any, input_encoding?: string, output_encoding?: string): void; + final(output_encoding?: string): string; + setAutoPadding(auto_padding: boolean): void; + } + export function createSign(algorithm: string): Signer; + interface Signer { + update(data: any): void; + sign(private_key: string, output_format: string): string; + } + export function createVerify(algorith: string): Verify; + interface Verify { + update(data: any): void; + verify(object: string, signature: string, signature_format?: string): boolean; + } + export function createDiffieHellman(prime_length: number): DiffieHellman; + export function createDiffieHellman(prime: number, encoding?: string): DiffieHellman; + interface DiffieHellman { + generateKeys(encoding?: string): string; + computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; + getPrime(encoding?: string): string; + getGenerator(encoding: string): string; + getPublicKey(encoding?: string): string; + getPrivateKey(encoding?: string): string; + setPublicKey(public_key: string, encoding?: string): void; + setPrivateKey(public_key: string, encoding?: string): void; + } + export function getDiffieHellman(group_name: string): DiffieHellman; + export function pbkdf2(password: string, salt: string, iterations: number, keylen: number, callback: (err: Error, derivedKey: string) => any): void; + export function pbkdf2Sync(password: string, salt: string, iterations: number, keylen: number) : Buffer; + export function randomBytes(size: number): Buffer; + export function randomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void; + export function pseudoRandomBytes(size: number): Buffer; + export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void; +} + +declare module "stream" { + import events = require("events"); + + export interface ReadableOptions { + highWaterMark?: number; + encoding?: string; + objectMode?: boolean; + } + + export class Readable extends events.EventEmitter implements NodeJS.ReadableStream { + readable: boolean; + constructor(opts?: ReadableOptions); + _read(size: number): void; + read(size?: number): any; + setEncoding(encoding: string): void; + pause(): void; + resume(): void; + pipe(destination: T, options?: { end?: boolean; }): T; + unpipe(destination?: T): void; + unshift(chunk: string): void; + unshift(chunk: Buffer): void; + wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; + push(chunk: any, encoding?: string): boolean; + } + + export interface WritableOptions { + highWaterMark?: number; + decodeStrings?: boolean; + } + + export class Writable extends events.EventEmitter implements NodeJS.WritableStream { + writable: boolean; + constructor(opts?: WritableOptions); + _write(data: Buffer, encoding: string, callback: Function): void; + _write(data: string, encoding: string, callback: Function): void; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export interface DuplexOptions extends ReadableOptions, WritableOptions { + allowHalfOpen?: boolean; + } + + // Note: Duplex extends both Readable and Writable. + export class Duplex extends Readable implements NodeJS.ReadWriteStream { + writable: boolean; + constructor(opts?: DuplexOptions); + _write(data: Buffer, encoding: string, callback: Function): void; + _write(data: string, encoding: string, callback: Function): void; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export interface TransformOptions extends ReadableOptions, WritableOptions {} + + // Note: Transform lacks the _read and _write methods of Readable/Writable. + export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream { + readable: boolean; + writable: boolean; + constructor(opts?: TransformOptions); + _transform(chunk: Buffer, encoding: string, callback: Function): void; + _transform(chunk: string, encoding: string, callback: Function): void; + _flush(callback: Function): void; + read(size?: number): any; + setEncoding(encoding: string): void; + pause(): void; + resume(): void; + pipe(destination: T, options?: { end?: boolean; }): T; + unpipe(destination?: T): void; + unshift(chunk: string): void; + unshift(chunk: Buffer): void; + wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; + push(chunk: any, encoding?: string): boolean; + write(buffer: Buffer, cb?: Function): boolean; + write(str: string, cb?: Function): boolean; + write(str: string, encoding?: string, cb?: Function): boolean; + end(): void; + end(buffer: Buffer, cb?: Function): void; + end(str: string, cb?: Function): void; + end(str: string, encoding?: string, cb?: Function): void; + } + + export class PassThrough extends Transform {} +} + +declare module "util" { + export interface InspectOptions { + showHidden?: boolean; + depth?: number; + colors?: boolean; + customInspect?: boolean; + } + + export function format(format: any, ...param: any[]): string; + export function debug(string: string): void; + export function error(...param: any[]): void; + export function puts(...param: any[]): void; + export function print(...param: any[]): void; + export function log(string: string): void; + export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; + export function inspect(object: any, options: InspectOptions): string; + export function isArray(object: any): boolean; + export function isRegExp(object: any): boolean; + export function isDate(object: any): boolean; + export function isError(object: any): boolean; + export function inherits(constructor: any, superConstructor: any): void; +} + +declare module "assert" { + function internal (value: any, message?: string): void; + module internal { + export class AssertionError implements Error { + name: string; + message: string; + actual: any; + expected: any; + operator: string; + generatedMessage: boolean; + + constructor(options?: {message?: string; actual?: any; expected?: any; + operator?: string; stackStartFunction?: Function}); + } + + export function fail(actual?: any, expected?: any, message?: string, operator?: string): void; + export function ok(value: any, message?: string): void; + export function equal(actual: any, expected: any, message?: string): void; + export function notEqual(actual: any, expected: any, message?: string): void; + export function deepEqual(actual: any, expected: any, message?: string): void; + export function notDeepEqual(acutal: any, expected: any, message?: string): void; + export function strictEqual(actual: any, expected: any, message?: string): void; + export function notStrictEqual(actual: any, expected: any, message?: string): void; + export var throws: { + (block: Function, message?: string): void; + (block: Function, error: Function, message?: string): void; + (block: Function, error: RegExp, message?: string): void; + (block: Function, error: (err: any) => boolean, message?: string): void; + }; + + export var doesNotThrow: { + (block: Function, message?: string): void; + (block: Function, error: Function, message?: string): void; + (block: Function, error: RegExp, message?: string): void; + (block: Function, error: (err: any) => boolean, message?: string): void; + }; + + export function ifError(value: any): void; + } + + export = internal; +} + +declare module "tty" { + import net = require("net"); + + export function isatty(fd: number): boolean; + export interface ReadStream extends net.Socket { + isRaw: boolean; + setRawMode(mode: boolean): void; + } + export interface WriteStream extends net.Socket { + columns: number; + rows: number; + } +} + +declare module "domain" { + import events = require("events"); + + export class Domain extends events.EventEmitter { + run(fn: Function): void; + add(emitter: events.EventEmitter): void; + remove(emitter: events.EventEmitter): void; + bind(cb: (err: Error, data: any) => any): any; + intercept(cb: (data: any) => any): any; + dispose(): void; + + addListener(event: string, listener: Function): Domain; + on(event: string, listener: Function): Domain; + once(event: string, listener: Function): Domain; + removeListener(event: string, listener: Function): Domain; + removeAllListeners(event?: string): Domain; + } + + export function create(): Domain; +} From d243e3bbc64d0d474fa64ac6069284fe3d32d4db Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 11:19:01 -0700 Subject: [PATCH 03/38] Added type property to motors and fixed regular expression --- EV3Base.ts | 8 +++++++- Motor.ts | 10 +++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 9483ff9..ccbcbf7 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -60,6 +60,12 @@ enum MotorProperty { uevent } +enum MotorType { + tacho, + minitacho +} + module.exports.FilePathConstructor = FilePathConstructor; module.exports.MotorPort = MotorPort; -module.exports.MotorProperty = MotorProperty; \ No newline at end of file +module.exports.MotorProperty = MotorProperty; +module.exports.MotorType = MotorType; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts index e2ed828..64146a1 100644 --- a/Motor.ts +++ b/Motor.ts @@ -7,6 +7,7 @@ var base = require("./EV3Base.js"); var FilePathConstructor = base.FilePathConstructor; var MotorPort = base.MotorPort; var MotorProperty = base.MotorProperty; +var MotorType = base.MotorType; class Motor { private port: MotorPort @@ -16,13 +17,16 @@ class Motor { } get position(): number { - var propertyPath: string = FilePathConstructor.motorProperty(this.port, MotorProperty.position); - return parseInt(fs.readFileSync(propertyPath).toString()); + return parseInt(this.readProperty(MotorProperty.position)); + } + + get type(): string { + return this.readProperty(MotorProperty.type); } private readProperty(property: MotorProperty): string { var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); - return fs.readFileSync(propertyPath).toString().match(/[0-9]+/)[0]; + return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; } constructor(port: MotorPort) { From 2d2830212323f3280d02c3e374df72119c1dc604 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 11:35:35 -0700 Subject: [PATCH 04/38] Added error handling and fixed position property --- EV3Base.ts | 3 ++- Motor.ts | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index ccbcbf7..0e136e6 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -57,7 +57,8 @@ enum MotorProperty { type, speed, target_ramp_up_count, - uevent + uevent, + position } enum MotorType { diff --git a/Motor.ts b/Motor.ts index 64146a1..6a3fb44 100644 --- a/Motor.ts +++ b/Motor.ts @@ -24,9 +24,12 @@ class Motor { return this.readProperty(MotorProperty.type); } - private readProperty(property: MotorProperty): string { + private readProperty(property: MotorProperty): string { var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); - return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; + if (fs.existsSync(propertyPath)) + return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; + else + throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); } constructor(port: MotorPort) { From c4c9ba79ea4431e383403e197d9816e8186ad705 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 14:45:56 -0700 Subject: [PATCH 05/38] Added unlimited-mode motor control, doesn't include break/hold modes --- EV3Base.ts | 72 ++++++++++++++++++++++++++++++++++--------------- Motor.ts | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 22 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 0e136e6..bc84ec4 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -29,36 +29,64 @@ String.prototype.format = function () { }); }; +function softBoolean(value: any, falseValue?: any, trueValue?: any) : boolean{ + switch (value) { + case 0: + case 'off': + case false: + return falseValue == undefined? false : falseValue; + + case 1: + case 'on': + case true: + return trueValue == undefined? true : trueValue; + + default: + return undefined; + } +} + enum MotorPort { A, B, C, D } enum MotorProperty { - device, - state, - target_speed, - direction, - stop_mode, - target_steer, - mode, + brake_mode, + hold_mode, + position, + position_setpoint, + pulses_per_second, + ramp_up, + reset, + run_mode, + speed_setpoint, subsystem, - target_tacho, + type, + device, + polarity_mode, + position_mode, power, - tacho, - target_time, - ramp_mode, - tacho_mode, - target_total_count, + ramp_down, regulation_mode, - target_power, - time, run, - target_ramp_down_count, - type, speed, - target_ramp_up_count, - uevent, - position + state, + time_setpoint, + uevent +} + +var MotorPropertyValidation = { + 0: { type: 'string', values: ['on', 'off'] }, //brake_mode + 1: { type: 'string', values: ['on', 'off'] }, //hold_mode + 2: { type: 'number', min: -2147483648, max: 2147483648 }, //position + 7: { type: 'string', values: ['forever', 'time', 'position'] }, //run_mode + 8: { type: 'number', min: -100, max: 100 }, //speed_setpoint + 10: { type: 'string', values: ['tacho', 'minitacho'] }, //type + 14: { type: 'number', min: -100, max: 100 }, //power + 16: { type: 'string', values: ['on', 'off'] }, //regulation_mode + 17: { type: 'number', values: [0, 1] }, //run + 18: { type: 'number', min: -100, max: 100 }, //speed + } enum MotorType { @@ -69,4 +97,6 @@ enum MotorType { module.exports.FilePathConstructor = FilePathConstructor; module.exports.MotorPort = MotorPort; module.exports.MotorProperty = MotorProperty; -module.exports.MotorType = MotorType; \ No newline at end of file +module.exports.MotorType = MotorType; +module.exports.MotorPropertyValidation = MotorPropertyValidation; +module.exports.softBoolean = softBoolean; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts index 6a3fb44..ad4e4e1 100644 --- a/Motor.ts +++ b/Motor.ts @@ -7,11 +7,14 @@ var base = require("./EV3Base.js"); var FilePathConstructor = base.FilePathConstructor; var MotorPort = base.MotorPort; var MotorProperty = base.MotorProperty; +var MotorPropertyValidation = base.MotorPropertyValidation; var MotorType = base.MotorType; +var softBoolean = base.softBoolean; class Motor { private port: MotorPort + //Read-only properties get speed(): number { return parseInt(this.readProperty(MotorProperty.speed)); } @@ -20,11 +23,15 @@ class Motor { return parseInt(this.readProperty(MotorProperty.position)); } + get power(): number { + return parseInt(this.readProperty(MotorProperty.power)); + } + get type(): string { return this.readProperty(MotorProperty.type); } - private readProperty(property: MotorProperty): string { + private readProperty(property: MotorProperty): string { var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); if (fs.existsSync(propertyPath)) return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; @@ -32,10 +39,80 @@ class Motor { throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); } + //Writable properties + + get targetSpeed(): number { + return parseInt(this.readProperty(MotorProperty.speed_setpoint)); + } + + set targetSpeed(value: number) { + this.writeProperty(MotorProperty.speed_setpoint, value); + } + + private writeProperty(property: MotorProperty, value: any) { + var propertySpec = MotorPropertyValidation[property]; + + switch (propertySpec.type) { + case 'number': + if (isNaN(value)) + throw new Error('The specified value is not a number.'); + + if (typeof propertySpec.min != 'undefined') + if (value < propertySpec.min) + throw new Error('The specified value must be greater than or equal to' + propertySpec.min + '.'); + + if (typeof propertySpec.max != 'undefined') + if (value > propertySpec.max) + throw new Error('The specified value must be less than or equal to' + propertySpec.max + '.'); + + if (typeof propertySpec.values != 'undefined') + if (propertySpec.values.indexOf(value) == -1) + throw new Error('"' + value + '" is not an acceptable value.'); + + break; + + case 'string': + if (typeof propertySpec.values != 'undefined') + if (propertySpec.values.indexOf(value) == -1) + throw new Error('"' + value + '" is not an acceptable value.'); + break; + } + + var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); + + if (fs.existsSync(propertyPath)) + return fs.writeFileSync(propertyPath, value); + else + throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); + } + + public run(options: motorRunOptions) { + for (var i in defaultMotorRunOptions) + if (options[i] == undefined) + options[i] = defaultMotorRunOptions[i]; + + this.writeProperty(MotorProperty.regulation_mode, softBoolean(options.regulationMode, 'off', 'on')); + this.writeProperty(MotorProperty.run, softBoolean(options.run,0,1)); + this.writeProperty(MotorProperty.speed_setpoint, options.targetSpeed); + } + constructor(port: MotorPort) { this.port = port; } } +interface motorRunOptions { + targetSpeed: number //equates to speed_setpoint. Default: 0 + run: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true + regulationMode: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false + +} + +var defaultMotorRunOptions = { + targetSpeed: 0, + run: 1, + regulationMode: false +} + module.exports = Motor; module.exports.MotorPort = base.MotorPort; \ No newline at end of file From 3d56ad8baecafde58bd7902772e143e499e247b3 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 15:08:59 -0700 Subject: [PATCH 06/38] Added comments to the major functions --- EV3Base.ts | 7 +++++++ Motor.ts | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index bc84ec4..5ba914d 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -2,6 +2,9 @@ var fs = require("fs"); var path = require('path'); +/** + * A module to handle path creation from known properties + */ module FilePathConstructor { var motorDeviceDir: string = '/sys/class/tacho-motor/'; var motorDirName: string = 'out{0}:motor:tacho'; @@ -15,6 +18,7 @@ module FilePathConstructor { } } +//Extend the string prototype interface String { format(...args: any[]): string } @@ -29,6 +33,9 @@ String.prototype.format = function () { }); }; +/** + * Takes any of the logical ways to express a boolean and normalizes them. + */ function softBoolean(value: any, falseValue?: any, trueValue?: any) : boolean{ switch (value) { case 0: diff --git a/Motor.ts b/Motor.ts index ad4e4e1..4e0353a 100644 --- a/Motor.ts +++ b/Motor.ts @@ -1,6 +1,7 @@ /// /// +//Require modules and globalize some stuff var fs = require("fs"); var base = require("./EV3Base.js"); @@ -11,26 +12,31 @@ var MotorPropertyValidation = base.MotorPropertyValidation; var MotorType = base.MotorType; var softBoolean = base.softBoolean; +//Class to hold the basic function of the motor class Motor { private port: MotorPort //Read-only properties - get speed(): number { + get speed(): number { //Indication of relative speed return parseInt(this.readProperty(MotorProperty.speed)); } - get position(): number { + get position(): number { //Number of tacho ticks return parseInt(this.readProperty(MotorProperty.position)); } - get power(): number { + get power(): number { //The power being sent to the motor return parseInt(this.readProperty(MotorProperty.power)); } - get type(): string { + get type(): string { //The type of motor return this.readProperty(MotorProperty.type); } + /** + * Reads the value of a property from the file; includes error handling if the file doesn't exist + * @param {MotorProperty} property The property to read + */ private readProperty(property: MotorProperty): string { var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); if (fs.existsSync(propertyPath)) @@ -41,7 +47,7 @@ class Motor { //Writable properties - get targetSpeed(): number { + get targetSpeed(): number { //The speed_setpoint return parseInt(this.readProperty(MotorProperty.speed_setpoint)); } @@ -49,6 +55,10 @@ class Motor { this.writeProperty(MotorProperty.speed_setpoint, value); } + /** + * Writes a value for a property. + * Checks the input against the validation params specified for each property; will throw if the input isn't valid. + */ private writeProperty(property: MotorProperty, value: any) { var propertySpec = MotorPropertyValidation[property]; @@ -86,6 +96,9 @@ class Motor { throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); } + /** + * Starts the motor. + */ public run(options: motorRunOptions) { for (var i in defaultMotorRunOptions) if (options[i] == undefined) From 0d84727a8359030ee6d530b436500d3fd7ceb7c2 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 17:50:52 -0700 Subject: [PATCH 07/38] Added hold_mode and break_mode --- Motor.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Motor.ts b/Motor.ts index 4e0353a..c165ab2 100644 --- a/Motor.ts +++ b/Motor.ts @@ -47,7 +47,8 @@ class Motor { //Writable properties - get targetSpeed(): number { //The speed_setpoint + //tarhetSpeed: The speed_setpoint + get targetSpeed(): number { return parseInt(this.readProperty(MotorProperty.speed_setpoint)); } @@ -55,6 +56,24 @@ class Motor { this.writeProperty(MotorProperty.speed_setpoint, value); } + //holdMode: Will actively hold the motor position after it stops + get holdMode(): string { + return this.readProperty(MotorProperty.hold_mode); + } + + set holdMode(value: string) { + this.writeProperty(MotorProperty.hold_mode, value); + } + + //breakMode: Will reverse the motor direction when it stops + get breakMode(): string { + return this.readProperty(MotorProperty.break_mode); + } + + set breakMode(value: string) { + this.writeProperty(MotorProperty.break_mode, value); + } + /** * Writes a value for a property. * Checks the input against the validation params specified for each property; will throw if the input isn't valid. From acaedcfda9028bbe011923764728dbdca0711c96 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 20:04:44 -0700 Subject: [PATCH 08/38] Added a run property, renamed the run function to avoid collisions, and added brake_mode --- Motor.ts | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Motor.ts b/Motor.ts index c165ab2..b054a97 100644 --- a/Motor.ts +++ b/Motor.ts @@ -47,7 +47,7 @@ class Motor { //Writable properties - //tarhetSpeed: The speed_setpoint + //targetSpeed: The speed_setpoint get targetSpeed(): number { return parseInt(this.readProperty(MotorProperty.speed_setpoint)); } @@ -56,22 +56,31 @@ class Motor { this.writeProperty(MotorProperty.speed_setpoint, value); } + //run: enables the motors. any type. + get run(): number { + return parseInt(this.readProperty(MotorProperty.run)); + } + + set run(value: number) { + this.writeProperty(MotorProperty.run, softBoolean(value, 0, 1)); + } + //holdMode: Will actively hold the motor position after it stops get holdMode(): string { return this.readProperty(MotorProperty.hold_mode); } set holdMode(value: string) { - this.writeProperty(MotorProperty.hold_mode, value); + this.writeProperty(MotorProperty.hold_mode, softBoolean(value, 'off', 'on')); } - //breakMode: Will reverse the motor direction when it stops - get breakMode(): string { - return this.readProperty(MotorProperty.break_mode); + //brakeMode: Will reverse the motor direction when it stops + get brakeMode(): string { + return this.readProperty(MotorProperty.brake_mode); } - set breakMode(value: string) { - this.writeProperty(MotorProperty.break_mode, value); + set brakeMode(value: string) { + this.writeProperty(MotorProperty.brake_mode, softBoolean(value, 'off', 'on')); } /** @@ -118,7 +127,7 @@ class Motor { /** * Starts the motor. */ - public run(options: motorRunOptions) { + public runMotor(options: motorRunOptions) { for (var i in defaultMotorRunOptions) if (options[i] == undefined) options[i] = defaultMotorRunOptions[i]; @@ -128,6 +137,13 @@ class Motor { this.writeProperty(MotorProperty.speed_setpoint, options.targetSpeed); } + public brake() { + this.holdMode = false; + this.brakeMode = true; + + this.runMotor({ run: false }); + } + constructor(port: MotorPort) { this.port = port; } From fe1056bdbfe631736c4c2179e377a109c461967a Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 20:55:30 -0700 Subject: [PATCH 09/38] Added functions for hold and coast --- Motor.ts | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/Motor.ts b/Motor.ts index b054a97..9c1dd8a 100644 --- a/Motor.ts +++ b/Motor.ts @@ -66,20 +66,20 @@ class Motor { } //holdMode: Will actively hold the motor position after it stops - get holdMode(): string { + get holdMode(): any { return this.readProperty(MotorProperty.hold_mode); } - set holdMode(value: string) { + set holdMode(value: any) { this.writeProperty(MotorProperty.hold_mode, softBoolean(value, 'off', 'on')); } //brakeMode: Will reverse the motor direction when it stops - get brakeMode(): string { + get brakeMode(): any { return this.readProperty(MotorProperty.brake_mode); } - set brakeMode(value: string) { + set brakeMode(value: any) { this.writeProperty(MotorProperty.brake_mode, softBoolean(value, 'off', 'on')); } @@ -137,6 +137,9 @@ class Motor { this.writeProperty(MotorProperty.speed_setpoint, options.targetSpeed); } + /** + * Stops the motor by reversing the direction + */ public brake() { this.holdMode = false; this.brakeMode = true; @@ -144,15 +147,35 @@ class Motor { this.runMotor({ run: false }); } + /** + * Stops the motor and actively holds it in place + */ + public hold() { + this.holdMode = true; + this.brakeMode = false; + + this.runMotor({ run: false }); + } + + /** + * Turns off the motor but allows it to coast + */ + public coast() { + this.holdMode = false; + this.brakeMode = false; + + this.runMotor({ run: false }); + } + constructor(port: MotorPort) { this.port = port; } } interface motorRunOptions { - targetSpeed: number //equates to speed_setpoint. Default: 0 - run: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true - regulationMode: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false + targetSpeed?: number //equates to speed_setpoint. Default: 0 + run?: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true + regulationMode?: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false } From e78bcb30b8f669e39c0c72e06312a06098a7fd56 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sat, 28 Jun 2014 23:36:35 -0700 Subject: [PATCH 10/38] Added initial LED support; partially untested --- EV3Base.ts | 30 ++++++++++++++++- LED.ts | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 LED.ts diff --git a/EV3Base.ts b/EV3Base.ts index 5ba914d..8c8d576 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -9,6 +9,9 @@ module FilePathConstructor { var motorDeviceDir: string = '/sys/class/tacho-motor/'; var motorDirName: string = 'out{0}:motor:tacho'; + var ledDeviceDir: string = '/sys/class/leds/'; + var ledDirName: string = 'ev3:{0}:{1}'; + export function motor(port: MotorPort) { return path.join(motorDeviceDir, motorDirName.format(MotorPort[port]), '/'); } @@ -16,6 +19,11 @@ module FilePathConstructor { export function motorProperty(port: MotorPort, property: MotorProperty) { return path.join(motor(port), MotorProperty[property]); } + + export function ledBrightness(position: ledPosition, color: ledUnitColor) { + + return path.join(ledDeviceDir, ledDirName.format(ledUnitColor[color], ledPosition[position]), '/brightness'); + } } //Extend the string prototype @@ -101,9 +109,29 @@ enum MotorType { minitacho } +enum ledPosition { + left, + right +} + +enum ledUnitColor { + green, + red +} + +enum ledColorSetting { + green, + amber, + red, + off +} + module.exports.FilePathConstructor = FilePathConstructor; module.exports.MotorPort = MotorPort; module.exports.MotorProperty = MotorProperty; module.exports.MotorType = MotorType; module.exports.MotorPropertyValidation = MotorPropertyValidation; -module.exports.softBoolean = softBoolean; \ No newline at end of file +module.exports.softBoolean = softBoolean; +module.exports.ledUnitColor = ledUnitColor; +module.exports.ledColorSetting = ledColorSetting; +module.exports.ledPosition = ledPosition; \ No newline at end of file diff --git a/LED.ts b/LED.ts new file mode 100644 index 0000000..19b08c6 --- /dev/null +++ b/LED.ts @@ -0,0 +1,97 @@ +/// +/// + +//Require modules and globalize some stuff +var fs = require("fs"); +var base = require("./EV3Base.js"); + +var FilePathConstructor = base.FilePathConstructor; +var softBoolean = base.softBoolean; +var ledPosition = base.ledPosition; +var ledUnitColor = base.ledUnitColor; +var ledColorSetting = base.ledColorSetting; + +class LED { + private position: ledPosition; + + constructor(position: ledPosition) { + this.position = position; + } + + get color(): ledColorSetting { + var ledStatus = this.readLedStatus(); + + if (!ledStatus.greenLED && !ledStatus.redLED) + return ledColorSetting.off; + else if (ledStatus.greenLED && ledStatus.redLED) + return ledColorSetting.amber; + else if (ledStatus.greenLED) + return ledColorSetting.green; + else if (ledStatus.redLED) + return ledColorSetting.red; + } + + set color(value: ledColorSetting) { + var ledState = new LedState(false, false); + + switch (value) { + case ledColorSetting.amber: + ledState.greenLED = true; + ledState.redLED = true; + break; + case ledColorSetting.green: + ledState.greenLED = true; + break; + case ledColorSetting.red: + ledState.redLED = true; + break; + } + + this.writeLedStatus(ledState); + } + + /** + * Reads the status of the LED unit from the file; includes error handling if the file doesn't exist + */ + private readLedStatus(): LedState { + var redPropertyPath: string = FilePathConstructor.ledBrightness(this.position, ledUnitColor.red); + var greenPropertyPath: string = FilePathConstructor.ledBrightness(this.position, ledUnitColor.green); + + if (fs.existsSync(redPropertyPath) && fs.existsSync(greenPropertyPath)) + return new LedState( + !!String.fromCharCode(fs.readFileSync(redPropertyPath)[0]), + !!String.fromCharCode(fs.readFileSync(greenPropertyPath)[0]) + ); + else + throw new Error('The file could not be found.'); + } + + /** + * Sets the status of the LED unit. + */ + private writeLedStatus(value: LedState) { + var redPropertyPath: string = FilePathConstructor.ledBrightness(this.position, ledUnitColor.red); + var greenPropertyPath: string = FilePathConstructor.ledBrightness(this.position, ledUnitColor.green); + + if (fs.existsSync(redPropertyPath) && fs.existsSync(greenPropertyPath)) { + fs.writeFileSync(redPropertyPath, softBoolean(value.redLED, 0, 1)); + fs.writeFileSync(greenPropertyPath, softBoolean(value.greenLED, 0, 1)); + } + else + throw new Error('The file could not be found.'); + } +} + +class LedState { + redLED: boolean; + greenLED: boolean; + + constructor(redLED: boolean, greenLED: boolean) { + this.redLED = redLED; + this.greenLED = greenLED; + } +} + +module.exports = LED; +module.exports.ledColorSetting = base.ledColorSetting; +module.exports.ledPosition = base.ledPosition \ No newline at end of file From 2af1cb955dd4c17d0d85e1127b553cb2022e2b32 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 30 Jun 2014 14:25:53 -0700 Subject: [PATCH 11/38] Added top-level index file to expose main interface and included package.json --- Index.ts | 11 +++++++++++ LED.ts | 4 +--- Motor.ts | 3 +-- package.json | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Index.ts create mode 100644 package.json diff --git a/Index.ts b/Index.ts new file mode 100644 index 0000000..3eeb2cc --- /dev/null +++ b/Index.ts @@ -0,0 +1,11 @@ +/// +var base = require("./EV3Base.js"); +var LED = require("./LED.js"); +var Motor = require("./Motor.js"); + +module.exports.Motor = Motor; +module.exports.LED = LED; + +module.exports.MotorPort = base.MotorPort; +module.exports.ledColorSetting = base.ledColorSetting; +module.exports.ledPosition = base.ledPosition; \ No newline at end of file diff --git a/LED.ts b/LED.ts index 19b08c6..d038363 100644 --- a/LED.ts +++ b/LED.ts @@ -92,6 +92,4 @@ class LedState { } } -module.exports = LED; -module.exports.ledColorSetting = base.ledColorSetting; -module.exports.ledPosition = base.ledPosition \ No newline at end of file +module.exports = LED; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts index 9c1dd8a..2490ee2 100644 --- a/Motor.ts +++ b/Motor.ts @@ -185,5 +185,4 @@ var defaultMotorRunOptions = { regulationMode: false } -module.exports = Motor; -module.exports.MotorPort = base.MotorPort; \ No newline at end of file +module.exports = Motor; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..a516c30 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "ev3dev", + "version": "0.1.0", + "description": "An interface to control an EV3 running ev3dev from JavaScript.", + "keywords": ["ev3dev"], + "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", + "bugs": {"url": "http://github.com/WasabiFan/ev3dev-NodeJS/issues"}, + "author": {"name": "WasabiFan", "email": "WasabiFan@outlook.com"}, + + "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js"], + "main": "Index.js", + "repository" : + { "type" : "git", + "url" : "http://github.com/WasabiFan/ev3dev-NodeJS.git" + } +} \ No newline at end of file From 09b41e775c26cfdae67d013b090feaecee9eba52 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 30 Jun 2014 14:57:44 -0700 Subject: [PATCH 12/38] Fixed npm package config --- .npmignore | 1 + package.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..b0a155e --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +*.ts \ No newline at end of file diff --git a/package.json b/package.json index a516c30..fa8f263 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "ev3dev", - "version": "0.1.0", + "version": "0.1.1", "description": "An interface to control an EV3 running ev3dev from JavaScript.", "keywords": ["ev3dev"], "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", "bugs": {"url": "http://github.com/WasabiFan/ev3dev-NodeJS/issues"}, "author": {"name": "WasabiFan", "email": "WasabiFan@outlook.com"}, - "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js"], + "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js", "README.md"], "main": "Index.js", "repository" : { "type" : "git", From 6f37556f719e1d3b955e9efbcdb5ba873fb76b86 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 30 Jun 2014 16:01:14 -0700 Subject: [PATCH 13/38] Added examples to README --- README.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c69f18f..cd9f637 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,45 @@ ev3dev-NodeJS ============= -EV3dev API language bindings for NodeJS +ev3dev-NodeJS is a NodeJS module that exposes the features of the ev3dev API. Your brick must be running [ev3dev](http://github.com/mindboards/ev3dev) and must have NodeJS installed. + +We currently support: + +- Motors + - Run forever +- LEDs + +Motors +------ +``` +//Require the module +var ev3 = require('ev3dev'); + +//Create the motor on port A +var motorA = new ev3.Motor(ev3.MotorPort.A); + +//Run the motor at 60% power +motorA.runMotor({ targetSpeed: 60 }); + +//Wait five seconds before turning off the motor and letting it coast +setTimeout(function () { + motorA.coast(); +}, 5000); +``` +Simple, right? Learn more about the Motor APIs on the Wiki. + +LEDs +---- +``` +//Require the module +var ev3 = require('ev3dev'); + +//Initialize both LEDs +var leftLED = new ev3.LED(ev3.ledPosition.left); +var rightLED = new ev3.LED(ev3.ledPosition.right); + +//Set their color +leftLED.color = ev3.ledColorSetting.green; +rightLED.color = ev3.ledColorSetting.red; +``` +More docs are also on the Wiki. \ No newline at end of file From 5686c00aac15d9782ac6f88e50e77ad263da7a62 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 30 Jun 2014 22:31:18 -0700 Subject: [PATCH 14/38] Renamed runMotor and moved motorRunOptions --- EV3Base.ts | 15 ++++++++++++++- Index.ts | 3 ++- Motor.ts | 16 +++++----------- README.md | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 8c8d576..c1c1bf7 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -104,6 +104,18 @@ var MotorPropertyValidation = { } +class motorRunOptions { + targetSpeed: number; //equates to speed_setpoint. Default: 0 + run: any; //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true + regulationMode: any; //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false + + constructor(targetSpeed?: number, run?: any, regulationMode?: any) { + this.targetSpeed = targetSpeed; + this.run = run; + this.regulationMode = regulationMode; + } +} + enum MotorType { tacho, minitacho @@ -134,4 +146,5 @@ module.exports.MotorPropertyValidation = MotorPropertyValidation; module.exports.softBoolean = softBoolean; module.exports.ledUnitColor = ledUnitColor; module.exports.ledColorSetting = ledColorSetting; -module.exports.ledPosition = ledPosition; \ No newline at end of file +module.exports.ledPosition = ledPosition; +module.exports.motorRunOptions = motorRunOptions; \ No newline at end of file diff --git a/Index.ts b/Index.ts index 3eeb2cc..d52ec52 100644 --- a/Index.ts +++ b/Index.ts @@ -8,4 +8,5 @@ module.exports.LED = LED; module.exports.MotorPort = base.MotorPort; module.exports.ledColorSetting = base.ledColorSetting; -module.exports.ledPosition = base.ledPosition; \ No newline at end of file +module.exports.ledPosition = base.ledPosition; +module.exports.motorRunOptions = base.motorRunOptions; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts index 2490ee2..0b6e241 100644 --- a/Motor.ts +++ b/Motor.ts @@ -11,6 +11,7 @@ var MotorProperty = base.MotorProperty; var MotorPropertyValidation = base.MotorPropertyValidation; var MotorType = base.MotorType; var softBoolean = base.softBoolean; +var motorRunOptions = base.motorRunOptions; //Class to hold the basic function of the motor class Motor { @@ -127,7 +128,7 @@ class Motor { /** * Starts the motor. */ - public runMotor(options: motorRunOptions) { + public startMotor(options: motorRunOptions) { for (var i in defaultMotorRunOptions) if (options[i] == undefined) options[i] = defaultMotorRunOptions[i]; @@ -144,7 +145,7 @@ class Motor { this.holdMode = false; this.brakeMode = true; - this.runMotor({ run: false }); + this.startMotor({ run: false }); } /** @@ -154,7 +155,7 @@ class Motor { this.holdMode = true; this.brakeMode = false; - this.runMotor({ run: false }); + this.startMotor({ run: false }); } /** @@ -164,7 +165,7 @@ class Motor { this.holdMode = false; this.brakeMode = false; - this.runMotor({ run: false }); + this.startMotor({ run: false }); } constructor(port: MotorPort) { @@ -172,13 +173,6 @@ class Motor { } } -interface motorRunOptions { - targetSpeed?: number //equates to speed_setpoint. Default: 0 - run?: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true - regulationMode?: any //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false - -} - var defaultMotorRunOptions = { targetSpeed: 0, run: 1, diff --git a/README.md b/README.md index cd9f637..097a9ac 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ var ev3 = require('ev3dev'); var motorA = new ev3.Motor(ev3.MotorPort.A); //Run the motor at 60% power -motorA.runMotor({ targetSpeed: 60 }); +motorA.startMotor({ targetSpeed: 60 }); //Wait five seconds before turning off the motor and letting it coast setTimeout(function () { From eaeb658e17885b1231b42b8ad1428eb332c3867d Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Tue, 1 Jul 2014 13:50:06 -0700 Subject: [PATCH 15/38] Added run-limited support; still no ramp --- EV3Base.ts | 12 +++++++++++- Index.ts | 3 ++- Motor.ts | 29 ++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index c1c1bf7..548fd75 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -65,6 +65,12 @@ enum MotorPort { A, B, C, D } +enum MotorRunMode { + forever, + time, + position +} + enum MotorProperty { brake_mode, hold_mode, @@ -94,6 +100,7 @@ var MotorPropertyValidation = { 0: { type: 'string', values: ['on', 'off'] }, //brake_mode 1: { type: 'string', values: ['on', 'off'] }, //hold_mode 2: { type: 'number', min: -2147483648, max: 2147483648 }, //position + 3: { type: 'number', min: -2147483648, max: 2147483648 }, //position_setpoint 7: { type: 'string', values: ['forever', 'time', 'position'] }, //run_mode 8: { type: 'number', min: -100, max: 100 }, //speed_setpoint 10: { type: 'string', values: ['tacho', 'minitacho'] }, //type @@ -101,6 +108,7 @@ var MotorPropertyValidation = { 16: { type: 'string', values: ['on', 'off'] }, //regulation_mode 17: { type: 'number', values: [0, 1] }, //run 18: { type: 'number', min: -100, max: 100 }, //speed + 20: { type: 'number', min: 0 } //time_setpoint } @@ -108,6 +116,7 @@ class motorRunOptions { targetSpeed: number; //equates to speed_setpoint. Default: 0 run: any; //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true regulationMode: any; //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false + time: number; //Time to run in milliseconds constructor(targetSpeed?: number, run?: any, regulationMode?: any) { this.targetSpeed = targetSpeed; @@ -147,4 +156,5 @@ module.exports.softBoolean = softBoolean; module.exports.ledUnitColor = ledUnitColor; module.exports.ledColorSetting = ledColorSetting; module.exports.ledPosition = ledPosition; -module.exports.motorRunOptions = motorRunOptions; \ No newline at end of file +module.exports.motorRunOptions = motorRunOptions; +module.exports.MotorRunMode = MotorRunMode; \ No newline at end of file diff --git a/Index.ts b/Index.ts index d52ec52..d7b91b7 100644 --- a/Index.ts +++ b/Index.ts @@ -9,4 +9,5 @@ module.exports.LED = LED; module.exports.MotorPort = base.MotorPort; module.exports.ledColorSetting = base.ledColorSetting; module.exports.ledPosition = base.ledPosition; -module.exports.motorRunOptions = base.motorRunOptions; \ No newline at end of file +module.exports.motorRunOptions = base.motorRunOptions; +module.exports.MotorRunMode = base.MotorRunMode; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts index 0b6e241..31ee752 100644 --- a/Motor.ts +++ b/Motor.ts @@ -12,6 +12,7 @@ var MotorPropertyValidation = base.MotorPropertyValidation; var MotorType = base.MotorType; var softBoolean = base.softBoolean; var motorRunOptions = base.motorRunOptions; +var MotorRunMode = base.MotorRunMode; //Class to hold the basic function of the motor class Motor { @@ -133,9 +134,30 @@ class Motor { if (options[i] == undefined) options[i] = defaultMotorRunOptions[i]; + if (options.time != undefined) { + this.writeProperty(MotorProperty.run_mode, MotorRunMode[MotorRunMode.time]); + this.writeProperty(MotorProperty.time_setpoint, options.time); + } + this.writeProperty(MotorProperty.regulation_mode, softBoolean(options.regulationMode, 'off', 'on')); - this.writeProperty(MotorProperty.run, softBoolean(options.run,0,1)); this.writeProperty(MotorProperty.speed_setpoint, options.targetSpeed); + this.writeProperty(MotorProperty.run, softBoolean(options.run, 0, 1)); + + } + + /** + * Runs the motor to a specified position. Works well with holdMode and brakeMode. + */ + public runServo(position: number, speed: number, absolute?: boolean) { + this.writeProperty(MotorProperty.run, 0); + this.writeProperty(MotorProperty.speed_setpoint, speed); + this.writeProperty(MotorProperty.regulation_mode, 'on'); + + if (!absolute) + this.writeProperty(MotorProperty.position, 0); + + this.writeProperty(MotorProperty.position_setpoint, position); + this.writeProperty(MotorProperty.run, 1); } /** @@ -153,7 +175,7 @@ class Motor { */ public hold() { this.holdMode = true; - this.brakeMode = false; + this.brakeMode = true; this.startMotor({ run: false }); } @@ -176,7 +198,8 @@ class Motor { var defaultMotorRunOptions = { targetSpeed: 0, run: 1, - regulationMode: false + regulationMode: false, + time: undefined } module.exports = Motor; \ No newline at end of file From cdf53d74311532b73b537254d40fcfebe3848678 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Tue, 1 Jul 2014 16:37:08 -0700 Subject: [PATCH 16/38] README edits --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 097a9ac..5715d0f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ We currently support: - Motors - Run forever + - Run time + - Run servo/position - LEDs Motors @@ -26,7 +28,6 @@ setTimeout(function () { motorA.coast(); }, 5000); ``` -Simple, right? Learn more about the Motor APIs on the Wiki. LEDs ---- @@ -42,4 +43,7 @@ var rightLED = new ev3.LED(ev3.ledPosition.right); leftLED.color = ev3.ledColorSetting.green; rightLED.color = ev3.ledColorSetting.red; ``` -More docs are also on the Wiki. \ No newline at end of file + + + +Simple, right? Learn more about the [Motor](https://github.com/WasabiFan/ev3dev-NodeJS/wiki/Motors) and [LED](https://github.com/WasabiFan/ev3dev-NodeJS/wiki/LEDs) APIs on the Wiki. \ No newline at end of file From 1f08f71961eba3489e872fc645b90771e9a53084 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Wed, 2 Jul 2014 17:26:42 -0700 Subject: [PATCH 17/38] Changed servo signature and added built-in servo brake/hold --- Motor.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Motor.ts b/Motor.ts index 31ee752..bfb659b 100644 --- a/Motor.ts +++ b/Motor.ts @@ -148,16 +148,27 @@ class Motor { /** * Runs the motor to a specified position. Works well with holdMode and brakeMode. */ - public runServo(position: number, speed: number, absolute?: boolean) { + public runServo(options: any) { this.writeProperty(MotorProperty.run, 0); - this.writeProperty(MotorProperty.speed_setpoint, speed); + this.writeProperty(MotorProperty.speed_setpoint, options.speed); this.writeProperty(MotorProperty.regulation_mode, 'on'); - if (!absolute) + if (!options.absolute) this.writeProperty(MotorProperty.position, 0); - this.writeProperty(MotorProperty.position_setpoint, position); + this.writeProperty(MotorProperty.position_setpoint, options.position); this.writeProperty(MotorProperty.run, 1); + + if (options.completeBehavior) { + switch (options.completeBehavior) { + case 'hold': + this.holdMode = true; + case 'brake': + this.brakeMode = true; + break; + + } + } } /** From 8966529a60fdc53280c89a7619e37fd4dca6d35e Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Fri, 4 Jul 2014 18:28:28 -0700 Subject: [PATCH 18/38] Initial commit of sensors - only basic analog support, unknown errors --- EV3Base.ts | 36 ++++++-- Index.ts | 2 + Sensors/Sensor.ts | 29 ++++++ linq.d.ts | 222 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 5 files changed, 285 insertions(+), 5 deletions(-) create mode 100644 Sensors/Sensor.ts create mode 100644 linq.d.ts diff --git a/EV3Base.ts b/EV3Base.ts index 548fd75..cf29c1d 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -1,6 +1,8 @@ /// +/// var fs = require("fs"); var path = require('path'); +var Enumerable = require('linq'); /** * A module to handle path creation from known properties @@ -9,6 +11,9 @@ module FilePathConstructor { var motorDeviceDir: string = '/sys/class/tacho-motor/'; var motorDirName: string = 'out{0}:motor:tacho'; + var sensorDeviceDir: string = '/sys/class/msensor'; + var sensorDirName: string = 'sensor{0}'; + var ledDeviceDir: string = '/sys/class/leds/'; var ledDirName: string = 'ev3:{0}:{1}'; @@ -20,8 +25,29 @@ module FilePathConstructor { return path.join(motor(port), MotorProperty[property]); } - export function ledBrightness(position: ledPosition, color: ledUnitColor) { + export function sensorNumber(port: number) { + if (!fs.existsSync(sensorDeviceDir)) + throw new Error('The sensor class directory does not exist.'); + + var sensorFile = Enumerable.from(fs.readdirSync(sensorDeviceDir)) + .firstOrDefault(file => fs.readFileSync( + path.join(sensorDeviceDir, '/', file, '/port_name') + ).toString() + .indexOf('in' + port) == 0); + return sensorFile.match(/[0-9]+/)[0]; + } + + export function sensor(sensorNumber: number) { + return path.join(sensorDeviceDir, sensorDirName.format(sensorNumber), '/'); + } + + export function sensorProperty(sensorNumber: number, property: string) { + return path.join(sensor(sensorNumber), property); + } + + + export function ledBrightness(position: ledPosition, color: ledUnitColor) { return path.join(ledDeviceDir, ledDirName.format(ledUnitColor[color], ledPosition[position]), '/brightness'); } } @@ -44,17 +70,17 @@ String.prototype.format = function () { /** * Takes any of the logical ways to express a boolean and normalizes them. */ -function softBoolean(value: any, falseValue?: any, trueValue?: any) : boolean{ +function softBoolean(value: any, falseValue?: any, trueValue?: any): boolean { switch (value) { - case 0: + case 0: case 'off': case false: - return falseValue == undefined? false : falseValue; + return falseValue == undefined ? false : falseValue; case 1: case 'on': case true: - return trueValue == undefined? true : trueValue; + return trueValue == undefined ? true : trueValue; default: return undefined; diff --git a/Index.ts b/Index.ts index d7b91b7..d360fa7 100644 --- a/Index.ts +++ b/Index.ts @@ -2,9 +2,11 @@ var base = require("./EV3Base.js"); var LED = require("./LED.js"); var Motor = require("./Motor.js"); +var Sensors = require("./Sensors/Sensor.js"); module.exports.Motor = Motor; module.exports.LED = LED; +module.exports.AnalogSensor = Sensors.AnalogSensor; module.exports.MotorPort = base.MotorPort; module.exports.ledColorSetting = base.ledColorSetting; diff --git a/Sensors/Sensor.ts b/Sensors/Sensor.ts new file mode 100644 index 0000000..498614e --- /dev/null +++ b/Sensors/Sensor.ts @@ -0,0 +1,29 @@ +/// +/// + +//Require modules and globalize some stuff +var fs = require("fs"); +var base = require("../EV3Base.js"); + +var FilePathConstructor = base.FilePathConstructor; +var softBoolean = base.softBoolean; + +class AnalogSensor { + sensorPort: number; + sensorIndex: number; + + constructor(sensorPort: number) { + this.sensorPort = sensorPort; + this.sensorIndex = FilePathConstructor.sensorNumber(sensorPort); + } + + get analogValue(): number { + var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'value0'); + if (fs.existsSync(propertyPath)) + return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; + else + throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); + } +} + +module.exports.AnalogSensor = AnalogSensor; \ No newline at end of file diff --git a/linq.d.ts b/linq.d.ts new file mode 100644 index 0000000..7da0cf9 --- /dev/null +++ b/linq.d.ts @@ -0,0 +1,222 @@ +// Type definitions for linq.js 2.2 +// Project: http://linqjs.codeplex.com/ +// Definitions by: Marcin Najder +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +// todo: jQuery plugin, RxJS Binding + +declare module linq { + + interface EnumerableStatic { + Choice(...contents: any[]): Enumerable; + Choice(contents: any[]): Enumerable; + Cycle(...contents: any[]): Enumerable; + Cycle(contents: any[]): Enumerable; + Empty(): Enumerable; + From(obj: any[]): Enumerable; + From(obj: any): Enumerable; + Return(element: any): Enumerable; + Matches(input: string, pattern: RegExp): Enumerable; + Matches(input: string, pattern: string, flags?: string): Enumerable; + Range(start: number, count: number, step?: number): Enumerable; + RangeDown(start: number, count: number, step?: number): Enumerable; + RangeTo(start: number, to: number, step?: number): Enumerable; + Repeat(obj: any, count?: number): Enumerable; + RepeatWithFinalize(initializer: () => any, finalizer: (resource: any) =>void ): Enumerable; + Generate(func: () => any, count?: number): Enumerable; + Generate(func: string, count?: number): Enumerable; + ToInfinity(start?: number, step?: number): Enumerable; + ToNegativeInfinity(start?: number, step?: number): Enumerable; + Unfold(seed, func: ($) => any): Enumerable; + Unfold(seed, func: string): Enumerable; + } + + interface Enumerable { + //Projection and Filtering Methods + CascadeBreadthFirst(func: ($) => any[], resultSelector: (v, i: number) => any): Enumerable; + CascadeBreadthFirst(func: string, resultSelector: string): Enumerable; + CascadeDepthFirst(func: ($) => any[], resultSelector: (v, i: number) => any): Enumerable; + CascadeDepthFirst(func: string, resultSelector: string): Enumerable; + Flatten(...items: any[]): Enumerable; + Pairwise(selector: (prev, next) => any): Enumerable; + Pairwise(selector: string): Enumerable; + Scan(func: (a, b) => any): Enumerable; + Scan(func: string): Enumerable; + Scan(seed, func: (a, b) => any, resultSelector?: ($) => any): Enumerable; + Scan(seed, func: string, resultSelector?: string): Enumerable; + Select(selector: ($, i: number) => any): Enumerable; + Select(selector: string): Enumerable; + SelectMany(collectionSelector: ($, i: number) => any[], resultSelector?: ($, item) => any): Enumerable; + SelectMany(collectionSelector: ($, i: number) => Enumerable, resultSelector?: ($, item) => any): Enumerable; + SelectMany(collectionSelector: string, resultSelector?: string): Enumerable; + Where(predicate: ($, i: number) => boolean): Enumerable; + Where(predicate: string): Enumerable; + OfType(type: Function): Enumerable; + Zip(second: any[], selector: (v1, v2, i: number) => any): Enumerable; + Zip(second: any[], selector: string): Enumerable; + Zip(second: Enumerable, selector: (v1, v2, i: number) => any): Enumerable; + Zip(second: Enumerable, selector: string): Enumerable; + //Join Methods + Join(inner: any[], outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2) => any, compareSelector?: (v) => any): Enumerable; + Join(inner: any[], outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; + Join(inner: Enumerable, outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2) => any, compareSelector?: (v) => any): Enumerable; + Join(inner: Enumerable, outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; + GroupJoin(inner: any[], outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2: Enumerable) => any, compareSelector?: (v) => any): Enumerable; + GroupJoin(inner: any[], outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; + GroupJoin(inner: Enumerable, outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2: Enumerable) => any, compareSelector?: (v) => any): Enumerable; + GroupJoin(inner: Enumerable, outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; + //Set Methods + All(predicate: ($) => boolean): boolean; + All(predicate: string): boolean; + Any(predicate?: ($) => boolean): boolean; + Any(predicate?: string): boolean; + Concat(second: any[]): Enumerable; + Concat(second: Enumerable): Enumerable; + Insert(index: number, second: any[]): Enumerable; + Insert(index: number, second: Enumerable): Enumerable; + Alternate(value): Enumerable; + Contains(value, compareSelector?: ($) => any): boolean; + Contains(value, compareSelector?: string): boolean; + DefaultIfEmpty(defaultValue): Enumerable; + Distinct(compareSelector?: ($) => any): Enumerable; + Distinct(compareSelector?: string): Enumerable; + Except(second: any[], compareSelector?: ($) => any): Enumerable; + Except(second: any[], compareSelector?: string): Enumerable; + Except(second: Enumerable, compareSelector?: ($) => any): Enumerable; + Except(second: Enumerable, compareSelector?: string): Enumerable; + Intersect(second: any[], compareSelector?: ($) => any): Enumerable; + Intersect(second: any[], compareSelector?: string): Enumerable; + Intersect(second: Enumerable, compareSelector?: ($) => any): Enumerable; + Intersect(second: Enumerable, compareSelector?: string): Enumerable; + SequenceEqual(second: any[], compareSelector?: ($) => any): boolean; + SequenceEqual(second: any[], compareSelector?: string): boolean; + SequenceEqual(second: Enumerable, compareSelector?: ($) => any): boolean; + SequenceEqual(second: Enumerable, compareSelector?: string): boolean; + Union(second: any[], compareSelector?: ($) => any): Enumerable; + Union(second: any[], compareSelector?: string): Enumerable; + Union(second: Enumerable, compareSelector?: ($) => any): Enumerable; + Union(second: Enumerable, compareSelector?: string): Enumerable; + //Ordering Methods + OrderBy(keySelector?: ($) => any): OrderedEnumerable; + OrderBy(keySelector?: string): OrderedEnumerable; + OrderByDescending(keySelector?: ($) => any): OrderedEnumerable; + OrderByDescending(keySelector?: string): OrderedEnumerable; + Reverse(): Enumerable; + Shuffle(): Enumerable; + //Grouping Methods + GroupBy(keySelector: ($) => any, elementSelector?: ($) => any, resultSelector?: (key, e) => any, compareSelector?: ($) =>any): Enumerable; + GroupBy(keySelector: string, elementSelector?: string, resultSelector?: string, compareSelector?: string): Enumerable; + PartitionBy(keySelector: ($) => any, elementSelector?: ($) => any, resultSelector?: (key, e) => any, compareSelector?: ($) =>any): Enumerable; + PartitionBy(keySelector: string, elementSelector?: string, resultSelector?: string, compareSelector?: string): Enumerable; + BufferWithCount(count: number): Enumerable; + // Aggregate Methods + Aggregate(func: (a, b) => any); + Aggregate(seed, func: (a, b) => any, resultSelector?: ($) => any); + Aggregate(func: string); + Aggregate(seed, func: string, resultSelector?: string); + Average(selector?: ($) => number): number; + Average(selector?: string): number; + Count(predicate?: ($) => boolean): number; + Count(predicate?: string): number; + Max(selector?: ($) => number): number; + Max(selector?: string): number; + Min(selector?: ($) => number): number; + Min(selector?: string): number; + MaxBy(selector: ($) => number): any; + MaxBy(selector: string): any; + MinBy(selector: ($) => number): any; + MinBy(selector: string): any; + Sum(selector?: ($) => number): number; + Sum(selector?: string): number; + //Paging Methods + ElementAt(index: number): any; + ElementAtOrDefault(index: number, defaultValue): any; + First(predicate?: ($) => boolean): any; + First(predicate?: string): any; + FirstOrDefault(defaultValue, predicate?: ($) => boolean): any; + FirstOrDefault(defaultValue, predicate?: string): any; + Last(predicate?: ($) => boolean): any; + Last(predicate?: string): any; + LastOrDefault(defaultValue, predicate?: ($) => boolean): any; + LastOrDefault(defaultValue, predicate?: string): any; + Single(predicate?: ($) => boolean): any; + Single(predicate?: string): any; + SingleOrDefault(defaultValue, predicate?: ($) => boolean): any; + SingleOrDefault(defaultValue, predicate?: string): any; + Skip(count: number): Enumerable; + SkipWhile(predicate: ($, i: number) => boolean): Enumerable; + SkipWhile(predicate: string): Enumerable; + Take(count: number): Enumerable; + TakeWhile(predicate: ($, i: number) => boolean): Enumerable; + TakeWhile(predicate: string): Enumerable; + TakeExceptLast(count?: number): Enumerable; + TakeFromLast(count: number): Enumerable; + IndexOf(item): number; + LastIndexOf(item): number; + // Convert Methods + ToArray(): any[]; + ToLookup(keySelector: ($) => any, elementSelector?: ($) => any, compareSelector?: (key) => any): Lookup; + ToLookup(keySelector: string, elementSelector?: string, compareSelector?: string): Lookup; + ToObject(keySelector: ($) => string, elementSelector: ($) => any): any; + ToObject(keySelector: string, elementSelector: string): any; + ToDictionary(keySelector: ($) => any, elementSelector: ($) => any, compareSelector?: (key) => any): Dictionary; + ToDictionary(keySelector: string, elementSelector: string, compareSelector?: string): Dictionary; + ToJSON(replacer?: (key, value) => any, space?: number): string; + ToJSON(replacer?: string, space?: number): string; + ToString(separator?: string, selector?: ($) =>any): string; + ToString(separator?: string, selector?: string): string; + //Action Methods + Do(action: ($, i: number) => void ): Enumerable; + Do(action: string): Enumerable; + ForEach(action: ($, i: number) => void ): void; + ForEach(func: ($, i: number) => boolean): void; + ForEach(action_func: string): void; + Write(separator?: string, selector?: ($) =>any): void; + Write(separator?: string, selector?: string): void; + WriteLine(selector?: ($) =>any): void; + Force(): void; + //Functional Methods + Let(func: (e: Enumerable) => Enumerable): Enumerable; + Share(): Enumerable; + MemoizeAll(): Enumerable; + //Error Handling Methods + Catch(handler: (error: Error) => void ): Enumerable; + Catch(handler: string): Enumerable; + Finally(finallyAction: () => void ): Enumerable; + Finally(finallyAction: string): Enumerable; + //For Debug Methods + Trace(message?: string, selector?: ($) =>any): Enumerable; + Trace(message?: string, selector?: string): Enumerable; + } + + interface OrderedEnumerable extends Enumerable { + ThenBy(keySelector: ($) => any): OrderedEnumerable; + ThenBy(keySelector: string): OrderedEnumerable; + ThenByDescending(keySelector: ($) => any): OrderedEnumerable; + ThenByDescending(keySelector: string): OrderedEnumerable; + } + + interface Grouping extends Enumerable { + Key(); + } + + interface Lookup { + Count(): number; + Get(key): Enumerable; + Contains(key): boolean; + ToEnumerable(): Enumerable; + } + + interface Dictionary { + Add(key, value): void; + Get(key): any; + Set(key, value): boolean; + Contains(key): boolean; + Clear(): void; + Remove(key): void; + Count(): number; + ToEnumerable(): Enumerable; + } +} + +declare var Enumerable: linq.EnumerableStatic; diff --git a/package.json b/package.json index fa8f263..c356cc0 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "bugs": {"url": "http://github.com/WasabiFan/ev3dev-NodeJS/issues"}, "author": {"name": "WasabiFan", "email": "WasabiFan@outlook.com"}, + "dependencies": {"linq": "3.x"}, "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js", "README.md"], "main": "Index.js", "repository" : From 661f2ad6dac6f6a5eed8e750ccdb5a71a5d4c201 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Fri, 4 Jul 2014 19:37:54 -0700 Subject: [PATCH 19/38] Made sensor class more generic --- Index.ts | 2 +- Sensors/Sensor.ts | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Index.ts b/Index.ts index d360fa7..e76f4f9 100644 --- a/Index.ts +++ b/Index.ts @@ -6,7 +6,7 @@ var Sensors = require("./Sensors/Sensor.js"); module.exports.Motor = Motor; module.exports.LED = LED; -module.exports.AnalogSensor = Sensors.AnalogSensor; +module.exports.GenericSensor = Sensors.GenericSensor; module.exports.MotorPort = base.MotorPort; module.exports.ledColorSetting = base.ledColorSetting; diff --git a/Sensors/Sensor.ts b/Sensors/Sensor.ts index 498614e..bfcc97d 100644 --- a/Sensors/Sensor.ts +++ b/Sensors/Sensor.ts @@ -8,22 +8,28 @@ var base = require("../EV3Base.js"); var FilePathConstructor = base.FilePathConstructor; var softBoolean = base.softBoolean; -class AnalogSensor { +class GenericSensor { sensorPort: number; sensorIndex: number; + numValues: number; constructor(sensorPort: number) { this.sensorPort = sensorPort; this.sensorIndex = FilePathConstructor.sensorNumber(sensorPort); + + var numValuesProperty: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'num_values'); + + if (fs.exists(numValuesProperty)) + this.numValues = fs.readFileSync(numValuesProperty).toString().match(/[0-9A-Za-z._]+/)[0]; } - get analogValue(): number { - var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'value0'); - if (fs.existsSync(propertyPath)) + public getValue(valueN: number) { + var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'value' + valueN); + if (valueN < this.numValues && fs.existsSync(propertyPath)) return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; else throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); - } + } } -module.exports.AnalogSensor = AnalogSensor; \ No newline at end of file +module.exports.GenericSensor = GenericSensor; \ No newline at end of file From eb09fea033204a065b91fcae4017d249c84fd01d Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sun, 6 Jul 2014 13:01:06 -0700 Subject: [PATCH 20/38] Changed motor path construction and updated motor properties. Will not correctly control motors yet. --- EV3Base.ts | 98 +++++++++++++++++++++++++++++++++++------------------- Motor.ts | 8 +++-- 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 548fd75..75da2e5 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -1,23 +1,40 @@ /// var fs = require("fs"); var path = require('path'); +var Enumerable = require('linq'); /** * A module to handle path creation from known properties */ module FilePathConstructor { var motorDeviceDir: string = '/sys/class/tacho-motor/'; - var motorDirName: string = 'out{0}:motor:tacho'; + var motorDirName: string = 'tacho-motor{0}'; var ledDeviceDir: string = '/sys/class/leds/'; var ledDirName: string = 'ev3:{0}:{1}'; - export function motor(port: MotorPort) { - return path.join(motorDeviceDir, motorDirName.format(MotorPort[port]), '/'); + export function motorNumber(port: MotorPort) { + if (!fs.existsSync(motorDeviceDir)) + throw new Error('The motor class directory does not exist.'); + + + var motorFile = Enumerable.from(fs.readdirSync(motorDeviceDir)) + .firstOrDefault(file => fs.readFileSync( + path.join(motorDeviceDir, '/', file, '/port_name') + ).toString() + .indexOf('out' + port) == 0); + + + return motorFile.match(/[0-9]+/)[0]; } - export function motorProperty(port: MotorPort, property: MotorProperty) { - return path.join(motor(port), MotorProperty[property]); + + export function motor(index: number) { + return path.join(motorDeviceDir, motorDirName.format(index), '/'); + } + + export function motorProperty(index: number, property: MotorProperty) { + return path.join(motor(index), MotorProperty[property]); } export function ledBrightness(position: ledPosition, color: ledUnitColor) { @@ -72,43 +89,56 @@ enum MotorRunMode { } enum MotorProperty { - brake_mode, - hold_mode, + uevent, + subsystem, + device, + port_name, + type, position, - position_setpoint, + state, + duty_cycle, pulses_per_second, - ramp_up, - reset, + duty_cycle_sp, + pulses_per_second_sp, + time_sp, + position_sp, run_mode, - speed_setpoint, - subsystem, - type, - device, - polarity_mode, - position_mode, - power, - ramp_down, regulation_mode, + stop_modes, + stop_mode, + position_mode, + polarity_mode, + ramp_up_sp, + ramp_down_sp, + speed_regulation_P, + speed_regulation_I, + speed_regulation_D, + speed_regulation_K, run, - speed, - state, - time_setpoint, - uevent + estop, + reset, } var MotorPropertyValidation = { - 0: { type: 'string', values: ['on', 'off'] }, //brake_mode - 1: { type: 'string', values: ['on', 'off'] }, //hold_mode - 2: { type: 'number', min: -2147483648, max: 2147483648 }, //position - 3: { type: 'number', min: -2147483648, max: 2147483648 }, //position_setpoint - 7: { type: 'string', values: ['forever', 'time', 'position'] }, //run_mode - 8: { type: 'number', min: -100, max: 100 }, //speed_setpoint - 10: { type: 'string', values: ['tacho', 'minitacho'] }, //type - 14: { type: 'number', min: -100, max: 100 }, //power - 16: { type: 'string', values: ['on', 'off'] }, //regulation_mode - 17: { type: 'number', values: [0, 1] }, //run - 18: { type: 'number', min: -100, max: 100 }, //speed - 20: { type: 'number', min: 0 } //time_setpoint + 4: { type: 'string', values: ['tacho', 'minitacho'] }, //type + 5: { type: 'number', min: -2147483648, max: 2147483648 }, //position + 9: { type: 'number', min: -100, max: 100 }, //duty_cycle_sp + 10: { type: 'number', min: -2000, max: 2000 }, //pulses_per_second_sp + 11: { type: 'number', min: 0 }, //time_sp + 12: { type: 'number', min: -2147483648, max: 2147483648 }, //position_sp + 13: { type: 'string', values: ['forever', 'time', 'position'] }, //run_mode + 14: { type: 'string', values: ['on', 'off'] }, //regulation_mode + 16: { type: 'string', values: ['coast', 'brake', 'hold'] }, //stop_mode + 17: { type: 'string', values: ['absolute', 'relative'] }, //position_mode + 18: { type: 'string', values: ['positive', 'negative'] },//polarity_mode + 25: { type: 'number', values: [0, 1] }, //run + 19: { type: 'number' }, //ramp_up_sp + 20: { type: 'number' }, //ramp_down_sp + 21: { type: 'number' }, //speed_regulation_P + 22: { type: 'number' }, //speed_regulation_I + 23: { type: 'number' }, //speed_regulation_D + 24: { type: 'number' }, //speed_regulation_K + } diff --git a/Motor.ts b/Motor.ts index bfb659b..4927d25 100644 --- a/Motor.ts +++ b/Motor.ts @@ -16,7 +16,8 @@ var MotorRunMode = base.MotorRunMode; //Class to hold the basic function of the motor class Motor { - private port: MotorPort + private port: MotorPort; + private index: number; //Read-only properties get speed(): number { //Indication of relative speed @@ -40,7 +41,7 @@ class Motor { * @param {MotorProperty} property The property to read */ private readProperty(property: MotorProperty): string { - var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); + var propertyPath: string = FilePathConstructor.motorProperty(this.index, property); if (fs.existsSync(propertyPath)) return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; else @@ -118,7 +119,7 @@ class Motor { break; } - var propertyPath: string = FilePathConstructor.motorProperty(this.port, property); + var propertyPath: string = FilePathConstructor.motorProperty(this.index, property); if (fs.existsSync(propertyPath)) return fs.writeFileSync(propertyPath, value); @@ -203,6 +204,7 @@ class Motor { constructor(port: MotorPort) { this.port = port; + this.index = FilePathConstructor.motorIndex(port); } } From d67cd673ffbfe7244228d05b6da05cdc4d069836 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sun, 6 Jul 2014 23:05:28 -0700 Subject: [PATCH 21/38] Finished translation to new drivers and fixed previously hidden bugs --- EV3Base.ts | 21 ++------- Index.ts | 1 - Motor.ts | 128 ++++++++++++++++++++++++++++++++++----------------- package.json | 6 ++- 4 files changed, 93 insertions(+), 63 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 75da2e5..5ca7820 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -13,17 +13,16 @@ module FilePathConstructor { var ledDeviceDir: string = '/sys/class/leds/'; var ledDirName: string = 'ev3:{0}:{1}'; - export function motorNumber(port: MotorPort) { + export function motorIndex(port: MotorPort) { if (!fs.existsSync(motorDeviceDir)) throw new Error('The motor class directory does not exist.'); var motorFile = Enumerable.from(fs.readdirSync(motorDeviceDir)) .firstOrDefault(file => fs.readFileSync( - path.join(motorDeviceDir, '/', file, '/port_name') + path.join(motorDeviceDir, file, '/port_name') ).toString() - .indexOf('out' + port) == 0); - + .indexOf('out' + MotorPort[port]) == 0); return motorFile.match(/[0-9]+/)[0]; } @@ -142,19 +141,6 @@ var MotorPropertyValidation = { } -class motorRunOptions { - targetSpeed: number; //equates to speed_setpoint. Default: 0 - run: any; //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: true - regulationMode: any; //will accept numbers 0 and 1, strings 'off' and 'on', and booleans true and false. Default: false - time: number; //Time to run in milliseconds - - constructor(targetSpeed?: number, run?: any, regulationMode?: any) { - this.targetSpeed = targetSpeed; - this.run = run; - this.regulationMode = regulationMode; - } -} - enum MotorType { tacho, minitacho @@ -186,5 +172,4 @@ module.exports.softBoolean = softBoolean; module.exports.ledUnitColor = ledUnitColor; module.exports.ledColorSetting = ledColorSetting; module.exports.ledPosition = ledPosition; -module.exports.motorRunOptions = motorRunOptions; module.exports.MotorRunMode = MotorRunMode; \ No newline at end of file diff --git a/Index.ts b/Index.ts index d7b91b7..eb9196c 100644 --- a/Index.ts +++ b/Index.ts @@ -9,5 +9,4 @@ module.exports.LED = LED; module.exports.MotorPort = base.MotorPort; module.exports.ledColorSetting = base.ledColorSetting; module.exports.ledPosition = base.ledPosition; -module.exports.motorRunOptions = base.motorRunOptions; module.exports.MotorRunMode = base.MotorRunMode; \ No newline at end of file diff --git a/Motor.ts b/Motor.ts index 4927d25..7e9ba45 100644 --- a/Motor.ts +++ b/Motor.ts @@ -36,6 +36,10 @@ class Motor { return this.readProperty(MotorProperty.type); } + private scale(value: number, oldMin: number, oldMax: number, newMin: number, newMax: number): number { + return ((value - oldMin) / (oldMax - oldMin)) * (newMax - newMin) + newMin; + } + /** * Reads the value of a property from the file; includes error handling if the file doesn't exist * @param {MotorProperty} property The property to read @@ -50,13 +54,29 @@ class Motor { //Writable properties - //targetSpeed: The speed_setpoint + //targetSpeed: The speed setpoint get targetSpeed(): number { - return parseInt(this.readProperty(MotorProperty.speed_setpoint)); + if (this.regulationMode == 'on') { + switch (this.type) { + case MotorType[MotorType.tacho]: + return this.scale(this.readProperty(MotorProperty.pulses_per_second), -900, 900, -100, 100); + case MotorType[MotorType.minitacho]: + return this.scale(this.readProperty(MotorProperty.pulses_per_second), -1200, 1200, -100, 100); + } + } } set targetSpeed(value: number) { - this.writeProperty(MotorProperty.speed_setpoint, value); + if (this.regulationMode == 'on') { + switch (this.type) { + case MotorType[MotorType.tacho]: + this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(value, -100, 100, -900, 900))); + break; + case MotorType[MotorType.minitacho]: + this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(value, -100, 100, -1200, 1200))); + break; + } + } } //run: enables the motors. any type. @@ -68,22 +88,25 @@ class Motor { this.writeProperty(MotorProperty.run, softBoolean(value, 0, 1)); } - //holdMode: Will actively hold the motor position after it stops - get holdMode(): any { - return this.readProperty(MotorProperty.hold_mode); + //regulationMode + get regulationMode(): number { + return parseInt(this.readProperty(MotorProperty.regulation_mode)); } - set holdMode(value: any) { - this.writeProperty(MotorProperty.hold_mode, softBoolean(value, 'off', 'on')); + set regulationMode(value: number) { + if (this.run) + this.writeProperty(MotorProperty.regulation_mode, softBoolean(value, 'off', 'on')); + else + throw new Error('You must stop the motor before changing the regulation mode.'); } - //brakeMode: Will reverse the motor direction when it stops - get brakeMode(): any { - return this.readProperty(MotorProperty.brake_mode); + //stopMode: Choses how to stop the motor + get stopMode(): string { + return this.readProperty(MotorProperty.stop_mode); } - set brakeMode(value: any) { - this.writeProperty(MotorProperty.brake_mode, softBoolean(value, 'off', 'on')); + set stopMode(value: string) { + this.writeProperty(MotorProperty.stop_mode, value); } /** @@ -92,7 +115,6 @@ class Motor { */ private writeProperty(property: MotorProperty, value: any) { var propertySpec = MotorPropertyValidation[property]; - switch (propertySpec.type) { case 'number': if (isNaN(value)) @@ -100,11 +122,11 @@ class Motor { if (typeof propertySpec.min != 'undefined') if (value < propertySpec.min) - throw new Error('The specified value must be greater than or equal to' + propertySpec.min + '.'); + throw new Error('The specified value must be greater than or equal to ' + propertySpec.min + '. Property: ' + MotorProperty[property]); if (typeof propertySpec.max != 'undefined') if (value > propertySpec.max) - throw new Error('The specified value must be less than or equal to' + propertySpec.max + '.'); + throw new Error('The specified value must be less than or equal to ' + propertySpec.max + '. Property: ' + MotorProperty[property]); if (typeof propertySpec.values != 'undefined') if (propertySpec.values.indexOf(value) == -1) @@ -130,54 +152,70 @@ class Motor { /** * Starts the motor. */ - public startMotor(options: motorRunOptions) { + public startMotor(options: any) { for (var i in defaultMotorRunOptions) if (options[i] == undefined) options[i] = defaultMotorRunOptions[i]; if (options.time != undefined) { this.writeProperty(MotorProperty.run_mode, MotorRunMode[MotorRunMode.time]); - this.writeProperty(MotorProperty.time_setpoint, options.time); + this.writeProperty(MotorProperty.time_sp, options.time); } + else + this.writeProperty(MotorProperty.run_mode, MotorRunMode[MotorRunMode.forever]) this.writeProperty(MotorProperty.regulation_mode, softBoolean(options.regulationMode, 'off', 'on')); - this.writeProperty(MotorProperty.speed_setpoint, options.targetSpeed); - this.writeProperty(MotorProperty.run, softBoolean(options.run, 0, 1)); + if (softBoolean(options.regulationMode)) { + switch (this.type) { + case MotorType[MotorType.tacho]: + this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -900, 900))); + break; + case MotorType[MotorType.minitacho]: + this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -1200, 1200))); + break; + } + } + else + this.writeProperty(MotorProperty.duty_cycle_sp, options.targetSpeed); + + this.writeProperty(MotorProperty.stop_mode, options.stopMode); + this.writeProperty(MotorProperty.run, softBoolean(options.run, 0, 1)); } /** * Runs the motor to a specified position. Works well with holdMode and brakeMode. */ public runServo(options: any) { + for (var i in defaultServoRunOptions) + if (options[i] == undefined) + options[i] = defaultServoRunOptions[i]; + this.writeProperty(MotorProperty.run, 0); - this.writeProperty(MotorProperty.speed_setpoint, options.speed); + + switch (this.type) { + case MotorType[MotorType.tacho]: + this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -900, 900))); + break; + case MotorType[MotorType.minitacho]: + this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -1200, 1200))); + break; + } + this.writeProperty(MotorProperty.regulation_mode, 'on'); - if (!options.absolute) - this.writeProperty(MotorProperty.position, 0); + this.writeProperty(MotorProperty.position_mode, options.positionMode); - this.writeProperty(MotorProperty.position_setpoint, options.position); + this.writeProperty(MotorProperty.position_sp, options.position); + this.writeProperty(MotorProperty.stop_mode, options.stopMode); this.writeProperty(MotorProperty.run, 1); - - if (options.completeBehavior) { - switch (options.completeBehavior) { - case 'hold': - this.holdMode = true; - case 'brake': - this.brakeMode = true; - break; - - } - } } /** * Stops the motor by reversing the direction */ public brake() { - this.holdMode = false; - this.brakeMode = true; + this.stopMode = 'brake'; this.startMotor({ run: false }); } @@ -186,8 +224,7 @@ class Motor { * Stops the motor and actively holds it in place */ public hold() { - this.holdMode = true; - this.brakeMode = true; + this.stopMode = 'hold'; this.startMotor({ run: false }); } @@ -196,8 +233,7 @@ class Motor { * Turns off the motor but allows it to coast */ public coast() { - this.holdMode = false; - this.brakeMode = false; + this.stopMode = 'coast'; this.startMotor({ run: false }); } @@ -212,7 +248,15 @@ var defaultMotorRunOptions = { targetSpeed: 0, run: 1, regulationMode: false, - time: undefined + time: undefined, + stopMode: 'coast' +} + +var defaultServoRunOptions = { + targetSpeed: 30, + positionMode: 'relative', + position: 0, + stopMode: 'coast' } module.exports = Motor; \ No newline at end of file diff --git a/package.json b/package.json index fa8f263..35dd18b 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,13 @@ "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", "bugs": {"url": "http://github.com/WasabiFan/ev3dev-NodeJS/issues"}, "author": {"name": "WasabiFan", "email": "WasabiFan@outlook.com"}, - + + + "dependencies": {"linq": "3.x"}, "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js", "README.md"], "main": "Index.js", "repository" : { "type" : "git", "url" : "http://github.com/WasabiFan/ev3dev-NodeJS.git" } -} \ No newline at end of file +} From cdcb15b6befdc7db78450a97c19653e883322a7b Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sun, 6 Jul 2014 23:22:54 -0700 Subject: [PATCH 22/38] Modified README --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5715d0f..10e0696 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,12 @@ var ev3 = require('ev3dev'); //Create the motor on port A var motorA = new ev3.Motor(ev3.MotorPort.A); -//Run the motor at 60% power -motorA.startMotor({ targetSpeed: 60 }); - -//Wait five seconds before turning off the motor and letting it coast -setTimeout(function () { - motorA.coast(); -}, 5000); +//Run the motor at 60% power for five seconds, and then hold it in place +motorA.startMotor({ + targetSpeed: 60, + time: 5000, + stopMode: 'hold' +}); ``` LEDs From 03428d05fcfcd2a0c48445b8bfaadd7fa889e67e Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sun, 6 Jul 2014 23:52:36 -0700 Subject: [PATCH 23/38] Added debug log function and implimented logging in motors --- EV3Base.ts | 9 +++++++++ Motor.ts | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/EV3Base.ts b/EV3Base.ts index 5ca7820..da5ffa1 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -3,6 +3,9 @@ var fs = require("fs"); var path = require('path'); var Enumerable = require('linq'); +//Debug settings +DEBUG = true; + /** * A module to handle path creation from known properties */ @@ -77,6 +80,12 @@ function softBoolean(value: any, falseValue?: any, trueValue?: any) : boolean{ } } +module.exports.debugLog = function (text: string, ...args: any[]) { + if (DEBUG) { + console.log("DEBUG: " + text.format(args)); + } +} + enum MotorPort { A, B, C, D } diff --git a/Motor.ts b/Motor.ts index 7e9ba45..ec21c0e 100644 --- a/Motor.ts +++ b/Motor.ts @@ -46,6 +46,9 @@ class Motor { */ private readProperty(property: MotorProperty): string { var propertyPath: string = FilePathConstructor.motorProperty(this.index, property); + + base.debugLog('READING PROPERTY {0}', propertyPath); + if (fs.existsSync(propertyPath)) return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; else @@ -143,6 +146,8 @@ class Motor { var propertyPath: string = FilePathConstructor.motorProperty(this.index, property); + base.debugLog('WRITING PROPERTY {0}', propertyPath); + if (fs.existsSync(propertyPath)) return fs.writeFileSync(propertyPath, value); else @@ -153,6 +158,8 @@ class Motor { * Starts the motor. */ public startMotor(options: any) { + base.debugLog('STARTING MOTOR {0},{1} with options {2}', MotorPort[this.port], this.index, options); + for (var i in defaultMotorRunOptions) if (options[i] == undefined) options[i] = defaultMotorRunOptions[i]; @@ -187,6 +194,7 @@ class Motor { * Runs the motor to a specified position. Works well with holdMode and brakeMode. */ public runServo(options: any) { + base.debugLog('RUNNING SERVO {0},{1} with options {2}', MotorPort[this.port], this.index, options); for (var i in defaultServoRunOptions) if (options[i] == undefined) options[i] = defaultServoRunOptions[i]; @@ -241,6 +249,8 @@ class Motor { constructor(port: MotorPort) { this.port = port; this.index = FilePathConstructor.motorIndex(port); + + base.debugLog('MOTOR CREATED at index {0} on port {1}', this.index, MotorPort[this.port]); } } From 395844bfebded084271f0056e8b473f10d24487a Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 7 Jul 2014 14:08:13 -0700 Subject: [PATCH 24/38] Fixed some debug log issues --- EV3Base.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/EV3Base.ts b/EV3Base.ts index da5ffa1..1c612a7 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -82,7 +82,12 @@ function softBoolean(value: any, falseValue?: any, trueValue?: any) : boolean{ module.exports.debugLog = function (text: string, ...args: any[]) { if (DEBUG) { - console.log("DEBUG: " + text.format(args)); + console.log("DEBUG: " + text.replace(/{(\d+)}/g, function (match, i) { + return typeof args[i] != 'undefined' + ? (typeof args[i] == 'object' ? JSON.stringify(args[i]) : args[i]) + : match + ; + })); } } From 75ff7a41528e9c50639aecb17c3190e86589d9f8 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 7 Jul 2014 14:28:06 -0700 Subject: [PATCH 25/38] Incremented version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 35dd18b..64dfd49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ev3dev", - "version": "0.1.1", + "version": "0.2.0", "description": "An interface to control an EV3 running ev3dev from JavaScript.", "keywords": ["ev3dev"], "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", From e7603143b523bcf7daa965d9bf3774669d75be30 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 7 Jul 2014 15:28:35 -0700 Subject: [PATCH 26/38] Patched the npm release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64dfd49..3e5154e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ev3dev", - "version": "0.2.0", + "version": "0.2.1", "description": "An interface to control an EV3 running ev3dev from JavaScript.", "keywords": ["ev3dev"], "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", From b3ca0f12118e613704b7391099df101eef8312eb Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Mon, 7 Jul 2014 20:28:53 -0700 Subject: [PATCH 27/38] gitignore edits --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4c43fe6..f41a14a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.js \ No newline at end of file +*.js +node_modules/ From b5b3ba5540cfe4ca54bddb1d4acd77710ca67562 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Tue, 8 Jul 2014 18:19:13 -0700 Subject: [PATCH 28/38] Fixed error message --- Sensors/Sensor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sensors/Sensor.ts b/Sensors/Sensor.ts index bfcc97d..122793f 100644 --- a/Sensors/Sensor.ts +++ b/Sensors/Sensor.ts @@ -28,7 +28,7 @@ class GenericSensor { if (valueN < this.numValues && fs.existsSync(propertyPath)) return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; else - throw new Error('The property file could not be found. Either the specified motor is not available or the property does not exist.'); + throw new Error('The property file could not be found. Either the specified sensor is not available or the property does not exist.'); } } From 0a4b49c79bb722bc03c25b709906d48bffb32d99 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Wed, 16 Jul 2014 12:12:11 -0700 Subject: [PATCH 29/38] Changed the default debug setting and fixed some compatibility issues with ev3dev 1.0 --- EV3Base.ts | 2 +- Motor.ts | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 1c612a7..01f74a8 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -4,7 +4,7 @@ var path = require('path'); var Enumerable = require('linq'); //Debug settings -DEBUG = true; +DEBUG = false; /** * A module to handle path creation from known properties diff --git a/Motor.ts b/Motor.ts index ec21c0e..56b1e1e 100644 --- a/Motor.ts +++ b/Motor.ts @@ -20,18 +20,10 @@ class Motor { private index: number; //Read-only properties - get speed(): number { //Indication of relative speed - return parseInt(this.readProperty(MotorProperty.speed)); - } - get position(): number { //Number of tacho ticks return parseInt(this.readProperty(MotorProperty.position)); } - get power(): number { //The power being sent to the motor - return parseInt(this.readProperty(MotorProperty.power)); - } - get type(): string { //The type of motor return this.readProperty(MotorProperty.type); } @@ -83,11 +75,11 @@ class Motor { } //run: enables the motors. any type. - get run(): number { - return parseInt(this.readProperty(MotorProperty.run)); + get run(): any { + return !!parseInt(this.readProperty(MotorProperty.run)); } - set run(value: number) { + set run(value: any) { this.writeProperty(MotorProperty.run, softBoolean(value, 0, 1)); } @@ -120,6 +112,7 @@ class Motor { var propertySpec = MotorPropertyValidation[property]; switch (propertySpec.type) { case 'number': + //console.log(typeof value + ', ' + value); if (isNaN(value)) throw new Error('The specified value is not a number.'); From 4fa8259b8638f223032a5eb061561bbecdee901b Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Wed, 16 Jul 2014 12:15:34 -0700 Subject: [PATCH 30/38] Bumped version and published to NPM --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e5154e..804ac5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ev3dev", - "version": "0.2.1", + "version": "0.2.3", "description": "An interface to control an EV3 running ev3dev from JavaScript.", "keywords": ["ev3dev"], "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", From f9494ecbb189e9ea80cd2a9fdada5c423f754abd Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Thu, 17 Jul 2014 23:11:42 -0700 Subject: [PATCH 31/38] Changed homepage link --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 804ac5e..f0ea1e5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.2.3", "description": "An interface to control an EV3 running ev3dev from JavaScript.", "keywords": ["ev3dev"], - "homepage": "http://github.com/WasabiFan/ev3dev-NodeJS", + "homepage": "http://wasabifan.github.io/ev3dev-NodeJS/", "bugs": {"url": "http://github.com/WasabiFan/ev3dev-NodeJS/issues"}, "author": {"name": "WasabiFan", "email": "WasabiFan@outlook.com"}, From f75d40b862d52c2a05b2512a46917f23fea8dce8 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Fri, 18 Jul 2014 01:37:08 -0700 Subject: [PATCH 32/38] Full generic sensor support --- Sensors/Sensor.ts | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/Sensors/Sensor.ts b/Sensors/Sensor.ts index 122793f..2b0340e 100644 --- a/Sensors/Sensor.ts +++ b/Sensors/Sensor.ts @@ -18,18 +18,51 @@ class GenericSensor { this.sensorIndex = FilePathConstructor.sensorNumber(sensorPort); var numValuesProperty: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'num_values'); - - if (fs.exists(numValuesProperty)) + + if (fs.existsSync(numValuesProperty)) this.numValues = fs.readFileSync(numValuesProperty).toString().match(/[0-9A-Za-z._]+/)[0]; } public getValue(valueN: number) { - var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'value' + valueN); - if (valueN < this.numValues && fs.existsSync(propertyPath)) - return fs.readFileSync(propertyPath).toString().match(/[0-9A-Za-z._]+/)[0]; + + if (valueN < this.numValues) + return this.sterilePropertyRead('value' + valueN).match(/[0-9A-Za-z._]+/)[0]; + else + throw new Error('The value index must be less than ' + this.numValues); + } + + //Get the possible sensor modes + get modes(): string[] { + return this.sterilePropertyRead('modes').split(' '); + } + + //Get the current sensor mode + get mode(): string { + return this.sterilePropertyRead('mode'); + } + + private sterilePropertyRead(property) { + var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, property); + + if (fs.existsSync(propertyPath)) + return fs.readFileSync(propertyPath).toString().replace('\n', ''); + else + throw new Error('The property file could not be found. Either the specified sensor is not available or the property does not exist.'); + } + + //Set the sensor mode + set mode(value: string) { + this.sterilePropertyWrite('mode', value); + } + + private sterilePropertyWrite(property, value) { + var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, property); + + if (fs.existsSync(propertyPath)) + fs.writeFileSync(propertyPath, value); else throw new Error('The property file could not be found. Either the specified sensor is not available or the property does not exist.'); - } + } } module.exports.GenericSensor = GenericSensor; \ No newline at end of file From 2c09babe66c4e2af1c17800f179885eb3e3a8191 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Fri, 18 Jul 2014 11:26:34 -0700 Subject: [PATCH 33/38] Added sensors to the support list --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 10e0696..b4bee76 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ We currently support: - Run forever - Run time - Run servo/position +- Sensors + - Generic read support - LEDs Motors From 4f27746bbc1bd7f75ef2aca2f6e0cb2ed221b065 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Tue, 22 Jul 2014 17:55:28 -0700 Subject: [PATCH 34/38] General TypeScript housekeeping --- EV3Base.ts | 8 +- LED.ts | 4 +- Motor.ts | 20 +-- Sensors/Sensor.ts | 20 +-- linq.d.ts | 376 +++++++++++++++++++++------------------------- 5 files changed, 199 insertions(+), 229 deletions(-) diff --git a/EV3Base.ts b/EV3Base.ts index 15e5fcc..3df2807 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -2,10 +2,10 @@ /// var fs = require("fs"); var path = require('path'); -var Enumerable = require('linq'); +var Enumerable: linqjs.EnumerableStatic = require('linq'); //Debug settings -DEBUG = false; +var DEBUG = false; /** * A module to handle path creation from known properties @@ -76,7 +76,7 @@ interface String { } String.prototype.format = function () { - var args = arguments; + var args: IArguments = arguments; return this.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] @@ -157,7 +157,7 @@ enum MotorProperty { reset, } -var MotorPropertyValidation = { +var MotorPropertyValidation: any = { 4: { type: 'string', values: ['tacho', 'minitacho'] }, //type 5: { type: 'number', min: -2147483648, max: 2147483648 }, //position 9: { type: 'number', min: -100, max: 100 }, //duty_cycle_sp diff --git a/LED.ts b/LED.ts index d038363..e5190d9 100644 --- a/LED.ts +++ b/LED.ts @@ -1,7 +1,7 @@ /// /// -//Require modules and globalize some stuff +// Require modules and globalize some stuff var fs = require("fs"); var base = require("./EV3Base.js"); @@ -61,7 +61,7 @@ class LED { return new LedState( !!String.fromCharCode(fs.readFileSync(redPropertyPath)[0]), !!String.fromCharCode(fs.readFileSync(greenPropertyPath)[0]) - ); + ); else throw new Error('The file could not be found.'); } diff --git a/Motor.ts b/Motor.ts index 56b1e1e..1e49479 100644 --- a/Motor.ts +++ b/Motor.ts @@ -8,7 +8,7 @@ var base = require("./EV3Base.js"); var FilePathConstructor = base.FilePathConstructor; var MotorPort = base.MotorPort; var MotorProperty = base.MotorProperty; -var MotorPropertyValidation = base.MotorPropertyValidation; +var MotorPropertyValidation: any = base.MotorPropertyValidation; var MotorType = base.MotorType; var softBoolean = base.softBoolean; var motorRunOptions = base.motorRunOptions; @@ -50,8 +50,8 @@ class Motor { //Writable properties //targetSpeed: The speed setpoint - get targetSpeed(): number { - if (this.regulationMode == 'on') { + get targetSpeed(): number { + if (this.regulationMode == 1) { switch (this.type) { case MotorType[MotorType.tacho]: return this.scale(this.readProperty(MotorProperty.pulses_per_second), -900, 900, -100, 100); @@ -62,13 +62,13 @@ class Motor { } set targetSpeed(value: number) { - if (this.regulationMode == 'on') { + if (this.regulationMode == 1) { switch (this.type) { case MotorType[MotorType.tacho]: - this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(value, -100, 100, -900, 900))); + this.writeProperty(MotorProperty.pulses_per_second_sp, this.scale(value, -100, 100, -900, 900)); break; case MotorType[MotorType.minitacho]: - this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(value, -100, 100, -1200, 1200))); + this.writeProperty(MotorProperty.pulses_per_second_sp, this.scale(value, -100, 100, -1200, 1200)); break; } } @@ -169,10 +169,10 @@ class Motor { if (softBoolean(options.regulationMode)) { switch (this.type) { case MotorType[MotorType.tacho]: - this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -900, 900))); + this.writeProperty(MotorProperty.pulses_per_second_sp, this.scale(options.targetSpeed, -100, 100, -900, 900)); break; case MotorType[MotorType.minitacho]: - this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -1200, 1200))); + this.writeProperty(MotorProperty.pulses_per_second_sp, this.scale(options.targetSpeed, -100, 100, -1200, 1200)); break; } } @@ -196,10 +196,10 @@ class Motor { switch (this.type) { case MotorType[MotorType.tacho]: - this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -900, 900))); + this.writeProperty(MotorProperty.pulses_per_second_sp, this.scale(options.targetSpeed, -100, 100, -900, 900)); break; case MotorType[MotorType.minitacho]: - this.writeProperty(MotorProperty.pulses_per_second_sp, parseInt(this.scale(options.targetSpeed, -100, 100, -1200, 1200))); + this.writeProperty(MotorProperty.pulses_per_second_sp, this.scale(options.targetSpeed, -100, 100, -1200, 1200)); break; } diff --git a/Sensors/Sensor.ts b/Sensors/Sensor.ts index 2b0340e..133c1e7 100644 --- a/Sensors/Sensor.ts +++ b/Sensors/Sensor.ts @@ -18,7 +18,7 @@ class GenericSensor { this.sensorIndex = FilePathConstructor.sensorNumber(sensorPort); var numValuesProperty: string = FilePathConstructor.sensorProperty(this.sensorIndex, 'num_values'); - + if (fs.existsSync(numValuesProperty)) this.numValues = fs.readFileSync(numValuesProperty).toString().match(/[0-9A-Za-z._]+/)[0]; } @@ -35,34 +35,34 @@ class GenericSensor { get modes(): string[] { return this.sterilePropertyRead('modes').split(' '); } - + //Get the current sensor mode get mode(): string { - return this.sterilePropertyRead('mode'); - } - - private sterilePropertyRead(property) { + return this.sterilePropertyRead('mode'); + } + + private sterilePropertyRead(property: string): string { var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, property); if (fs.existsSync(propertyPath)) return fs.readFileSync(propertyPath).toString().replace('\n', ''); else throw new Error('The property file could not be found. Either the specified sensor is not available or the property does not exist.'); - } + } //Set the sensor mode set mode(value: string) { this.sterilePropertyWrite('mode', value); - } + } - private sterilePropertyWrite(property, value) { + private sterilePropertyWrite(property: string, value: any) { var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, property); if (fs.existsSync(propertyPath)) fs.writeFileSync(propertyPath, value); else throw new Error('The property file could not be found. Either the specified sensor is not available or the property does not exist.'); - } + } } module.exports.GenericSensor = GenericSensor; \ No newline at end of file diff --git a/linq.d.ts b/linq.d.ts index 7da0cf9..6699a8a 100644 --- a/linq.d.ts +++ b/linq.d.ts @@ -1,222 +1,192 @@ -// Type definitions for linq.js 2.2 -// Project: http://linqjs.codeplex.com/ -// Definitions by: Marcin Najder -// Definitions: https://github.com/borisyankov/DefinitelyTyped +// Typing for linq.js, ver 3.0.3-Beta4 -// todo: jQuery plugin, RxJS Binding - -declare module linq { +declare module linqjs { + interface IEnumerator { + current(): any; + moveNext(): boolean; + dispose(): void; + } interface EnumerableStatic { - Choice(...contents: any[]): Enumerable; - Choice(contents: any[]): Enumerable; - Cycle(...contents: any[]): Enumerable; - Cycle(contents: any[]): Enumerable; - Empty(): Enumerable; - From(obj: any[]): Enumerable; - From(obj: any): Enumerable; - Return(element: any): Enumerable; - Matches(input: string, pattern: RegExp): Enumerable; - Matches(input: string, pattern: string, flags?: string): Enumerable; - Range(start: number, count: number, step?: number): Enumerable; - RangeDown(start: number, count: number, step?: number): Enumerable; - RangeTo(start: number, to: number, step?: number): Enumerable; - Repeat(obj: any, count?: number): Enumerable; - RepeatWithFinalize(initializer: () => any, finalizer: (resource: any) =>void ): Enumerable; - Generate(func: () => any, count?: number): Enumerable; - Generate(func: string, count?: number): Enumerable; - ToInfinity(start?: number, step?: number): Enumerable; - ToNegativeInfinity(start?: number, step?: number): Enumerable; - Unfold(seed, func: ($) => any): Enumerable; - Unfold(seed, func: string): Enumerable; + Utils: { + createLambda(expression: any): (...params: any[]) => any; + createEnumerable(getEnumerator: () => IEnumerator): Enumerable; + createEnumerator(initialize: () => void, tryGetNext: () => boolean, dispose: () => void): IEnumerator; + extendTo(type: any): void; + }; + choice(...params: any[]): Enumerable; + cycle(...params: any[]): Enumerable; + empty(): Enumerable; + from(): Enumerable; + from(obj: Enumerable): Enumerable; + from(obj: string): Enumerable; + from(obj: number): Enumerable; + from(obj: { length: number;[x: number]: any; }): Enumerable; + from(obj: any): Enumerable; + make(element: any): Enumerable; + matches(input: string, pattern: RegExp): Enumerable; + matches(input: string, pattern: string, flags?: string): Enumerable; + range(start: number, count: number, step?: number): Enumerable; + rangeDown(start: number, count: number, step?: number): Enumerable; + rangeTo(start: number, to: number, step?: number): Enumerable; + repeat(element: any, count?: number): Enumerable; + repeatWithFinalize(initializer: () => any, finalizer: (element) => void): Enumerable; + generate(func: () => any, count?: number): Enumerable; + toInfinity(start?: number, step?: number): Enumerable; + toNegativeInfinity(start?: number, step?: number): Enumerable; + unfold(seed: any, func: (value: any) => any): Enumerable; + defer(enumerableFactory: () => Enumerable): Enumerable; } interface Enumerable { - //Projection and Filtering Methods - CascadeBreadthFirst(func: ($) => any[], resultSelector: (v, i: number) => any): Enumerable; - CascadeBreadthFirst(func: string, resultSelector: string): Enumerable; - CascadeDepthFirst(func: ($) => any[], resultSelector: (v, i: number) => any): Enumerable; - CascadeDepthFirst(func: string, resultSelector: string): Enumerable; - Flatten(...items: any[]): Enumerable; - Pairwise(selector: (prev, next) => any): Enumerable; - Pairwise(selector: string): Enumerable; - Scan(func: (a, b) => any): Enumerable; - Scan(func: string): Enumerable; - Scan(seed, func: (a, b) => any, resultSelector?: ($) => any): Enumerable; - Scan(seed, func: string, resultSelector?: string): Enumerable; - Select(selector: ($, i: number) => any): Enumerable; - Select(selector: string): Enumerable; - SelectMany(collectionSelector: ($, i: number) => any[], resultSelector?: ($, item) => any): Enumerable; - SelectMany(collectionSelector: ($, i: number) => Enumerable, resultSelector?: ($, item) => any): Enumerable; - SelectMany(collectionSelector: string, resultSelector?: string): Enumerable; - Where(predicate: ($, i: number) => boolean): Enumerable; - Where(predicate: string): Enumerable; - OfType(type: Function): Enumerable; - Zip(second: any[], selector: (v1, v2, i: number) => any): Enumerable; - Zip(second: any[], selector: string): Enumerable; - Zip(second: Enumerable, selector: (v1, v2, i: number) => any): Enumerable; - Zip(second: Enumerable, selector: string): Enumerable; - //Join Methods - Join(inner: any[], outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2) => any, compareSelector?: (v) => any): Enumerable; - Join(inner: any[], outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; - Join(inner: Enumerable, outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2) => any, compareSelector?: (v) => any): Enumerable; - Join(inner: Enumerable, outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; - GroupJoin(inner: any[], outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2: Enumerable) => any, compareSelector?: (v) => any): Enumerable; - GroupJoin(inner: any[], outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; - GroupJoin(inner: Enumerable, outerKeySelector: (v1) => any, innerKeySelector: (v1) => any, resultSelector: (v1, v2: Enumerable) => any, compareSelector?: (v) => any): Enumerable; - GroupJoin(inner: Enumerable, outerKeySelector: string, innerKeySelector: string, resultSelector: string, compareSelector?: string): Enumerable; - //Set Methods - All(predicate: ($) => boolean): boolean; - All(predicate: string): boolean; - Any(predicate?: ($) => boolean): boolean; - Any(predicate?: string): boolean; - Concat(second: any[]): Enumerable; - Concat(second: Enumerable): Enumerable; - Insert(index: number, second: any[]): Enumerable; - Insert(index: number, second: Enumerable): Enumerable; - Alternate(value): Enumerable; - Contains(value, compareSelector?: ($) => any): boolean; - Contains(value, compareSelector?: string): boolean; - DefaultIfEmpty(defaultValue): Enumerable; - Distinct(compareSelector?: ($) => any): Enumerable; - Distinct(compareSelector?: string): Enumerable; - Except(second: any[], compareSelector?: ($) => any): Enumerable; - Except(second: any[], compareSelector?: string): Enumerable; - Except(second: Enumerable, compareSelector?: ($) => any): Enumerable; - Except(second: Enumerable, compareSelector?: string): Enumerable; - Intersect(second: any[], compareSelector?: ($) => any): Enumerable; - Intersect(second: any[], compareSelector?: string): Enumerable; - Intersect(second: Enumerable, compareSelector?: ($) => any): Enumerable; - Intersect(second: Enumerable, compareSelector?: string): Enumerable; - SequenceEqual(second: any[], compareSelector?: ($) => any): boolean; - SequenceEqual(second: any[], compareSelector?: string): boolean; - SequenceEqual(second: Enumerable, compareSelector?: ($) => any): boolean; - SequenceEqual(second: Enumerable, compareSelector?: string): boolean; - Union(second: any[], compareSelector?: ($) => any): Enumerable; - Union(second: any[], compareSelector?: string): Enumerable; - Union(second: Enumerable, compareSelector?: ($) => any): Enumerable; - Union(second: Enumerable, compareSelector?: string): Enumerable; - //Ordering Methods - OrderBy(keySelector?: ($) => any): OrderedEnumerable; - OrderBy(keySelector?: string): OrderedEnumerable; - OrderByDescending(keySelector?: ($) => any): OrderedEnumerable; - OrderByDescending(keySelector?: string): OrderedEnumerable; - Reverse(): Enumerable; - Shuffle(): Enumerable; - //Grouping Methods - GroupBy(keySelector: ($) => any, elementSelector?: ($) => any, resultSelector?: (key, e) => any, compareSelector?: ($) =>any): Enumerable; - GroupBy(keySelector: string, elementSelector?: string, resultSelector?: string, compareSelector?: string): Enumerable; - PartitionBy(keySelector: ($) => any, elementSelector?: ($) => any, resultSelector?: (key, e) => any, compareSelector?: ($) =>any): Enumerable; - PartitionBy(keySelector: string, elementSelector?: string, resultSelector?: string, compareSelector?: string): Enumerable; - BufferWithCount(count: number): Enumerable; - // Aggregate Methods - Aggregate(func: (a, b) => any); - Aggregate(seed, func: (a, b) => any, resultSelector?: ($) => any); - Aggregate(func: string); - Aggregate(seed, func: string, resultSelector?: string); - Average(selector?: ($) => number): number; - Average(selector?: string): number; - Count(predicate?: ($) => boolean): number; - Count(predicate?: string): number; - Max(selector?: ($) => number): number; - Max(selector?: string): number; - Min(selector?: ($) => number): number; - Min(selector?: string): number; - MaxBy(selector: ($) => number): any; - MaxBy(selector: string): any; - MinBy(selector: ($) => number): any; - MinBy(selector: string): any; - Sum(selector?: ($) => number): number; - Sum(selector?: string): number; - //Paging Methods - ElementAt(index: number): any; - ElementAtOrDefault(index: number, defaultValue): any; - First(predicate?: ($) => boolean): any; - First(predicate?: string): any; - FirstOrDefault(defaultValue, predicate?: ($) => boolean): any; - FirstOrDefault(defaultValue, predicate?: string): any; - Last(predicate?: ($) => boolean): any; - Last(predicate?: string): any; - LastOrDefault(defaultValue, predicate?: ($) => boolean): any; - LastOrDefault(defaultValue, predicate?: string): any; - Single(predicate?: ($) => boolean): any; - Single(predicate?: string): any; - SingleOrDefault(defaultValue, predicate?: ($) => boolean): any; - SingleOrDefault(defaultValue, predicate?: string): any; - Skip(count: number): Enumerable; - SkipWhile(predicate: ($, i: number) => boolean): Enumerable; - SkipWhile(predicate: string): Enumerable; - Take(count: number): Enumerable; - TakeWhile(predicate: ($, i: number) => boolean): Enumerable; - TakeWhile(predicate: string): Enumerable; - TakeExceptLast(count?: number): Enumerable; - TakeFromLast(count: number): Enumerable; - IndexOf(item): number; - LastIndexOf(item): number; - // Convert Methods - ToArray(): any[]; - ToLookup(keySelector: ($) => any, elementSelector?: ($) => any, compareSelector?: (key) => any): Lookup; - ToLookup(keySelector: string, elementSelector?: string, compareSelector?: string): Lookup; - ToObject(keySelector: ($) => string, elementSelector: ($) => any): any; - ToObject(keySelector: string, elementSelector: string): any; - ToDictionary(keySelector: ($) => any, elementSelector: ($) => any, compareSelector?: (key) => any): Dictionary; - ToDictionary(keySelector: string, elementSelector: string, compareSelector?: string): Dictionary; - ToJSON(replacer?: (key, value) => any, space?: number): string; - ToJSON(replacer?: string, space?: number): string; - ToString(separator?: string, selector?: ($) =>any): string; - ToString(separator?: string, selector?: string): string; - //Action Methods - Do(action: ($, i: number) => void ): Enumerable; - Do(action: string): Enumerable; - ForEach(action: ($, i: number) => void ): void; - ForEach(func: ($, i: number) => boolean): void; - ForEach(action_func: string): void; - Write(separator?: string, selector?: ($) =>any): void; - Write(separator?: string, selector?: string): void; - WriteLine(selector?: ($) =>any): void; - Force(): void; - //Functional Methods - Let(func: (e: Enumerable) => Enumerable): Enumerable; - Share(): Enumerable; - MemoizeAll(): Enumerable; - //Error Handling Methods - Catch(handler: (error: Error) => void ): Enumerable; - Catch(handler: string): Enumerable; - Finally(finallyAction: () => void ): Enumerable; - Finally(finallyAction: string): Enumerable; - //For Debug Methods - Trace(message?: string, selector?: ($) =>any): Enumerable; - Trace(message?: string, selector?: string): Enumerable; + constructor(getEnumerator: () => IEnumerator); + getEnumerator(): IEnumerator; + + // Extension Methods + traverseBreadthFirst(func: (element: any) => Enumerable, resultSelector?: (element: any, nestLevel: number) => any): Enumerable; + traverseDepthFirst(func: (element: any) => Enumerable, resultSelector?: (element: any, nestLevel: number) => any): Enumerable; + flatten(): Enumerable; + pairwise(selector: (prev: any, current: any) => any): Enumerable; + scan(func: (prev: any, current: any) => any): Enumerable; + scan(seed: any, func: (prev: any, current: any) => any): Enumerable; + select(selector: (element: any, index: number) => any): Enumerable; + selectMany(collectionSelector: (element: any, index: number) => any[], resultSelector?: (outer: any, inner: any) => any): Enumerable; + selectMany(collectionSelector: (element: any, index: number) => Enumerable, resultSelector?: (outer: any, inner: any) => any): Enumerable; + selectMany(collectionSelector: (element: any, index: number) => { length: number;[x: number]: any; }, resultSelector?: (outer: any, inner: any) => any): Enumerable; + where(predicate: (element: any, index: number) => boolean): Enumerable; + choose(selector: (element: any, index: number) => any): Enumerable; + ofType(type: any): Enumerable; + zip(second: any[], resultSelector: (first: any, second: any, index: number) => any): Enumerable; + zip(second: Enumerable, resultSelector: (first: any, second: any, index: number) => any): Enumerable; + zip(second: { length: number;[x: number]: any; }, resultSelector: (first: any, second: any, index: number) => any): Enumerable; + zip(...params: any[]): Enumerable; // last one is selector + merge(second: any[], resultSelector: (first: any, second: any, index: number) => any): Enumerable; + merge(second: Enumerable, resultSelector: (first: any, second: any, index: number) => any): Enumerable; + merge(second: { length: number;[x: number]: any; }, resultSelector: (first: any, second: any, index: number) => any): Enumerable; + merge(...params: any[]): Enumerable; // last one is selector + join(inner: Enumerable, outerKeySelector: (outer: any) => any, innerKeySelector: (inner: any) => any, resultSelector: (outer: any, inner: any) => any, compareSelector?: (obj: any) => any): Enumerable; + groupJoin(inner: Enumerable, outerKeySelector: (outer: any) => any, innerKeySelector: (inner: any) => any, resultSelector: (outer: any, inner: any) => any, compareSelector?: (obj: any) => any): Enumerable; + all(predicate: (element: any) => boolean): boolean; + any(predicate?: (element: any) => boolean): boolean; + isEmpty(): boolean; + concat(...sequences: any[]): Enumerable; + insert(index: number, second: any[]): Enumerable; + insert(index: number, second: Enumerable): Enumerable; + insert(index: number, second: { length: number;[x: number]: any; }): Enumerable; + alternate(alternateValue: any): Enumerable; + alternate(alternateSequence: any[]): Enumerable; + alternate(alternateSequence: Enumerable): Enumerable; + contains(value: any, compareSelector: (element: any) => any): Enumerable; + defaultIfEmpty(defaultValue?: any): Enumerable; + distinct(compareSelector?: (element: any) => any): Enumerable; + distinctUntilChanged(compareSelector: (element: any) => any): Enumerable; + except(second: any[], compareSelector?: (element: any) => any): Enumerable; + except(second: { length: number;[x: number]: any; }, compareSelector?: (element: any) => any): Enumerable; + except(second: Enumerable, compareSelector?: (element: any) => any): Enumerable; + intersect(second: any[], compareSelector?: (element: any) => any): Enumerable; + intersect(second: { length: number;[x: number]: any; }, compareSelector?: (element: any) => any): Enumerable; + intersect(second: Enumerable, compareSelector?: (element: any) => any): Enumerable; + sequenceEqual(second: any[], compareSelector?: (element: any) => any): Enumerable; + sequenceEqual(second: { length: number;[x: number]: any; }, compareSelector?: (element: any) => any): Enumerable; + sequenceEqual(second: Enumerable, compareSelector?: (element: any) => any): Enumerable; + union(second: any[], compareSelector?: (element: any) => any): Enumerable; + union(second: { length: number;[x: number]: any; }, compareSelector?: (element: any) => any): Enumerable; + union(second: Enumerable, compareSelector?: (element: any) => any): Enumerable; + orderBy(keySelector: (element: any) => any): OrderedEnumerable; + orderByDescending(keySelector: (element: any) => any): OrderedEnumerable; + reverse(): Enumerable; + shuffle(): Enumerable; + weightedSample(weightSelector: (element: any) => any): Enumerable; + groupBy(keySelector: (element: any) => any, elementSelector?: (element: any) => any, resultSelector?: (key: any, element: any) => any, compareSelector?: (element: any) => any): Enumerable; + partitionBy(keySelector: (element: any) => any, elementSelector?: (element: any) => any, resultSelector?: (key: any, element: any) => any, compareSelector?: (element: any) => any): Enumerable; + buffer(count: number): Enumerable; + aggregate(func: (prev: any, current: any) => any): any; + aggregate(seed: any, func: (prev: any, current: any) => any, resultSelector?: (last: any) => any): any; + average(selector?: (element: any) => any): number; + count(predicate?: (element: any, index: number) => boolean): number; + max(selector?: (element: any) => any): number; + min(selector?: (element: any) => any): number; + maxBy(keySelector: (element: any) => any): any; + minBy(keySelector: (element: any) => any): any; + sum(selector?: (element: any) => any): number; + elementAt(index: number): any; + elementAtOrDefault(index: number, defaultValue?: any): any; + first(predicate?: (element: any, index: number) => boolean): any; + firstOrDefault(predicate?: (element: any, index: number) => boolean, defaultValue?: any): any; + last(predicate?: (element: any, index: number) => boolean): any; + lastOrDefault(predicate?: (element: any, index: number) => boolean, defaultValue?: any): any; + single(predicate?: (element: any, index: number) => boolean): any; + singleOrDefault(predicate?: (element: any, index: number) => boolean, defaultValue?: any): any; + skip(count: number): Enumerable; + skipWhile(predicate: (element: any, index: number) => boolean): Enumerable; + take(count: number): Enumerable; + takeWhile(predicate: (element: any, index: number) => boolean): Enumerable; + takeExceptLast(count?: number): Enumerable; + takeFromLast(count: number): Enumerable; + indexOf(item: any): number; + indexOf(predicate: (element: any, index: number) => boolean): number; + lastIndexOf(item: any): number; + lastIndexOf(predicate: (element: any, index: number) => boolean): number; + asEnumerable(): Enumerable; + toArray(): any[]; + toLookup(keySelector: (element: any) => any, elementSelector?: (element: any) => any, compareSelector?: (element: any) => any): Lookup; + toObject(keySelector: (element: any) => any, elementSelector?: (element: any) => any): Object; + toDictionary(keySelector: (element: any) => any, elementSelector?: (element: any) => any, compareSelector?: (element: any) => any): Dictionary; + toJSONString(replacer: (key: string, value: any) => any): string; + toJSONString(replacer: any[]): string; + toJSONString(replacer: (key: string, value: any) => any, space: any): string; + toJSONString(replacer: any[], space: any): string; + toJoinedString(separator?: string, selector?: (element: any, index: number) => any): string; + doAction(action: (element: any, index: number) => void): Enumerable; + doAction(action: (element: any, index: number) => boolean): Enumerable; + forEach(action: (element: any, index: number) => void): void; + forEach(action: (element: any, index: number) => boolean): void; + write(separator?: string, selector?: (element: any) => any): void; + writeLine(selector?: (element: any) => any): void; + force(): void; + letBind(func: (source: Enumerable) => any[]): Enumerable; + letBind(func: (source: Enumerable) => { length: number;[x: number]: any; }): Enumerable; + letBind(func: (source: Enumerable) => Enumerable): Enumerable; + share(): DisposableEnumerable; + memoize(): DisposableEnumerable; + catchError(handler: (exception: any) => void): Enumerable; + finallyAction(finallyAction: () => void): Enumerable; + log(selector?: (element: any) => void): Enumerable; + trace(message?: string, selector?: (element: any) => void): Enumerable; } interface OrderedEnumerable extends Enumerable { - ThenBy(keySelector: ($) => any): OrderedEnumerable; - ThenBy(keySelector: string): OrderedEnumerable; - ThenByDescending(keySelector: ($) => any): OrderedEnumerable; - ThenByDescending(keySelector: string): OrderedEnumerable; + createOrderedEnumerable(keySelector: (element: any) => any, descending: boolean): OrderedEnumerable; + thenBy(keySelector: (element: any) => any): OrderedEnumerable; + thenByDescending(keySelector: (element: any) => any): OrderedEnumerable; } - interface Grouping extends Enumerable { - Key(); + interface DisposableEnumerable extends Enumerable { + dispose(): void; + } + + interface Dictionary { + add(key: any, value: any): void; + get(key: any): any; + set(key: any, value: any): boolean; + contains(key: any): boolean; + clear(): void; + remove(key: any): void; + count(): number; + toEnumerable(): Enumerable; // Enumerable } interface Lookup { - Count(): number; - Get(key): Enumerable; - Contains(key): boolean; - ToEnumerable(): Enumerable; + count(): number; + get(key: any): Enumerable; + contains(key: any): boolean; + toEnumerable(): Enumerable; // Enumerable } - interface Dictionary { - Add(key, value): void; - Get(key): any; - Set(key, value): boolean; - Contains(key): boolean; - Clear(): void; - Remove(key): void; - Count(): number; - ToEnumerable(): Enumerable; + interface Grouping extends Enumerable { + key(): any; } } -declare var Enumerable: linq.EnumerableStatic; +// export definition +declare var Enumerable: linqjs.EnumerableStatic; From e279a3ba25a9d56cd967a45814933a813d609b23 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Tue, 22 Jul 2014 21:26:18 -0700 Subject: [PATCH 35/38] Added some classes for specific sensors; NXT ultrasonic sensor has an unknown unit issue --- EV3Base.ts | 4 ++++ Index.ts | 8 +++++-- Sensors/Sensor.ts | 34 +++++++++++++++++++--------- Sensors/SimpleSensors.ts | 48 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 Sensors/SimpleSensors.ts diff --git a/EV3Base.ts b/EV3Base.ts index 3df2807..ae1c46e 100644 --- a/EV3Base.ts +++ b/EV3Base.ts @@ -91,13 +91,17 @@ String.prototype.format = function () { function softBoolean(value: any, falseValue?: any, trueValue?: any): boolean { switch (value) { case 0: + case '0': case 'off': case false: + case 'false': return falseValue == undefined ? false : falseValue; case 1: + case '1': case 'on': case true: + case 'true': return trueValue == undefined ? true : trueValue; default: diff --git a/Index.ts b/Index.ts index 5374fbf..9ef3d6a 100644 --- a/Index.ts +++ b/Index.ts @@ -2,11 +2,15 @@ var base = require("./EV3Base.js"); var LED = require("./LED.js"); var Motor = require("./Motor.js"); -var Sensors = require("./Sensors/Sensor.js"); +var Sensor = require("./Sensors/Sensor.js"); +var SimpleSensors = require("./Sensors/SimpleSensors.js"); module.exports.Motor = Motor; module.exports.LED = LED; -module.exports.GenericSensor = Sensors.GenericSensor; + +module.exports.GenericSensor = Sensor; +module.exports.TouchSensor = SimpleSensors.TouchSensor; +module.exports.UltrasonicSensor = SimpleSensors.UltrasonicSensor; module.exports.MotorPort = base.MotorPort; module.exports.ledColorSetting = base.ledColorSetting; diff --git a/Sensors/Sensor.ts b/Sensors/Sensor.ts index 133c1e7..18c0d97 100644 --- a/Sensors/Sensor.ts +++ b/Sensors/Sensor.ts @@ -1,5 +1,4 @@ /// -/// //Require modules and globalize some stuff var fs = require("fs"); @@ -23,25 +22,40 @@ class GenericSensor { this.numValues = fs.readFileSync(numValuesProperty).toString().match(/[0-9A-Za-z._]+/)[0]; } - public getValue(valueN: number) { + public getValue(valueN: number): string { + var val; if (valueN < this.numValues) - return this.sterilePropertyRead('value' + valueN).match(/[0-9A-Za-z._]+/)[0]; + val = this.readProperty('value' + valueN); else throw new Error('The value index must be less than ' + this.numValues); + + val = val.match(/[0-9A-Za-z._]+/)[0] + + var dpVal = val / Math.pow(10, parseInt(this.readProperty('dp'))); + + if (!isNaN(dpVal)) + return dpVal; + + return val; } //Get the possible sensor modes get modes(): string[] { - return this.sterilePropertyRead('modes').split(' '); + return this.readProperty('modes').split(' '); } //Get the current sensor mode get mode(): string { - return this.sterilePropertyRead('mode'); + return this.readProperty('mode'); } - private sterilePropertyRead(property: string): string { + //Get the sensor type_id + get typeId(): string { + return this.readProperty('type_id'); + } + + private readProperty(property: string): string { var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, property); if (fs.existsSync(propertyPath)) @@ -52,12 +66,12 @@ class GenericSensor { //Set the sensor mode set mode(value: string) { - this.sterilePropertyWrite('mode', value); + this.writeProperty('mode', value); } - private sterilePropertyWrite(property: string, value: any) { + private writeProperty(property: string, value: any) { var propertyPath: string = FilePathConstructor.sensorProperty(this.sensorIndex, property); - + if (fs.existsSync(propertyPath)) fs.writeFileSync(propertyPath, value); else @@ -65,4 +79,4 @@ class GenericSensor { } } -module.exports.GenericSensor = GenericSensor; \ No newline at end of file +module.exports = GenericSensor; \ No newline at end of file diff --git a/Sensors/SimpleSensors.ts b/Sensors/SimpleSensors.ts new file mode 100644 index 0000000..f792173 --- /dev/null +++ b/Sensors/SimpleSensors.ts @@ -0,0 +1,48 @@ +/// + +var GenericSensor = require('./Sensor.js'); +var base = require("../EV3Base.js"); + +var softBoolean = base.softBoolean; + +class TouchSensor extends GenericSensor { + get touchState(): boolean { + return softBoolean(this.getValue(0)); + } +} + +class UltrasonicSensor extends GenericSensor { + constructor(sensorPort: number) { + super(sensorPort); + this.unitMode = 'in'; + } + + get unitMode(): string { + switch (this.mode) { + case 'US-DIST-CM': + case 'US-SI-CM': + case 'NXT-US-CM': + case 'NXT-US-SI-CM': + return 'CM'; + case 'US-DIST-IN': + case 'US-SI-IN': + case 'NXT-US-IN': + case 'NXT-US-SI-IN': + return 'IN'; + } + } + + set unitMode(unit: string) { + if (parseInt(this.typeId) == 5) + this.mode = 'NXT-US-' + unit.toUpperCase(); + else + this.mode = 'US-DIST-' + unit.toUpperCase(); + } + + get distanceValue(): number { + return parseFloat(this.getValue(0)); + } +} + +module.exports.TouchSensor = TouchSensor; +module.exports.UltrasonicSensor = UltrasonicSensor; \ No newline at end of file From 3cd4f12e05d368bd78d2b6c97108e3391ea66498 Mon Sep 17 00:00:00 2001 From: WasabiFan Date: Sun, 3 Aug 2014 15:05:44 -0700 Subject: [PATCH 36/38] Add sensors to NPM package --- README.md | 2 ++ package.json | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b4bee76..43d0ba0 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ We currently support: - Generic read support - LEDs +**NOTE**: This library should be treated like an alpha release. The APIs are still changing rapidly, and the functionality cannot be fully tested until the codebase is more stable. + Motors ------ ``` diff --git a/package.json b/package.json index 63c5fe0..abe7d37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ev3dev", - "version": "0.2.3", + "version": "0.3.1", "description": "An interface to control an EV3 running ev3dev from JavaScript.", "keywords": ["ev3dev"], "homepage": "http://wasabifan.github.io/ev3dev-NodeJS/", @@ -8,7 +8,7 @@ "author": {"name": "WasabiFan", "email": "WasabiFan@outlook.com"}, "dependencies": {"linq": "3.x"}, - "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js", "README.md"], + "files": ["EV3Base.js", "LED.js", "Motor.js", "Index.js", "README.md", "Sensors/Sensor.js", "Sensors/SimpleSensors.js"], "main": "Index.js", "repository" : { "type" : "git", From 39509dff884c12864879db62e2eb0f57dd630fe7 Mon Sep 17 00:00:00 2001 From: Wasabi Fan Date: Sat, 6 Sep 2014 22:51:51 -0700 Subject: [PATCH 37/38] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 43d0ba0..d04a3de 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +
+**IMPORTANT NOTE: AS OF 9/6/2014, ALL WORK HAS STOPPED IN THIS REPO. Development will continue here: http://github.com/fdetro/ev3dev-lang in the `language-binding-unification` branch.** +
+ ev3dev-NodeJS ============= @@ -49,4 +53,4 @@ rightLED.color = ev3.ledColorSetting.red; -Simple, right? Learn more about the [Motor](https://github.com/WasabiFan/ev3dev-NodeJS/wiki/Motors) and [LED](https://github.com/WasabiFan/ev3dev-NodeJS/wiki/LEDs) APIs on the Wiki. \ No newline at end of file +Simple, right? Learn more about the [Motor](https://github.com/WasabiFan/ev3dev-NodeJS/wiki/Motors) and [LED](https://github.com/WasabiFan/ev3dev-NodeJS/wiki/LEDs) APIs on the Wiki. From fb7bc3df246eb4848a684c94d406799ace118dc1 Mon Sep 17 00:00:00 2001 From: Wasabi Fan Date: Sun, 14 Sep 2014 13:15:32 -0700 Subject: [PATCH 38/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d04a3de..52d1e46 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-**IMPORTANT NOTE: AS OF 9/6/2014, ALL WORK HAS STOPPED IN THIS REPO. Development will continue here: http://github.com/fdetro/ev3dev-lang in the `language-binding-unification` branch.** +**IMPORTANT NOTE: AS OF 9/6/2014, ALL WORK HAS STOPPED IN THIS REPO. Development will continue here: http://github.com/ev3dev/ev3dev-lang in the `language-binding-unification` branch.**
ev3dev-NodeJS