├── README.md
├── data
└── README
├── examples
└── README
├── lib
├── bcpkix-jdk15on-1.54.jar
├── bcprov-jdk15on-1.54.jar
├── ecc-25519-java-1.0.1.jar
├── slf4j-api-1.7.21.jar
├── slf4j-nop-1.7.21.jar
└── sshj-0.16.0.jar
├── resources
├── README.md
├── build.properties
├── build.xml
├── code
│ ├── ExampleTaglet.class
│ ├── ExampleTaglet.java
│ ├── ant-contrib-1.0b3.jar
│ └── doc.sh
├── stylesheet.css
└── tool.properties
├── src
└── gohai
│ └── uploadtopi
│ └── UploadToPiTool.java
└── web
├── index.html
└── stylesheet.css
/README.md:
--------------------------------------------------------------------------------
1 | # Upload to Pi Tool
2 |
3 | ### Description
4 |
5 | This tool adds an _Upload to Pi_ menu item under _Tools_. Invoking it will compile the current sketch, upload it to a connected Raspberry Pi, and execute it there. Any output of your sketch, such as from `println`, is displayed on your local console.
6 |
7 | By default, a connection with _raspberrypi.local_ is attempted, using the default username (_pi_) and password (_raspberry_). These settings can be changed by modifying the values in Processing's `preferences.txt` file. See section _Configuration_ for more details.
8 |
9 | Sketches are uploaded to the default user's home directory (`/home/pi`). The most recently uploaded sketch is also automatically started whenever the Raspberry Pi boots up. This behavior can be changed, if needed.
10 |
11 | Since this tool needs to make some assumption about the Pi's system configuration, only the Raspbian operating system is currently supported. (We tested it against its _March 2016_ release.)
12 |
13 | ### Install with the Contribution Manager
14 |
15 | Add contributed tools by selecting the menu item _Tools_ → _Add Tool..._ This will open the Contribution Manager, where you can browse for Upload to Pi, or any other tool you want to install.
16 |
17 | Not all available tools have been converted to show up in this menu. If a tool isn't there, it will need to be installed manually by following the instructions below.
18 |
19 | ### Manual Install
20 |
21 | Contributed tools may be downloaded separately and manually placed within the `tools` folder of your Processing sketchbook. To find (and change) the Processing sketchbook location on your computer, open the Preferences window from the Processing application (PDE) and look for the "Sketchbook location" item at the top.
22 |
23 | By default the following locations are used for your sketchbook folder:
24 | * For Mac users, the sketchbook folder is located inside `~/Documents/Processing`
25 | * For Windows users, the sketchbook folder is located inside `My Documents/Processing`
26 |
27 | Download Upload to Pi from https://github.com/gohai/processing-uploadtopi
28 |
29 | Unzip and copy the contributed tool's folder into the `tools` folder in the Processing sketchbook. You will need to create this `tools` folder if it does not exist.
30 |
31 | The folder structure for tool Upload to Pi should be as follows:
32 |
33 | ```
34 | Processing
35 | tools
36 | Upload to Pi
37 | examples
38 | tool
39 | Upload to Pi.jar
40 | reference
41 | src
42 | ```
43 |
44 | Some folders like `examples` or `src` might be missing. After tool Upload to Pi has been successfully installed, restart the Processing application.
45 |
46 | ### Configuration
47 |
48 | The following settings can be modified by editing Processing's `preferences.txt` file:
49 |
50 | `gohai.uploadtopi.hostname` - the IP address or hostname of your Raspberry Pi; This defaults to `raspberrypi.local`, which is the default mDNS address of the Raspberry Pi on the local network. If you're using Windows, which currently doesn't support mDNS resolution out of the box, or you're having more than one Raspberry Pi connected to your network, you might need to change this value. See [here](https://learn.adafruit.com/bonjour-zeroconf-networking-for-windows-and-linux/overview) for more information how to enable mDNS resolution on different operating systems.
51 |
52 | `gohai.uploadtopi.username` - the username to use with the Pi, defaults to `raspberry`
53 |
54 | `gohai.uploadtopi.password` - the password to use, defaults to `pi`
55 |
56 | `gohai.uploadtopi.persistent` - whether or not to upload the sketch to persistent memory, defaults to `true`; If set to `false`, the sketch will be uploaded to `/tmp` instead of `/home/pi`.
57 |
58 | `gohai.uploadtopi.autostart` - whether or not to automatically start the sketch after bootup, defaults to `true`
59 |
60 | `gohai.uploadtopi.logging` - whether to write the output of the sketch (including any error messages) to a .log file in the sketch folder on the Raspberry Pi when automatically started after bootup, defaults to `true`
61 |
62 | ### Troubleshooting
63 |
64 | If you're having trouble, please file issues [here](https://github.com/gohai/processing-uploadtopi/issues/new).
65 |
--------------------------------------------------------------------------------
/data/README:
--------------------------------------------------------------------------------
1 | The data folder:
2 | If your tool is using files like images, sound files, any data file, etc.,
3 | put them into the data folder. When writing your tool you can use the
4 | following methods as a starting point to load or get files from the data folder,
5 | these are suggestions amongst many other solutions.
6 |
7 | When using an Object which extends PApplet inside your tool, PApplet's internal
8 | methods such as loadImage, loadStrings, etc. will use your tool's data folder to find
9 | files to be loaded.
10 |
11 |
12 |
13 |
14 |
15 | /**
16 | * load an image from the data folder or an absolute path. This
17 | * java.awt.Image can be displayed within a JFrame for example.
18 | *
19 | * @param theFilename
20 | * @return
21 | */
22 | public Image loadImage(String theFilename) {
23 | if (theFilename.startsWith(File.separator)) {
24 | return new ImageIcon(theFilename).getImage();
25 | } else {
26 | URL img = this.getClass().getResource(getPath(theFilename));
27 | return new ImageIcon(img).getImage();
28 | }
29 | }
30 |
31 |
32 | /**
33 | * load an image from the data folder or an absolute path as a PImage.
34 | *
35 | * @param theFilename
36 | * @return
37 | */
38 | public PImage loadPImage(String theFilename) {
39 | return new PImage(loadImage(theFilename));
40 | }
41 |
42 |
43 | /**
44 | * load a text file from the data folder or an absolute path.
45 | *
46 | * @param theFilename
47 | * @return
48 | */
49 | public String loadString(String theFilename) {
50 | InputStream is = null;
51 | if (theFilename.startsWith(File.separator)) {
52 | try {
53 | is = new FileInputStream(loadFile(theFilename));
54 | } catch (FileNotFoundException e) {
55 | System.err.println("ERROR @ loadString() " + e);
56 | }
57 | } else {
58 | is = getClass().getResourceAsStream(getPath(theFilename));
59 | }
60 | InputStreamReader isr = new InputStreamReader(is);
61 | BufferedReader br = new BufferedReader(isr);
62 | int buffer;
63 | String result = "";
64 | try {
65 | while ((buffer = br.read()) != -1) {
66 | result += (char) buffer;
67 | }
68 | } catch (Exception e) {
69 | System.err.println("ERROR @ loadString() " + e);
70 | }
71 | return result;
72 | }
73 |
74 |
75 | /**
76 | * getPath will return the path to a file or folder inside the data folder
77 | * of the tool or an absolute path.
78 | *
79 | * @param theFilename
80 | * @return
81 | */
82 | public String getPath(String theFilename) {
83 | if (theFilename.startsWith("/")) {
84 | return theFilename;
85 | }
86 | return File.separator + "data" + File.separator + theFilename;
87 | }
88 |
89 |
90 | /**
91 | * load a file from the data folder or an absolute path.
92 | *
93 | * @param theFilename
94 | * @return
95 | */
96 | public File loadFile(String theFilename) {
97 | if (theFilename.startsWith(File.separator)) {
98 | return new File(theFilename);
99 | }
100 | String path = getClass().getResource(getPath(theFilename)).getPath();
101 | return new File(path);
102 | }
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/examples/README:
--------------------------------------------------------------------------------
1 | add examples for your tool here.
--------------------------------------------------------------------------------
/lib/bcpkix-jdk15on-1.54.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/lib/bcpkix-jdk15on-1.54.jar
--------------------------------------------------------------------------------
/lib/bcprov-jdk15on-1.54.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/lib/bcprov-jdk15on-1.54.jar
--------------------------------------------------------------------------------
/lib/ecc-25519-java-1.0.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/lib/ecc-25519-java-1.0.1.jar
--------------------------------------------------------------------------------
/lib/slf4j-api-1.7.21.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/lib/slf4j-api-1.7.21.jar
--------------------------------------------------------------------------------
/lib/slf4j-nop-1.7.21.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/lib/slf4j-nop-1.7.21.jar
--------------------------------------------------------------------------------
/lib/sshj-0.16.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/lib/sshj-0.16.0.jar
--------------------------------------------------------------------------------
/resources/README.md:
--------------------------------------------------------------------------------
1 | # ##tool.name## Tool
2 |
3 | ### Description
4 |
5 | This tool adds an _Upload to Pi_ menu item under _Tools_. Invoking it will compile the current sketch, upload it to a connected Raspberry Pi, and execute it there. Any output of your sketch, such as from `println`, is displayed on your local console.
6 |
7 | By default, a connection with _raspberrypi.local_ is attempted, using the default username (_raspberry_) and password (_pi_). These settings can be changed by modifying the values in Processing's `preferences.txt` file. See section _Configuration_ for more details.
8 |
9 | Sketches are uploaded to the default user's home directory (`/home/pi`). The most recently uploaded sketch is also automatically started whenever the Raspberry Pi boots up. This behavior can be changed, if needed.
10 |
11 | Since this tool needs to make some assumption about the Pi's system configuration, only the Raspbian operating system is currently supported. (We tested it against its _March 2016_ release.)
12 |
13 | ### Install with the Contribution Manager
14 |
15 | Add contributed tools by selecting the menu item _Tools_ → _Add Tool..._ This will open the Contribution Manager, where you can browse for ##tool.name##, or any other tool you want to install.
16 |
17 | Not all available tools have been converted to show up in this menu. If a tool isn't there, it will need to be installed manually by following the instructions below.
18 |
19 | ### Manual Install
20 |
21 | Contributed tools may be downloaded separately and manually placed within the `tools` folder of your Processing sketchbook. To find (and change) the Processing sketchbook location on your computer, open the Preferences window from the Processing application (PDE) and look for the "Sketchbook location" item at the top.
22 |
23 | By default the following locations are used for your sketchbook folder:
24 | * For Mac users, the sketchbook folder is located inside `~/Documents/Processing`
25 | * For Windows users, the sketchbook folder is located inside `My Documents/Processing`
26 |
27 | Download ##tool.name## from ##tool.url##
28 |
29 | Unzip and copy the contributed tool's folder into the `tools` folder in the Processing sketchbook. You will need to create this `tools` folder if it does not exist.
30 |
31 | The folder structure for tool ##tool.name## should be as follows:
32 |
33 | ```
34 | Processing
35 | tools
36 | ##tool.name##
37 | examples
38 | tool
39 | ##tool.name##.jar
40 | reference
41 | src
42 | ```
43 |
44 | Some folders like `examples` or `src` might be missing. After tool ##tool.name## has been successfully installed, restart the Processing application.
45 |
46 | ### Configuration
47 |
48 | The following settings can be modified by editing Processing's `preferences.txt` file:
49 |
50 | `gohai.uploadtopi.hostname` - the IP address or hostname of your Raspberry Pi; This defaults to `raspberrypi.local`, which is the default mDNS address of the Raspberry Pi on the local network. If you're using Windows, which currently doesn't support mDNS resolution out of the box, or you're having more than one Raspberry Pi connected to your network, you might need to change this value. See [here](https://learn.adafruit.com/bonjour-zeroconf-networking-for-windows-and-linux/overview) for more information how to enable mDNS resolution on different operating systems.
51 |
52 | `gohai.uploadtopi.username` - the username to use with the Pi, defaults to `raspberry`
53 |
54 | `gohai.uploadtopi.password` - the password to use, defaults to `pi`
55 |
56 | `gohai.uploadtopi.persistent` - whether or not to upload the sketch to persistent memory, defaults to `true`; If set to `false`, the sketch will be uploaded to `/tmp` instead of `/home/pi`.
57 |
58 | `gohai.uploadtopi.autostart` - whether or not to automatically start the sketch after bootup, defaults to `true`
59 |
60 | ### Troubleshooting
61 |
62 | If you're having trouble, please file issues [here](https://github.com/gohai/processing-uploadtopi/issues/new).
63 |
--------------------------------------------------------------------------------
/resources/build.properties:
--------------------------------------------------------------------------------
1 | # Create a Tool for the Processing open source programming language and
2 | # environment (http://www.processing.org)
3 | #
4 | # Customize the build properties to make the ant-build-process work for your
5 | # environment. How? Please read the comments below.
6 | #
7 | # The default properties are set for OS X. Please refer to comments for Windows
8 | # settings.
9 |
10 |
11 | # Where is your Processing sketchbook located?
12 | # If you are not sure, check the sketchbook location in your Processing
13 | # application preferences.
14 | # ${user.home} points the compiler to your home directory.
15 | # For windows the default path to your sketchbook would be
16 | # ${user.home}/My Documents/Processing (make adjustments below).
17 |
18 | #sketchbook.location=${user.home}/My Documents/Processing
19 | sketchbook.location=${user.home}/Documents/Processing
20 |
21 |
22 | # Where are the jar files located that are required for compiling your Tool such
23 | # as e.g. core.jar?
24 | # By default the local classpath location points to folder libs inside Eclipse's
25 | # workspace (by default found in your home directory).
26 | # For Windows, the default path would be
27 | # ${user.home}/Documents/workspace/libs (make adjustments below)
28 | # For OS X,the following path will direct you into Processing's application
29 | # package, in case you put Processing inside your Applications folder.
30 |
31 | #classpath.local.location=${user.home}/Documents/workspace/libs
32 | classpath.local.location=/Applications/Processing.app/Contents/Java
33 |
34 |
35 | # Add all jar files that are required for compiling your project to the local
36 | # and project classpath. Use a comma as delimiter. These jar files must be
37 | # inside your classpath.local.location folder.
38 | # For creating a Tool, both pde.jar and core.jar are required.
39 |
40 | classpath.local.include=core.jar,pde.jar
41 |
42 |
43 | # Add Processing's libraries folder to the classpath.
44 | # If you don't need to include the libraries folder to your classpath, comment
45 | # out the following line.
46 |
47 | classpath.libraries.location=${sketchbook.location}/libraries
48 |
49 |
50 | # Set the java version that should be used to compile your Tool.
51 |
52 | java.target.version=1.7
53 |
54 |
55 | # Set the description of the Ant build.xml file.
56 |
57 | ant.description=Processing Tool Ant build file.
58 |
59 |
60 | # Give your Tool a name. The name must not contain spaces or special characters.
61 | # When creating a tool, the name of the main class which implements Tool must be
62 | # the same as the value defined for project.name in your build.properties.
63 |
64 | project.name=UploadToPiTool
65 |
66 |
67 | # The name as the user will see it. This can contain spaces and special
68 | # characters.
69 |
70 | project.prettyName=Upload to Pi
71 |
72 |
73 | # Use 'normal' or 'fast' as value for project.compile.
74 | # 'fast' will only compile the project into your sketchbook.
75 | # 'normal' will compile the distribution including the javadoc-reference and all
76 | # web-files (the compile process here takes longer).
77 | # All files compiled with project.compile=normal are stored
78 | # in the distribution folder.
79 |
80 | project.compile=normal
81 |
82 |
83 | # Set your name and URL, used for the web page and properties file.
84 |
85 | author.name=Gottfried Haider
86 | author.url=http://gottfriedhaider.com/
87 |
88 |
89 | # Set the web page for your Tool.
90 | # This is NOT a direct link to where to download it.
91 |
92 | tool.url=https://github.com/gohai/processing-uploadtopi
93 |
94 |
95 | # Set the category (or categories) of your Tool from the following list:
96 | # "3D" "Animation" "Compilations" "Data"
97 | # "Fabrication" "Geometry" "GUI" "Hardware"
98 | # "I/O" "Language" "Math" "Simulation"
99 | # "Sound" "Utilities" "Typography" "Video & Vision"
100 | #
101 | # If a value other than those listed is used, your library will listed as
102 | # "Other". Many categories must be comma-separated.
103 |
104 | tool.categories=Other
105 |
106 |
107 | # A short sentence (or fragment) to summarize the Tool's function. This will be
108 | # shown from inside the PDE when the Tool is being installed. Avoid repeating
109 | # the name of your Tool here. Also, avoid saying anything redundant like
110 | # mentioning that it's a Tool. This should start with a capitalized letter, and
111 | # end with a period.
112 |
113 | tool.sentence=Uploads and runs a sketch on a Raspberry Pi.
114 |
115 |
116 | # Additional information suitable for the Processing website. The value of
117 | # 'sentence' always will be prepended, so you should start by writing the
118 | # second sentence here. If your Tool only works on certain operating systems,
119 | # mention it here.
120 |
121 | tool.paragraph=This currently attempts to connect to a Raspberry Pi in the local network (hostname raspberrypi.local) with the default credentials. In development.
122 |
123 |
124 | # Set the source code repository for your project.
125 | # We recommend Bitbucket (https://bitbucket.org) or GitHub (https://github.com).
126 |
127 | source.host=GitHub
128 | source.url=https://github.com/gohai/processing-uploadtopi
129 | source.repository=https://github.com/gohai/processing-uploadtopi.git
130 |
131 |
132 | # The current version of your Tool.
133 | # This number must be parsable as an int. It increments once with each release.
134 | # This is used to compare different versions of the same Tool, and check if an
135 | # update is available.
136 |
137 | tool.version=7
138 |
139 |
140 | # The version as the user will see it.
141 |
142 | tool.prettyVersion=1.0.6
143 |
144 |
145 | # The min and max revision of Processing compatible with your Tool.
146 | # Note that these fields use the revision and not the version of Processing,
147 | # parsable as an int. For example, the revision number for 2.2.1 is 227.
148 | # You can find the revision numbers in the change log: https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt
149 | # Only use maxRevision (or minRevision), when your Tool is known to break in a
150 | # later (or earlier) release. Otherwise, use the default value 0.
151 |
152 | compatible.minRevision=247
153 | compatible.maxRevision=0
154 |
155 |
156 | # The platforms and Processing version that the Tool has been tested
157 | # against. This information is only used in the generated webpage.
158 |
159 | tested.platform=osx
160 | tested.processingVersion=3.0.2
161 |
162 |
163 | # Additional information for the generated webpage.
164 |
165 | tool.copyright=(c) 2015
166 | tool.dependencies=?
167 | tool.keywords=?
168 |
169 |
170 | # Include javadoc references into your project's javadocs.
171 |
172 | javadoc.java.href=http://docs.oracle.com/javase/7/docs/api/
173 | javadoc.processing.href=http://processing.org/reference/javadoc/everything/
174 |
--------------------------------------------------------------------------------
/resources/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ${ant.description}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | ${line}
81 | Building the Processing Tool, ${project.name} ${tool.version}
82 | ${line}
83 | src path ${project.src}
84 | bin path ${project.bin}
85 | classpath.local ${classpath.local.location}
86 | sketchbook ${sketchbook.location}
87 | java version ${java.target.version}
88 | ${line}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 | ${exampleDir}
344 |
350 |
351 |
357 |
358 |
359 |
360 |
361 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 | ${line}
380 | Name ${project.name}
381 | Version ${tool.prettyVersion} (${tool.version})
382 | Compiled ${project.compile}
383 | Sketchbook ${sketchbook.location}
384 | ${line}
385 | done, finished.
386 | ${line}
387 |
388 |
389 |
390 |
391 |
392 |
--------------------------------------------------------------------------------
/resources/code/ExampleTaglet.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/resources/code/ExampleTaglet.class
--------------------------------------------------------------------------------
/resources/code/ExampleTaglet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or
5 | * without modification, are permitted provided that the following
6 | * conditions are met:
7 | *
8 | * -Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | *
11 | * -Redistribution in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in
13 | * the documentation and/or other materials provided with the
14 | * distribution.
15 | *
16 | * Neither the name of Sun Microsystems, Inc. or the names of
17 | * contributors may be used to endorse or promote products derived
18 | * from this software without specific prior written permission.
19 | *
20 | * This software is provided "AS IS," without a warranty of any
21 | * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
22 | * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
24 | * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
25 | * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
26 | * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
27 | * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
28 | * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
29 | * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
30 | * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
31 | * THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
32 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
33 | *
34 | * You acknowledge that Software is not designed, licensed or
35 | * intended for use in the design, construction, operation or
36 | * maintenance of any nuclear facility.
37 | */
38 |
39 | import com.sun.tools.doclets.Taglet;
40 | import com.sun.javadoc.*;
41 | import java.util.Map;
42 | import java.io.*;
43 | /**
44 | * A sample Taglet representing @example. This tag can be used in any kind of
45 | * {@link com.sun.javadoc.Doc}. It is not an inline tag. The text is displayed
46 | * in yellow to remind the developer to perform a task. For
47 | * example, "@example Hello" would be shown as:
48 | *
49 | *
50 | * To Do:
51 | *
Fix this!
52 | *
53 | *
54 | *
55 | * @author Jamie Ho
56 | * @since 1.4
57 | */
58 |
59 | public class ExampleTaglet implements Taglet {
60 |
61 | private static final String NAME = "example";
62 | private static final String HEADER = "example To Do:";
63 |
64 | /**
65 | * Return the name of this custom tag.
66 | */
67 | public String getName() {
68 | return NAME;
69 | }
70 |
71 | /**
72 | * Will return true since @example
73 | * can be used in field documentation.
74 | * @return true since @example
75 | * can be used in field documentation and false
76 | * otherwise.
77 | */
78 | public boolean inField() {
79 | return true;
80 | }
81 |
82 | /**
83 | * Will return true since @example
84 | * can be used in constructor documentation.
85 | * @return true since @example
86 | * can be used in constructor documentation and false
87 | * otherwise.
88 | */
89 | public boolean inConstructor() {
90 | return true;
91 | }
92 |
93 | /**
94 | * Will return true since @example
95 | * can be used in method documentation.
96 | * @return true since @example
97 | * can be used in method documentation and false
98 | * otherwise.
99 | */
100 | public boolean inMethod() {
101 | return true;
102 | }
103 |
104 | /**
105 | * Will return true since @example
106 | * can be used in method documentation.
107 | * @return true since @example
108 | * can be used in overview documentation and false
109 | * otherwise.
110 | */
111 | public boolean inOverview() {
112 | return true;
113 | }
114 |
115 | /**
116 | * Will return true since @example
117 | * can be used in package documentation.
118 | * @return true since @example
119 | * can be used in package documentation and false
120 | * otherwise.
121 | */
122 | public boolean inPackage() {
123 | return true;
124 | }
125 |
126 | /**
127 | * Will return true since @example
128 | * can be used in type documentation (classes or interfaces).
129 | * @return true since @example
130 | * can be used in type documentation and false
131 | * otherwise.
132 | */
133 | public boolean inType() {
134 | return true;
135 | }
136 |
137 | /**
138 | * Will return false since @example
139 | * is not an inline tag.
140 | * @return false since @example
141 | * is not an inline tag.
142 | */
143 |
144 | public boolean isInlineTag() {
145 | return false;
146 | }
147 |
148 | /**
149 | * Register this Taglet.
150 | * @param tagletMap the map to register this tag to.
151 | */
152 | public static void register(Map tagletMap) {
153 | ExampleTaglet tag = new ExampleTaglet();
154 | Taglet t = (Taglet) tagletMap.get(tag.getName());
155 | if (t != null) {
156 | tagletMap.remove(tag.getName());
157 | }
158 | tagletMap.put(tag.getName(), tag);
159 | }
160 |
161 | /**
162 | * Given the Tag representation of this custom
163 | * tag, return its string representation.
164 | * @param tag the Tag representation of this custom tag.
165 | */
166 | public String toString(Tag tag) {
167 | return createHTML(readFile(tag.text()));
168 | }
169 |
170 |
171 | /**
172 | * Given an array of Tags representing this custom
173 | * tag, return its string representation.
174 | * @param tags the array of Tags representing of this custom tag.
175 | */
176 | public String toString(Tag[] tags) {
177 | if (tags.length == 0) {
178 | return null;
179 | }
180 | return createHTML(readFile(tags[0].text()));
181 | }
182 |
183 |
184 |
185 | String createHTML(String theString) {
186 | if(theString!=null) {
187 | String dd = "";
193 |
194 | return dd+"\n
" +
195 | "
+Example
" +
196 | "
"+theString+"
" +
197 | "
";
198 | }
199 | return "";
200 | }
201 |
202 |
203 | /**
204 | * check if the examples directory exists and return the example as given in the tag.
205 | * @param theExample the name of the example
206 | */
207 | String readFile(String theExample) {
208 | String record = "";
209 | String myResult = "";
210 | int recCount = 0;
211 | String myDir = "../examples";
212 | File file=new File(myDir);
213 | if(file.exists()==false) {
214 | myDir = "./examples";
215 | }
216 | try {
217 | FileReader fr = new FileReader(myDir+"/"+theExample+"/"+theExample+".pde");
218 | BufferedReader br = new BufferedReader(fr);
219 | record = new String();
220 | while ((record = br.readLine()) != null) {
221 | myResult += record+"\n";
222 | }
223 | } catch (IOException e) {
224 | System.out.println(e);
225 | return null;
226 | }
227 | return myResult;
228 | }
229 | }
230 |
231 |
232 |
--------------------------------------------------------------------------------
/resources/code/ant-contrib-1.0b3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gohai/processing-uploadtopi/b8bcec43c2a1fe1d894ff740c4a73779a6baeee0/resources/code/ant-contrib-1.0b3.jar
--------------------------------------------------------------------------------
/resources/code/doc.sh:
--------------------------------------------------------------------------------
1 | # a shell script to create a java documentation
2 | # for a processing library.
3 | #
4 | # make changes to the variables below so they
5 | # fit the structure of your library
6 |
7 | # the package name of your library
8 | package=template;
9 |
10 | # source folder location
11 | src=../src;
12 |
13 | # the destination folder of your documentation
14 | dest=../documentation;
15 |
16 |
17 | # compile the java documentation
18 | javadoc -d $dest -stylesheetfile ./stylesheet.css -sourcepath ${src} ${package}
19 |
--------------------------------------------------------------------------------
/resources/stylesheet.css:
--------------------------------------------------------------------------------
1 | /* Javadoc style sheet */
2 | /* Define colors, fonts and other style attributes here to override the defaults */
3 | /* processingLibs style by andreas schlegel, sojamo */
4 |
5 |
6 | body {
7 | margin : 0;
8 | padding : 0;
9 | padding-left : 10px;
10 | padding-right : 8px;
11 | background-color : #FFFFFF;
12 | font-family : Verdana, Geneva, Arial, Helvetica, sans-serif;
13 | font-size : 100%;
14 | font-size : 0.7em;
15 | font-weight : normal;
16 | line-height : normal;
17 | margin-bottom:30px;
18 | }
19 |
20 |
21 |
22 |
23 | /* Headings */
24 | h1, h2, h3, h4, h5, th {
25 | font-family :Arial, Helvetica, sans-serif;
26 | font-size:1.2em;
27 | }
28 |
29 |
30 | p {
31 | font-size : 1em;
32 | width:80%;
33 | }
34 |
35 | pre, code {
36 | font-family : "Courier New", Courier, monospace;
37 | font-size : 12px;
38 | line-height : normal;
39 | }
40 |
41 |
42 |
43 | table {
44 | border:0;
45 | margin-bottom:10px;
46 | margin-top:10px;
47 | }
48 |
49 |
50 | tr, td {
51 | border-top: 0px solid;
52 | border-left: 0px solid;
53 | padding-top:8px;
54 | padding-bottom:8px;
55 | }
56 |
57 |
58 |
59 | hr {
60 | border:0;
61 | height:1px;
62 | padding:0;
63 | margin:0;
64 | margin-bottom:4px;
65 |
66 | }
67 |
68 |
69 |
70 | dd, th, td, font {
71 | font-size:1.0em;
72 | line-height:1.0em;
73 | }
74 |
75 |
76 |
77 | dt {
78 | margin-bottom:0px;
79 | }
80 |
81 |
82 |
83 | dd {
84 | margin-top:2px;
85 | margin-bottom:4px;
86 | }
87 |
88 |
89 |
90 | a {
91 | text-decoration: underline;
92 | font-weight: normal;
93 | }
94 |
95 | a:hover,
96 | a:active {
97 | text-decoration: underline;
98 | font-weight: normal;
99 | }
100 |
101 | a:visited,
102 | a:link:visited {
103 | text-decoration: underline;
104 | font-weight: normal;
105 | }
106 |
107 |
108 | img {
109 | border: 0px solid #000000;
110 | }
111 |
112 |
113 |
114 | /* Navigation bar fonts */
115 | .NavBarCell1 {
116 | border:0;
117 | }
118 |
119 | .NavBarCell1Rev {
120 | border:0;
121 | }
122 |
123 | .NavBarFont1 {
124 | font-family: Arial, Helvetica, sans-serif;
125 | font-size:1.1em;
126 | }
127 |
128 |
129 | .NavBarFont1 b {
130 | font-weight:normal;
131 | }
132 |
133 |
134 |
135 | .NavBarFont1:after, .NavBarFont1Rev:after {
136 | font-weight:normal;
137 | content: " \\";
138 | }
139 |
140 |
141 | .NavBarFont1Rev {
142 | font-family: Arial, Helvetica, sans-serif;
143 | font-size:1.1em;
144 | }
145 |
146 | .NavBarFont1Rev b {
147 | font-family: Arial, Helvetica, sans-serif;
148 | font-size:1.1em;
149 | font-weight:normal;
150 | }
151 |
152 | .NavBarCell2 {
153 | font-family: Arial, Helvetica, sans-serif;
154 | }
155 |
156 | .NavBarCell3 {
157 | font-family: Arial, Helvetica, sans-serif;
158 | }
159 |
160 |
161 |
162 | font.FrameItemFont {
163 | font-family: Helvetica, Arial, sans-serif;
164 | font-size:1.1em;
165 | line-height:1.1em;
166 | }
167 |
168 | font.FrameHeadingFont {
169 | font-family: Helvetica, Arial, sans-serif;
170 | line-height:32px;
171 | }
172 |
173 | /* Font used in left-hand frame lists */
174 | .FrameTitleFont {
175 | font-family: Helvetica, Arial, sans-serif
176 | }
177 |
178 |
179 | .toggleList {
180 | padding:0;
181 | margin:0;
182 | margin-top:12px;
183 | }
184 |
185 | .toggleList dt {
186 | font-weight:bold;
187 | font-size:12px;
188 | font-family:arial,sans-serif;
189 | padding:0px;
190 | margin:10px 0px 10px 0px;
191 | }
192 |
193 | .toggleList dt span {
194 | font-family: monospace;
195 | padding:0;
196 | margin:0;
197 | }
198 |
199 |
200 | .toggleList dd {
201 | margin:0;
202 | padding:0;
203 | }
204 |
205 | html.isjs .toggleList dd {
206 | display: none;
207 | }
208 |
209 | .toggleList pre {
210 | padding: 4px 4px 4px 4px;
211 | }
212 |
213 |
214 |
215 |
216 |
217 | /* COLORS */
218 |
219 | pre, code {
220 | color: #000000;
221 | }
222 |
223 |
224 | body {
225 | color : #333333;
226 | background-color :#FFFFFF;
227 | }
228 |
229 |
230 | h1, h2, h3, h4, h5, h6 {
231 | color:#555;
232 | }
233 |
234 | a,
235 | .toggleList dt {
236 | color: #1a7eb0;
237 | }
238 |
239 | a:hover,
240 | a:active {
241 | color: #1a7eb0;
242 | }
243 |
244 | a:visited,
245 | a:link:visited {
246 | color: #1a7eb0;
247 | }
248 |
249 | td,tr {
250 | border-color: #999999;
251 | }
252 |
253 | hr {
254 | color:#999999;
255 | background:#999999;
256 | }
257 |
258 |
259 | .TableHeadingColor {
260 | background: #dcdcdc;
261 | color: #555;
262 | }
263 |
264 |
265 | .TableSubHeadingColor {
266 | background: #EEEEFF
267 | }
268 |
269 | .TableRowColor {
270 | background: #FFFFFF
271 | }
272 |
273 |
274 | .NavBarCell1 {
275 | background-color:#dcdcdc;
276 | color:#000;
277 | }
278 |
279 | .NavBarCell1 a {
280 | color:#333;
281 | }
282 |
283 |
284 | .NavBarCell1Rev {
285 | background-color:transparent;
286 | }
287 |
288 | .NavBarFont1 {
289 | color:#333;
290 | }
291 |
292 |
293 | .NavBarFont1Rev {
294 | color:#fff;
295 | }
296 |
297 | .NavBarCell2 {
298 | background-color:#999;
299 | }
300 |
301 | .NavBarCell2 a {
302 | color:#fff;
303 | }
304 |
305 |
306 |
307 | .NavBarCell3 {
308 | background-color:#dcdcdc;
309 | }
310 |
311 |
--------------------------------------------------------------------------------
/resources/tool.properties:
--------------------------------------------------------------------------------
1 | # More on this file here: https://github.com/processing/processing/wiki/Tool-Basics
2 | # UTF-8 supported.
3 |
4 | # The name of your tool as you want it formatted.
5 | name = ##tool.name##
6 |
7 | # List of authors. Links can be provided using the syntax [author name](url).
8 | authors = [##author.name##](##author.url##)
9 |
10 | # A web page for your tool, NOT a direct link to where to download it.
11 | url = ##tool.url##
12 |
13 | # The category (or categories) of your tool, must be from the following list:
14 | # "3D" "Animation" "Compilations" "Data"
15 | # "Fabrication" "Geometry" "GUI" "Hardware"
16 | # "I/O" "Language" "Math" "Simulation"
17 | # "Sound" "Utilities" "Typography" "Video & Vision"
18 | #
19 | # If a value other than those listed is used, your library will listed as
20 | # "Other". Many categories must be comma-separated.
21 | categories = ##tool.categories##
22 |
23 | # A short sentence (or fragment) to summarize the tool's function. This will be
24 | # shown from inside the PDE when the tool is being installed. Avoid repeating
25 | # the name of your tool here. Also, avoid saying anything redundant like
26 | # mentioning that it's a tool. This should start with a capitalized letter, and
27 | # end with a period.
28 | sentence = ##tool.sentence##
29 |
30 | # Additional information suitable for the Processing website. The value of
31 | # 'sentence' always will be prepended, so you should start by writing the
32 | # second sentence here. If your tool only works on certain operating systems,
33 | # mention it here.
34 | paragraph = ##tool.paragraph##
35 |
36 | # Links in the 'sentence' and 'paragraph' attributes can be inserted using the
37 | # same syntax as for authors.
38 | # That is, [here is a link to Processing](http://processing.org/)
39 |
40 | # A version number that increments once with each release. This is used to
41 | # compare different versions of the same tool, and check if an update is
42 | # available. You should think of it as a counter, counting the total number of
43 | # releases you've had.
44 | version = ##tool.version## # This must be parsable as an int
45 |
46 | # The version as the user will see it. If blank, the version attribute will be
47 | # used here. This should be a single word, with no spaces.
48 | prettyVersion = ##tool.prettyVersion## # This is treated as a String
49 |
50 | # The min and max revision of Processing compatible with your tool.
51 | # Note that these fields use the revision and not the version of Processing,
52 | # parsable as an int. For example, the revision number for 2.2.1 is 227.
53 | # You can find the revision numbers in the change log: https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt
54 | # Only use maxRevision (or minRevision), when your tool is known to break in a
55 | # later (or earlier) release. Otherwise, use the default value 0.
56 | minRevision = ##compatible.minRevision##
57 | maxRevision = ##compatible.maxRevision##
58 |
--------------------------------------------------------------------------------
/src/gohai/uploadtopi/UploadToPiTool.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Tool to upload and run sketches on Raspberry Pi devices.
3 | *
4 | * Copyright (c) The Processing Foundation 2016
5 | * Developed by Gottfried Haider
6 | *
7 | * This library is free software; you can redistribute it and/or
8 | * modify it under the terms of the GNU Lesser General Public
9 | * License as published by the Free Software Foundation; either
10 | * version 2.1 of the License, or (at your option) any later version.
11 | *
12 | * This library is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General
18 | * Public License along with this library; if not, write to the
19 | * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 | * Boston, MA 02111-1307 USA
21 | *
22 | * @author Gottfried Haider
23 | */
24 |
25 | package gohai.uploadtopi;
26 |
27 | import processing.app.Base;
28 | import processing.app.Mode;
29 | import processing.app.Preferences;
30 | import processing.app.Sketch;
31 | import processing.app.tools.Tool;
32 | import processing.app.ui.Editor;
33 | import processing.app.ui.EditorConsole;
34 | import java.io.File;
35 | import java.io.InputStream;
36 | import java.io.IOException;
37 | import java.lang.reflect.*;
38 | import java.net.ConnectException;
39 | import java.net.SocketTimeoutException;
40 | import java.net.UnknownHostException;
41 | import java.util.concurrent.TimeUnit;
42 | import net.schmizz.sshj.common.DisconnectReason;
43 | import net.schmizz.sshj.common.IOUtils;
44 | import net.schmizz.sshj.common.StreamCopier;
45 | import net.schmizz.sshj.connection.channel.direct.Session;
46 | import net.schmizz.sshj.connection.channel.direct.Session.Command;
47 | import net.schmizz.sshj.connection.ConnectionException;
48 | import net.schmizz.sshj.DefaultConfig;
49 | import net.schmizz.keepalive.KeepAliveProvider;
50 | import net.schmizz.sshj.sftp.SFTPClient;
51 | import net.schmizz.sshj.SSHClient;
52 | import net.schmizz.sshj.transport.TransportException;
53 | import net.schmizz.sshj.userauth.UserAuthException;
54 |
55 |
56 | // XXX: there doesn't seem to be a way to handle the use pressing the stop button
57 | // XXX: implement method to retrieve Pi's serial number
58 | // XXX: implement method to retrieve Pi's network IPs & MAC addresses
59 |
60 |
61 | public class UploadToPiTool implements Tool {
62 | Base base;
63 | SSHClient ssh;
64 | Thread t;
65 |
66 | String hostname;
67 | String username;
68 | String password;
69 | boolean persistent;
70 | boolean autostart;
71 | boolean logging;
72 |
73 |
74 | public String getMenuTitle() {
75 | return "Upload to Pi";
76 | }
77 |
78 |
79 | public void init(Base base) {
80 | this.base = base;
81 | loadPreferences();
82 | // saving the preferences adds them to the txt file for the user to edit
83 | savePreferences();
84 | }
85 |
86 |
87 | public void run() {
88 | final Editor editor = base.getActiveEditor();
89 | final String sketchName = editor.getSketch().getName();
90 | final String sketchPath = editor.getSketch().getFolder().getAbsolutePath();
91 |
92 | // this assumes the working directory is home at the beginning of a ssh/sftp session
93 | // "~" didn't work (no such file)
94 | final String dest = (persistent) ? "." : "/tmp";
95 |
96 | // already running?
97 | if (t != null) {
98 | // terminate thread
99 | t.interrupt();
100 | try {
101 | // wait for it to finish
102 | t.join();
103 | } catch (InterruptedException e) {
104 | System.err.println("Error joining thread: " + e.getMessage());
105 | }
106 | t = null;
107 | // the thread should already have called this, but in case it didn't
108 | disconnect();
109 | }
110 |
111 | editor.getConsole().clear();
112 |
113 | // this doesn't trigger the "Save as" dialog for unnamed sketches, but instead saves
114 | // them in the temporary location that is also used for compiling
115 | try {
116 | editor.getSketch().save();
117 | } catch (Exception e) {
118 | editor.statusError("Cannot save sketch");
119 | // DEBUG
120 | e.printStackTrace();
121 | System.err.println(e);
122 | return;
123 | }
124 |
125 | try {
126 | exportSketch();
127 | } catch (Exception e) {
128 | editor.statusError("Cannot export sketch");
129 | if (e instanceof InvocationTargetException) {
130 | System.err.println("Most likely caused by a syntax error. Press the Run button to get more information on where the problem lies.");
131 | } else {
132 | // DEBUG
133 | e.printStackTrace();
134 | System.err.println(e);
135 | }
136 | return;
137 | }
138 |
139 | t = new Thread(new Runnable() {
140 | public void run() {
141 |
142 | try {
143 | editor.statusNotice("Connecting to " + hostname + " ...");
144 | ssh = connect(hostname, username, password);
145 | } catch (Exception e) {
146 | editor.statusError("Cannot connect to " + hostname);
147 | if (e instanceof UnknownHostException) {
148 | System.err.println("Unknown host");
149 | } else if (e instanceof UserAuthException) {
150 | System.err.println("Wrong username or password");
151 | } else if (e instanceof ConnectException && e.getMessage().equals("Connection refused")) {
152 | System.err.println("No SSH server running?");
153 | } else if (e instanceof SocketTimeoutException) {
154 | System.err.println("A timeout occurred");
155 | } else if (e instanceof ConnectionException && e.getMessage().equals("Operation timed out")) {
156 | System.err.println("A timeout occurred");
157 | } else {
158 | // DEBUG
159 | e.printStackTrace();
160 | System.err.println(e);
161 | }
162 | return;
163 | }
164 |
165 | try {
166 | editor.statusNotice("Uploading " + sketchName + " ...");
167 | stopSketches();
168 | removeSketch(dest, sketchName);
169 | uploadSketch(sketchPath + File.separator + "application.linux-armv6hf", dest, sketchName);
170 | removeAutostarts();
171 | if (autostart) {
172 | addAutostart(dest, sketchName);
173 | }
174 | } catch (Exception e) {
175 | editor.statusError("Cannot upload " + sketchName);
176 | // DEBUG
177 | e.printStackTrace();
178 | System.err.println(e);
179 | disconnect();
180 | return;
181 | }
182 |
183 | try {
184 | editor.statusNotice("Syncing disks ...");
185 | syncDisks();
186 | } catch (Exception e) {
187 | editor.statusError("Cannot sync disks");
188 | // DEBUG
189 | e.printStackTrace();
190 | System.err.println(e);
191 | disconnect();
192 | return;
193 | }
194 |
195 | editor.statusNotice("Running " + sketchName + " on the Raspberry Pi");
196 | try {
197 | int retVal = runRemoteSketch(dest, sketchName);
198 | if (retVal == 0) {
199 | // clean exit
200 | editor.statusNotice("Sketch " + sketchName + " ended");
201 | } else {
202 | // error?
203 | editor.statusError("Sketch " + sketchName + " ended with exit code " + retVal);
204 | }
205 | } catch (Exception e) {
206 | editor.statusError("Error running " + sketchName);
207 | // DEBUG
208 | e.printStackTrace();
209 | System.err.println(e);
210 | }
211 |
212 | disconnect();
213 |
214 | }
215 | }, "Upload to Pi");
216 |
217 | t.start();
218 | }
219 |
220 |
221 | public void addAutostart(String dest, String sketchName) throws IOException {
222 | Session session = ssh.startSession();
223 | String cmdString = dest + "/" + sketchName + "/" + sketchName + " --uploadtopi-managed";
224 |
225 | Command cmd;
226 | if (logging) {
227 | // LXDE autostart doesn't support spaces in its arguments, so we have to add an aux shell script
228 | cmd = session.exec("echo '" + cmdString + " >>" + dest + "/" + sketchName + "/" + sketchName + ".log 2>&1' > .config/lxsession/LXDE-pi/processing.sh && chmod a+x .config/lxsession/LXDE-pi/processing.sh");
229 | cmd.join(3, TimeUnit.SECONDS);
230 | session.close();
231 | session = ssh.startSession();
232 | cmd = session.exec("echo '.config/lxsession/LXDE-pi/processing.sh --uploadtopi-managed' >> .config/lxsession/LXDE-pi/autostart");
233 | cmd.join(3, TimeUnit.SECONDS);
234 | } else {
235 | cmd = session.exec("echo '" + cmdString + " >> .config/lxsession/LXDE-pi/autostart");
236 | }
237 |
238 | if (cmd.getExitStatus() != 0) {
239 | // not critical
240 | System.err.println("Error modifying .config/lxsession/LXDE-pi/autostart");
241 | }
242 | session.close();
243 | }
244 |
245 |
246 | public static SSHClient connect(String host, String username, String password) throws IOException, TransportException, UserAuthException {
247 | DefaultConfig defaultConfig = new DefaultConfig();
248 | defaultConfig.setKeepAliveProvider(KeepAliveProvider.KEEP_ALIVE);
249 | SSHClient ssh = new SSHClient(defaultConfig);
250 | // seems to throw an IOException on Windows
251 | try {
252 | ssh.loadKnownHosts();
253 | } catch (Exception e) {}
254 |
255 | // set a timeout to try to work around this bizzare timeout error on some OS X machines:
256 | // java.net.ConnectException: Operation timed out
257 | // at java.net.PlainSocketImpl.socketConnect(Native Method)
258 | // at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
259 | ssh.setConnectTimeout(5000);
260 |
261 | // we could enable compression here with
262 | //ssh.useCompression();
263 | // but the Pi is likely in the local network anyway (would need JZlib)
264 |
265 | try {
266 | ssh.connect(host);
267 | } catch (TransportException e) {
268 | if (e.getDisconnectReason() == DisconnectReason.HOST_KEY_NOT_VERIFIABLE) {
269 | String msg = e.getMessage();
270 | String[] split = msg.split("`");
271 | String fingerprint = split[3];
272 | // try again
273 | ssh = new SSHClient();
274 | // this doesn't update the known_hosts file
275 | ssh.addHostKeyVerifier(fingerprint);
276 | ssh.setConnectTimeout(5000);
277 | //ssh.useCompression();
278 | ssh.connect(host);
279 | } else {
280 | throw e;
281 | }
282 | }
283 |
284 | // send keep-alife nop every minute
285 | ssh.getConnection().getKeepAlive().setKeepAliveInterval(60);
286 | ssh.authPassword(username, password);
287 | return ssh;
288 | }
289 |
290 |
291 | public void disconnect() {
292 | if (ssh != null) {
293 | try {
294 | ssh.disconnect();
295 | } catch (Exception e) {
296 | }
297 | ssh = null;
298 | }
299 | }
300 |
301 |
302 | public void exportSketch() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
303 | Editor editor = base.getActiveEditor();
304 | Mode mode = editor.getMode();
305 | Sketch sketch = editor.getSketch();
306 |
307 | String oldSetting = Preferences.get("export.application.platform_linux");
308 | Preferences.set("export.application.platform_linux", "true");
309 |
310 | try {
311 | Method javaModeMethod = mode.getClass().getMethod("handleExportApplication", sketch.getClass());
312 | javaModeMethod.invoke(mode, sketch);
313 | } catch (Exception e) {
314 | System.err.println("The UploadToPi tool can only handle sketches using the Java mode at this time.");
315 | throw new RuntimeException("Unsupported mode");
316 | } finally {
317 | Preferences.set("export.application.platform_linux", oldSetting);
318 | }
319 | }
320 |
321 |
322 | private void loadPreferences() {
323 | hostname = Preferences.get("gohai.uploadtopi.hostname");
324 | if (hostname == null) {
325 | hostname = "raspberrypi.local";
326 | }
327 | username = Preferences.get("gohai.uploadtopi.username");
328 | if (username == null) {
329 | username = "pi";
330 | }
331 | password = Preferences.get("gohai.uploadtopi.password");
332 | if (password == null) {
333 | password = "raspberry";
334 | }
335 | String tmp = Preferences.get("gohai.uploadtopi.persistent");
336 | if (tmp == null) {
337 | persistent = true;
338 | } else {
339 | persistent = Boolean.parseBoolean(tmp);
340 | }
341 | tmp = Preferences.get("gohai.uploadtopi.autostart");
342 | if (tmp == null) {
343 | autostart = true;
344 | } else {
345 | autostart = Boolean.parseBoolean(tmp);
346 | }
347 | tmp = Preferences.get("gohai.uploadtopi.logging");
348 | if (tmp == null) {
349 | logging = true;
350 | } else {
351 | logging = Boolean.parseBoolean(tmp);
352 | }
353 | }
354 |
355 |
356 | public void removeAutostarts() throws IOException {
357 | Session session = ssh.startSession();
358 | Command cmd = session.exec("sed -i \"/uploadtopi-managed/d\" .config/lxsession/LXDE-pi/autostart");
359 | cmd.join(3, TimeUnit.SECONDS);
360 | if (cmd.getExitStatus() != 0) {
361 | // not critical
362 | System.err.println("Error modifying .config/lxsession/LXDE-pi/autostart");
363 | }
364 | session.close();
365 | }
366 |
367 |
368 | public void removeSketch(String dest, String sketchName) throws IOException {
369 | // try to remove the current sketch's directory
370 | // necessary as sftp put w/ rename doesn't work if the target (directory) exists
371 | Session session = ssh.startSession();
372 | Command cmd = session.exec("rm -Rf " + dest + "/" + sketchName);
373 | cmd.join(10, TimeUnit.SECONDS);
374 | if (cmd.getExitStatus() != 0) {
375 | throw new RuntimeException("Error removing directory " + dest + "/" + sketchName);
376 | }
377 | session.close();
378 | }
379 |
380 |
381 | public int runRemoteSketch(String dest, String sketchName) throws IOException {
382 | Session session = ssh.startSession();
383 | // --uploadtopi-managed is a dummy argument we use in removeSketch() to indentify ours
384 | String cmdString = "DISPLAY=:0 " + dest + "/" + sketchName + "/" + sketchName + " --uploadtopi-managed";
385 | Command cmd = session.exec(cmdString);
386 |
387 | // redirect output to stdout and stderr
388 | new StreamCopier(cmd.getInputStream(), System.out)
389 | .bufSize(cmd.getLocalMaxPacketSize())
390 | .spawn("stdout");
391 |
392 | new StreamCopier(cmd.getErrorStream(), System.err)
393 | .bufSize(cmd.getLocalMaxPacketSize())
394 | .spawn("stderr");
395 |
396 | do {
397 | // wait for sketch execution to end
398 | Thread.yield();
399 | } while (cmd.isOpen() && !t.isInterrupted());
400 |
401 | try {
402 | // when the current thread is interrupted the following line throws a
403 | // ConnectionException, likely due to the InterruptedException pending
404 | cmd.close();
405 | session.close();
406 | return cmd.getExitStatus();
407 | } catch (Exception e) {
408 | return 0;
409 | }
410 | }
411 |
412 |
413 | public void savePreferences() {
414 | Preferences.set("gohai.uploadtopi.hostname", hostname);
415 | Preferences.set("gohai.uploadtopi.username", username);
416 | Preferences.set("gohai.uploadtopi.password", password);
417 | Preferences.setBoolean("gohai.uploadtopi.persistent", persistent);
418 | Preferences.setBoolean("gohai.uploadtopi.autostart", autostart);
419 | Preferences.setBoolean("gohai.uploadtopi.logging", logging);
420 | }
421 |
422 |
423 | public void stopSketches() throws IOException {
424 | Session session = ssh.startSession();
425 | // kill any Processing sketch we started either directly or through autostart
426 | Command cmd = session.exec("pgrep -f \"uploadtopi-managed\" | xargs kill -9");
427 | cmd.join(3, TimeUnit.SECONDS);
428 | // cmd.getExitStatus() throws a NPE here, not sure why - ignore for now
429 | session.close();
430 | }
431 |
432 |
433 | public void syncDisks() throws IOException {
434 | Session session = ssh.startSession();
435 | Command cmd = session.exec("sync");
436 | cmd.join(30, TimeUnit.SECONDS);
437 | if (cmd.getExitStatus() != 0) {
438 | // not critical
439 | System.err.println("Error syncing disks. Make sure you power off the Pi safely to prevent file corruption.");
440 | }
441 | session.close();
442 | }
443 |
444 |
445 | public void uploadSketch(String localDir, String dest, String sketchName) throws IOException {
446 | SFTPClient sftp = ssh.newSFTPClient();
447 | // XXX: only upload changed files?
448 | sftp.put(localDir, dest + "/" + sketchName);
449 | sftp.chmod(dest + "/" + sketchName + "/" + sketchName, 0755);
450 | sftp.close();
451 | }
452 | }
453 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | ##tool.name##
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
44 | A tool by ##author.name## for the Processing programming environment.
45 | Last update, ##date##.
46 |
47 |
48 | ##tool.sentence##
49 | ##tool.paragraph##
50 | Feel free to replace this paragraph with a description of the tool.
51 | Contributed libraries are developed, documented, and maintained by members of the Processing community. Further directions are included with each tool. For feedback and support, please post to the Discourse. We strongly encourage all libraries to be open source, but not all of them are.
52 |
53 |
54 |
55 |
56 |
57 |
58 |
Download
59 |
60 | Download ##tool.name## version ##tool.prettyVersion## (##tool.version##) in
61 | .zip format.
62 |
63 |
Installation
64 |
65 | Unzip and put the extracted ##project.name## folder into the tools folder of your Processing sketches. Reference and examples are included in the ##project.name## folder.
66 |
67 |
68 |
69 |
70 |
71 |
Keywords. ##tool.keywords##
72 |
Reference. Have a look at the javadoc reference here. A copy of the reference is included in the .zip as well.
73 |
Source. The source code of ##tool.name## is available at ##source.host##, and its repository can be browsed here.
74 |
75 |
76 |
77 |
78 |
Examples
79 |
Find a list of examples in the current distribution of ##tool.name##, or have a look at them by following the links below.