Simple single-color 8x8x8 LED Cube with AVRs
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cubeWorker.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. /*
  2. * cubeWorker.java
  3. *
  4. * Copyright 2011 Thomas Buck <xythobuz@me.com>
  5. * Copyright 2011 Max Nuding <max.nuding@gmail.com>
  6. * Copyright 2011 Felix Bäder <baeder.felix@gmail.com>
  7. *
  8. * This file is part of LED-Cube.
  9. *
  10. * LED-Cube is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * LED-Cube is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with LED-Cube. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. /*
  24. * This class handles one animation file. This file can contain
  25. * many animations, but has to be only 1Mbit in size (128*1024 Byte).
  26. */
  27. import java.util.ArrayList;
  28. import java.util.Arrays;
  29. import java.util.Scanner;
  30. import java.util.Collections;
  31. import java.io.FileWriter;
  32. import java.io.File;
  33. import java.io.IOException;
  34. import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
  35. import java.io.Closeable;
  36. import java.io.FileNotFoundException;
  37. import java.io.FileOutputStream;
  38. import java.io.IOException;
  39. import java.io.InputStream;
  40. import java.io.InputStreamReader;
  41. import java.io.OutputStream;
  42. import java.io.BufferedReader;
  43. import java.net.URI;
  44. import java.net.URISyntaxException;
  45. import java.net.URL;
  46. import java.security.CodeSource;
  47. import java.security.ProtectionDomain;
  48. import java.util.zip.ZipEntry;
  49. import java.util.zip.ZipException;
  50. import java.util.zip.ZipFile;
  51. import java.lang.Process;
  52. import java.util.StringTokenizer;
  53. public class cubeWorker {
  54. // --------------------
  55. // Definitions
  56. // --------------------
  57. final int UP = 0;
  58. final int DOWN = 1;
  59. // --------------------
  60. // Fields
  61. // --------------------
  62. private ArrayList<Animation> animations = new ArrayList<Animation>();
  63. private int framesRemaining = 2016; // (128 * 1024) / 65 = 2016,...
  64. private boolean changedState = false;
  65. // --------------------
  66. cubeWorker() {
  67. animations.add(new Animation());
  68. animations.get(0).setName("Animation 1");
  69. animations.get(0).add(0);
  70. animations.get(0).get(0).setName("Frame 1");
  71. framesRemaining--;
  72. }
  73. cubeWorker(ArrayList<Animation> anims) {
  74. animations = anims;
  75. }
  76. // --------------------
  77. // Misc. Methods
  78. // --------------------
  79. // Returns how many animations are defined
  80. public int numOfAnimations() {
  81. return animations.size();
  82. }
  83. // Returns how many frames are in the current animation
  84. public int numOfFrames(int selectedAnimation) {
  85. return animations.get(selectedAnimation).size();
  86. }
  87. // Tells how many Frames you can add until you reached 1 Mbit...
  88. public int framesRemaining() {
  89. return framesRemaining;
  90. }
  91. // --------------------
  92. // Animation Specific
  93. // --------------------
  94. // Adds a new Animation
  95. // Returns id if ok, -1 if error or not enough space for
  96. // another animation
  97. public int addAnimation() {
  98. changedState = true;
  99. if (framesRemaining <= 0) {
  100. return -1;
  101. } else {
  102. int s = animations.size();
  103. animations.add(s, new Animation());
  104. animations.get(s).setName("Animation " + animations.size());
  105. return s;
  106. }
  107. }
  108. // Removes an animation
  109. public void removeAnimation(int selectedAnimation) {
  110. changedState = true;
  111. animations.remove(selectedAnimation);
  112. selectedAnimation = 0;
  113. }
  114. public String getAnimationName(int selectedAnimation) {
  115. return animations.get(selectedAnimation).getName();
  116. }
  117. public void setAnimationName(String s, int selectedAnimation) {
  118. changedState = true;
  119. animations.get(selectedAnimation).setName(s);
  120. }
  121. public void moveAnimation(int dir, int selectedAnimation) {
  122. changedState = true;
  123. if (dir == UP){
  124. //animation moved up
  125. if (selectedAnimation > 0) {
  126. Collections.swap(animations, selectedAnimation, selectedAnimation - 1);
  127. }
  128. } else if (dir == DOWN){
  129. //animation moved down
  130. if (selectedAnimation < (animations.size() - 1)) {
  131. Collections.swap(animations, selectedAnimation, selectedAnimation + 1);
  132. }
  133. }
  134. }
  135. // --------------------
  136. // Frame Specific
  137. // --------------------
  138. public String getFrameName(int anim, int frame) {
  139. return animations.get(anim).get(frame).getName();
  140. }
  141. public void setFrameName(String s, int anim, int frame) {
  142. changedState = true;
  143. animations.get(anim).get(frame).setName(s);
  144. }
  145. // Adds a Frame to the current animation.
  146. // Returns id if okay, -1 if error
  147. public int addFrame(int anim) {
  148. changedState = true;
  149. if (framesRemaining <= 0) {
  150. return -1;
  151. }
  152. framesRemaining--;
  153. int s = animations.get(anim).size();
  154. animations.get(anim).add(s);
  155. animations.get(anim).get(s).setName("Frame " + animations.get(anim).size());
  156. return s;
  157. }
  158. // Remove the frame
  159. public void removeFrame(int anim, int frame) {
  160. changedState = true;
  161. animations.get(anim).remove(frame);
  162. }
  163. // Returns array with 64 bytes with led values
  164. public short[] getFrame(int anim, int frame) {
  165. return animations.get(anim).get(frame).getData();
  166. }
  167. public void setFrame(short[] data, int anim, int frame) {
  168. changedState = true;
  169. animations.get(anim).get(frame).setData(data);
  170. }
  171. // Frame duration in 1/24th of a second
  172. public short getFrameTime(int anim, int frame) {
  173. return animations.get(anim).get(frame).getTime();
  174. }
  175. public void setFrameTime(short time, int anim, int frame) {
  176. changedState = true;
  177. animations.get(anim).get(frame).setTime(time);
  178. }
  179. public void moveFrame(int dir, int anim, int frame){
  180. changedState = true;
  181. if (dir == UP){
  182. // frame moved up
  183. if (frame > 0) {
  184. Collections.swap(animations.get(anim).frames, frame, frame - 1);
  185. }
  186. } else if (dir == DOWN){
  187. // frame moved down
  188. if (frame < (animations.get(anim).size() - 1)) {
  189. Collections.swap(animations.get(anim).frames, frame, frame + 1);
  190. }
  191. }
  192. }
  193. // --------------------
  194. // File Specific
  195. // --------------------
  196. // Loads an animation file into this object
  197. public int loadState(String path) {
  198. changedState = false;
  199. try {
  200. animations = AnimationUtility.readFile(path);
  201. } catch (Exception e) {
  202. System.out.println("Did not load!");
  203. e.printStackTrace(System.out);
  204. return -1;
  205. }
  206. int size = 0;
  207. for (int i = 0; i < animations.size(); i++) {
  208. size += animations.get(i).size();
  209. }
  210. framesRemaining = 2016 - size;
  211. if (size > 2016) {
  212. return -1;
  213. }
  214. return 0;
  215. }
  216. // Saves the state of this object in an animation file
  217. public int saveState(String path) {
  218. changedState = false;
  219. AnimationUtility.writeFile(path, animations);
  220. if (AnimationUtility.getLastError() != null) {
  221. System.out.println(AnimationUtility.getLastError());
  222. return -1;
  223. }
  224. return 0;
  225. }
  226. // Returns true if last saved state != current state
  227. public boolean changedStateSinceSave() {
  228. return changedState;
  229. }
  230. // --------------------
  231. // Serial Port Specific
  232. // --------------------
  233. // sends state of object to led cube
  234. public int uploadState(String port) {
  235. return 0;
  236. }
  237. // loads all state from the cube into this object
  238. public int downloadState(String port) {
  239. return 0;
  240. }
  241. public String[] getSerialPorts() {
  242. String[] ports = {"Select serial port..."};
  243. String helperName;
  244. if ((System.getProperty("os.name").toLowerCase()).indexOf("win") >= 0) {
  245. helperName = "serialHelper.exe";
  246. } else {
  247. helperName = "serialHelper";
  248. }
  249. String[] arg = {"p"};
  250. String portLines = HelperUtility.runHelper(arg);
  251. // System.out.println("Output: " + portLines);
  252. if (portLines == null) {
  253. return ports;
  254. }
  255. StringTokenizer sT = new StringTokenizer(portLines, "\n");
  256. int size = sT.countTokens() + 1;
  257. ports = new String[size];
  258. ports[0] = "Select serial port...";
  259. for (int i = 1; i < size; i++) {
  260. ports[i] = sT.nextToken();
  261. }
  262. return ports;
  263. }
  264. // --------------------
  265. }
  266. class HelperUtility {
  267. public static String runHelper(String[] args) {
  268. String[] helperName = new String[args.length + 1];
  269. boolean windows = false;
  270. if ((System.getProperty("os.name").toLowerCase()).indexOf("win") >= 0) {
  271. helperName[0] = "serialHelper.exe";
  272. windows = true;
  273. } else {
  274. helperName[0] = "serialHelper";
  275. }
  276. for (int i = 0; i < args.length; i++) {
  277. helperName[i + 1] = args[i];
  278. }
  279. String ret = "";
  280. try {
  281. File helper = new File(getFile(getJarURI(), helperName[0]));
  282. helperName[0] = helper.getAbsolutePath();
  283. if (!windows) {
  284. Process execute = Runtime.getRuntime().exec("chmod a+x " + helper.getAbsolutePath());
  285. execute.waitFor();
  286. if (execute.exitValue() != 0) {
  287. System.out.println("Could not set helper as executeable (" + execute.exitValue()+ ")");
  288. return null;
  289. }
  290. }
  291. Process p = Runtime.getRuntime().exec(helperName);
  292. BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
  293. String line;
  294. boolean fin = false;
  295. do { // Wait for process to finish... Doesn't work...?
  296. fin = false;
  297. try {
  298. p.waitFor();
  299. } catch (Exception e) {
  300. fin = true;
  301. }
  302. // Read output in same loop... Should work...!
  303. line = br.readLine();
  304. if (line != null) {
  305. ret = ret + line + "\n";
  306. fin = true;
  307. }
  308. } while (fin);
  309. br.close();
  310. if (ret.length() == 0) {
  311. ret = "g"; // We have added a last \n... We will remove it, so add garbage to be removed...
  312. }
  313. ret = ret.substring(0, ret.length() - 1);
  314. return ret;
  315. } catch(Exception e) {
  316. e.printStackTrace();
  317. }
  318. return null;
  319. }
  320. // From http://stackoverflow.com/questions/600146/run-exe-which-is-packaged-inside-jar
  321. private static URI getJarURI()
  322. throws URISyntaxException
  323. {
  324. final ProtectionDomain domain;
  325. final CodeSource source;
  326. final URL url;
  327. final URI uri;
  328. domain = cubeWorker.class.getProtectionDomain();
  329. source = domain.getCodeSource();
  330. url = source.getLocation();
  331. uri = url.toURI();
  332. return (uri);
  333. }
  334. private static URI getFile(final URI where,
  335. final String fileName)
  336. throws ZipException,
  337. IOException
  338. {
  339. final File location;
  340. final URI fileURI;
  341. location = new File(where);
  342. // not in a JAR, just return the path on disk
  343. if(location.isDirectory())
  344. {
  345. fileURI = URI.create(where.toString() + fileName);
  346. }
  347. else
  348. {
  349. final ZipFile zipFile;
  350. zipFile = new ZipFile(location);
  351. try
  352. {
  353. fileURI = extract(zipFile, fileName);
  354. }
  355. finally
  356. {
  357. zipFile.close();
  358. }
  359. }
  360. return (fileURI);
  361. }
  362. private static URI extract(final ZipFile zipFile,
  363. final String fileName)
  364. throws IOException
  365. {
  366. final File tempFile;
  367. final ZipEntry entry;
  368. final InputStream zipStream;
  369. OutputStream fileStream;
  370. tempFile = File.createTempFile(fileName, Long.toString(System.currentTimeMillis()));
  371. tempFile.deleteOnExit();
  372. entry = zipFile.getEntry(fileName);
  373. if(entry == null)
  374. {
  375. throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
  376. }
  377. zipStream = zipFile.getInputStream(entry);
  378. fileStream = null;
  379. try
  380. {
  381. final byte[] buf;
  382. int i;
  383. fileStream = new FileOutputStream(tempFile);
  384. buf = new byte[1024];
  385. i = 0;
  386. while((i = zipStream.read(buf)) != -1)
  387. {
  388. fileStream.write(buf, 0, i);
  389. }
  390. }
  391. finally
  392. {
  393. close(zipStream);
  394. close(fileStream);
  395. }
  396. return (tempFile.toURI());
  397. }
  398. private static void close(final Closeable stream)
  399. {
  400. if(stream != null)
  401. {
  402. try
  403. {
  404. stream.close();
  405. }
  406. catch(final IOException ex)
  407. {
  408. ex.printStackTrace();
  409. }
  410. }
  411. }
  412. }
  413. class AnimationUtility {
  414. private static String lastError = null;
  415. public static ArrayList<Animation> readFile(String path) throws Exception {
  416. Scanner sc = new Scanner(new File(path));
  417. ArrayList<Animation> animations = new ArrayList<Animation>();
  418. do {
  419. Animation tmp = readAnimation(sc);
  420. if (tmp == null) {
  421. return animations;
  422. }
  423. if (sc.hasNextLine()) {
  424. sc.nextLine();
  425. }
  426. animations.add(tmp);
  427. } while (sc.hasNextLine());
  428. return animations;
  429. }
  430. public static void writeFile(String path, ArrayList<Animation> animations) {
  431. File f = new File(path);
  432. if (f.exists()) {
  433. try {
  434. f.delete();
  435. } catch (Exception e) {
  436. lastError = e.toString();
  437. return;
  438. }
  439. }
  440. FileWriter output = null;
  441. try {
  442. output = new FileWriter(f);
  443. for (int i = 0; i < animations.size(); i++) {
  444. writeAnimation(animations.get(i), output, (i == (animations.size() - 1)));
  445. }
  446. } catch (Exception e) {
  447. lastError = e.toString();
  448. return;
  449. } finally {
  450. if (output != null) {
  451. try {
  452. output.close();
  453. } catch (Exception e) {
  454. lastError = e.toString();
  455. }
  456. }
  457. }
  458. }
  459. public static String getLastError() {
  460. String tmp = lastError;
  461. lastError = null;
  462. return tmp;
  463. }
  464. private static Animation readAnimation(Scanner sc) {
  465. Animation anim = new Animation();
  466. AFrame f = null;
  467. int index = 0;
  468. String tmpSize = sc.nextLine().replaceAll("\\n", "");
  469. if (tmpSize.equals("")) {
  470. return null;
  471. }
  472. Integer tmpSizeAgain = new Integer(tmpSize);
  473. int size = tmpSizeAgain.intValue();
  474. anim.setName(sc.nextLine());
  475. while (size > 0) {
  476. f = readFrame(sc, index);
  477. anim.add(index, f);
  478. index++;
  479. size--;
  480. }
  481. return anim;
  482. }
  483. private static AFrame readFrame(Scanner sc, int index) {
  484. AFrame frame = new AFrame();
  485. frame.setName(sc.nextLine());
  486. short[] d = {};
  487. for (int i = 0; i < 8; i++) {
  488. short[] data = hexConvert(sc.nextLine());
  489. d = concat(data, d);
  490. }
  491. frame.setData(d);
  492. d = hexConvert(sc.nextLine());
  493. frame.setTime(d[0]);
  494. return frame;
  495. }
  496. private static short[] concat(short[] a, short[] b) {
  497. short[] c = new short[a.length + b.length];
  498. System.arraycopy(a, 0, c, 0, a.length);
  499. System.arraycopy(b, 0, c, a.length, b.length);
  500. return c;
  501. }
  502. private static short[] hexConvert(String hex) {
  503. hex = hex.replaceAll("\\n", "");
  504. short[] tmp = new short[hex.length()/2];
  505. for (int i = 0; i < hex.length(); i=i+2){
  506. char[] tmpString = new char[2];
  507. tmpString[0] = hex.charAt(i);
  508. tmpString[1] = hex.charAt(i+1);
  509. String tmpS = String.copyValueOf(tmpString);
  510. if(i == 0){
  511. tmp[0] = Short.parseShort(tmpS, 16);
  512. } else {
  513. tmp[i/2] = Short.parseShort(tmpS, 16);
  514. }
  515. }
  516. return tmp;
  517. }
  518. private static void writeAnimation(Animation anim, FileWriter f, boolean last) throws IOException {
  519. f.write(anim.size() + "\n");
  520. f.write(anim.getName() + "\n");
  521. for (int i = 0; i < anim.size(); i++) {
  522. writeFrame(anim.get(i), f);
  523. }
  524. if (!last) {
  525. f.write("\n");
  526. }
  527. }
  528. private static void writeFrame(AFrame fr, FileWriter f) throws IOException {
  529. f.write(fr.getName() + "\n");
  530. for (int i = 0; i < 8; i++) {
  531. writeLayer(fr.getLayer(i), f);
  532. }
  533. f.write(Integer.toString( (fr.getTime() & 0xff) + 0x100, 16).substring(1) + "\n");
  534. }
  535. private static void writeLayer(short[] l, FileWriter f) throws IOException {
  536. String hex = "";
  537. for (int i = 0; i < l.length; i++) {
  538. hex += Integer.toString( (l[i] & 0xff) + 0x100, 16).substring(1);
  539. }
  540. hex += "\n";
  541. f.write(hex);
  542. }
  543. }
  544. class AFrame {
  545. private short[] data = new short[64];
  546. private short duration = 1;
  547. private String name = "Frame";
  548. String getName() {
  549. return name;
  550. }
  551. void setName(String s) {
  552. name = s;
  553. }
  554. void setData(short[] d) {
  555. data = d;
  556. }
  557. short[] getData() {
  558. return data;
  559. }
  560. void setTime(short t) {
  561. duration = t;
  562. }
  563. short getTime() {
  564. return duration;
  565. }
  566. short[] getLayer(int i) {
  567. return Arrays.copyOfRange(data, (i * 8), (i * 8) + 8);
  568. }
  569. }
  570. class Animation {
  571. ArrayList<AFrame> frames = new ArrayList<AFrame>();
  572. private int lastFrameIndex = 0;
  573. private String name = "Animation";
  574. String getName() {
  575. return name;
  576. }
  577. void setName(String s) {
  578. name = s;
  579. }
  580. AFrame get(int i) {
  581. try {
  582. return frames.get(i);
  583. } catch (IndexOutOfBoundsException e) {
  584. System.out.println(e.toString());
  585. return null;
  586. }
  587. }
  588. void set(AFrame f, int i) {
  589. if (lastFrameIndex <= i) {
  590. try {
  591. frames.set(i, f);
  592. } catch (IndexOutOfBoundsException e) {
  593. System.out.println(e.toString());
  594. }
  595. }
  596. }
  597. void remove(int i) {
  598. try {
  599. frames.remove(i);
  600. } catch (IndexOutOfBoundsException e) {
  601. System.out.println(e.toString());
  602. }
  603. }
  604. void add(int i) {
  605. try {
  606. frames.add(i, new AFrame());
  607. lastFrameIndex++;
  608. } catch (IndexOutOfBoundsException e) {
  609. System.out.println(e.toString());
  610. }
  611. }
  612. void add(int i, AFrame f) {
  613. try {
  614. frames.add(i, f);
  615. lastFrameIndex++;
  616. } catch (IndexOutOfBoundsException e) {
  617. System.out.println(e.toString());
  618. }
  619. }
  620. int size() {
  621. return frames.size();
  622. }
  623. }