proton

Firmware for Ghostbusters proton pack
git clone https://git.woozle.org/neale/proton.git

commit
4068174
parent
e58a19a
author
Neale Pickett
date
2016-10-02 11:59:11 -0600 MDT
Added wand and 7seg displays
5 files changed,  +201, -29
M ProtonPack.ino
+65, -26
  1@@ -10,26 +10,44 @@
  2 #include "Synchrotron.h"
  3 
  4 // Music Player
  5-#define MUSIC_CS 7
  6-#define MUSIC_DATA 6
  7-#define MUSIC_CARDCS 4
  8-#define MUSIC_REQ 3
  9+#define MUSIC_MCS 7
 10+#define MUSIC_DCS 6
 11+#define MUSIC_CCS 4
 12+#define MUSIC_DRQ 0 // Cut trace on board and wire to 0, so you can use 3 for SPI
 13 MusicPlayer *music;
 14 
 15+// LED output scaling
 16+#define brightness 255
 17+
 18 // Synchrotron
 19 #define SYNC1_NPIXELS 24
 20 #define SYNC1_DATA 5
 21 Synchrotron *sync1;
 22 
 23+// Neutrona Wand
 24+#define WAND1_NPIXELS 14
 25+#define WAND1_DATA 9
 26+Synchrotron *wand1;
 27+
 28+// Displays
 29+Adafruit_7segment disp1;
 30+Adafruit_7segment disp2;
 31+
 32 // Debug LED
 33 #define DEBUG 13
 34 
 35 // Inputs
 36 #define TRIGGER 8
 37+#define POT1 A0
 38 
 39 // global time counter
 40 unsigned long jiffies = 0;
 41 
 42+// 6 seems to be about what my overly-critical brain needs to buffer out
 43+// any delays caused by NMI sections of music player code so that they're unnoticeable
 44+#define MILLIS_PER_JIFFY 6
 45+
 46+
 47 void setup() {
 48   randomSeed(analogRead(12));
 49 
 50@@ -40,10 +58,20 @@ void setup() {
 51   pinMode(DEBUG, OUTPUT);
 52 
 53   // music player, this sets up SPI for us
 54-  music = new MusicPlayer(MUSIC_CS, MUSIC_DATA, MUSIC_REQ, MUSIC_CARDCS);
 55+  music = new MusicPlayer(MUSIC_MCS, MUSIC_DCS, MUSIC_DRQ, MUSIC_CCS);
 56 
 57   // synchrotron
 58   sync1 = new Synchrotron(SYNC1_NPIXELS, SYNC1_DATA);
 59+
 60+  // nuetrona wand
 61+  wand1 = new Synchrotron(WAND1_NPIXELS, WAND1_DATA);
 62+
 63+  // 7segment displays
 64+  disp1 = Adafruit_7segment();
 65+  disp1.begin(0x70);
 66+
 67+  disp2 = Adafruit_7segment();
 68+  disp2.begin(0x71);
 69 }
 70 
 71 
 72@@ -56,39 +84,39 @@ void flashDebug() {
 73 
 74 void loop() {
 75   static int state = 0;
 76-  // 6 seems to be about what my overly-critical brain needs to buffer out
 77-  // any music player delays so that they're unnoticeable
 78-  unsigned long new_jiffies = millis() / 6;
 79+  static float disp2val = 40.83;
 80+  unsigned long new_jiffies = millis() / MILLIS_PER_JIFFY;
 81   boolean trigger = ! digitalRead(TRIGGER);
 82 
 83   music->poll(jiffies);
 84 
 85   switch (state) {
 86-  case 0:
 87-    if (trigger && music->startPlayingFile("track001.mp3")) {
 88-      state = 1;
 89-      sync1->charge();
 90-    }
 91+  case 0: // move to steady state
 92+    sync1->transition(400, 12, brightness, 0, 0);
 93+    wand1->transition(400, 24, brightness, 0, 0);
 94+    state = 10;
 95     break;
 96-  case 1:
 97-    if (! music->isPlaying()) {
 98-      state = 3;
 99+  case 10: // waiting for charge button
100+    if (trigger && sync1->transitioned() && music->startPlayingFile("track001.mp3")) {
101+      state = 20;
102+      sync1->transition(700, 2, brightness, brightness/8, 0);
103+      wand1->transition(700, 10, brightness, brightness/8, 0);
104     }
105     break;
106-  case 3:
107-    if (trigger && music->startPlayingFile("track003.mp3")) {
108-      state = 4;
109-      sync1->fire();
110+  case 20: // charge button pressed
111+    if (sync1->transitioned()) {
112+      state = 30;
113     }
114     break;
115-  case 4:
116-    if (! trigger && music->startPlayingFile("track002.mp3")) {
117-      state = 5;
118-      sync1->discharge();
119+  case 30: // waiting for fire button
120+    if (trigger && music->startPlayingFile("nutrona.mp3")) {
121+      state = 40;
122+      sync1->transition(40, 1, brightness/8, brightness/4, brightness/2);
123+      wand1->transition(40, 5, brightness/6, brightness/2, brightness/6);
124     }
125     break;
126-  case 5:
127-    if (! music->isPlaying()) {
128+  case 40: // fire button pressed
129+    if (! trigger && music->startPlayingFile("track002.mp3")) {
130       state = 0;
131     }
132     break;
133@@ -97,6 +125,17 @@ void loop() {
134   if (new_jiffies > jiffies) {
135     jiffies = new_jiffies;
136     sync1->tick(jiffies);
137+    wand1->tick(jiffies);
138+
139+    if (jiffies % 10 == 0) {
140+      // This is expensive
141+      disp1.printFloat(5198 * sync1->speed());
142+      disp1.writeDisplay();
143+
144+      disp2val = analogRead(POT1) / 10.0;
145+      disp2.printFloat(disp2val, 1);
146+      disp2.writeDisplay();
147+    }
148     flashDebug();
149   }
150 }
M Synchrotron.cpp
+14, -3
 1@@ -39,12 +39,22 @@ Synchrotron::transition(int duration, int final_tickrate, byte final_r, byte fin
 2   initial_b = b;
 3 }
 4 
 5+bool
 6+Synchrotron::transitioned() {
 7+  return (transition_elapsed >= transition_length);
 8+}
 9+
10+float
11+Synchrotron::speed() {
12+  return 1 / ftickrate;
13+}
14+
15 Synchrotron::standby() {
16   transition(400, 12, brightness, 0, 0);
17 }
18 
19 Synchrotron::charge() {
20-  transition(400, 2, brightness, brightness/8, 0);
21+  transition(700, 2, brightness, brightness/8, 0);
22 }
23 
24 Synchrotron::fire() {
25@@ -75,10 +85,11 @@ Synchrotron::tick(unsigned long jiffies) {
26   }
27 
28   if (transition_length > transition_elapsed) {
29-    tickrate = initial_tickrate + (dtickrate * transition_elapsed);
30+    transition_elapsed += 1;
31+    ftickrate = initial_tickrate + (dtickrate * transition_elapsed);
32+    tickrate = ftickrate;
33     r = initial_r + (dr * transition_elapsed);
34     g = initial_g + (dg * transition_elapsed);
35     b = initial_b + (db * transition_elapsed);
36-    transition_elapsed += 1;
37   }
38 }
M Synchrotron.h
+3, -0
 1@@ -14,9 +14,12 @@ class Synchrotron {
 2   int transition_length, transition_elapsed;
 3   int initial_tickrate, initial_r, initial_g, initial_b;
 4   float dtickrate, dr, dg, db;
 5+  float ftickrate;
 6 public:
 7   Synchrotron(uint16_t n, uint8_t p=6, neoPixelType t=NEO_GRB + NEO_KHZ800);
 8   transition(int duration, int final_tickrate, byte final_r, byte final_g, byte final_b);
 9+  bool transitioned();
10+  float speed();
11   standby();
12   charge();
13   fire();
A nutrona.mp3
+0, -0
A radlove.svg
+119, -0
  1@@ -0,0 +1,119 @@
  2+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  3+<!-- Created with Inkscape (http://www.inkscape.org/) -->
  4+
  5+<svg
  6+   xmlns:dc="http://purl.org/dc/elements/1.1/"
  7+   xmlns:cc="http://creativecommons.org/ns#"
  8+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  9+   xmlns:svg="http://www.w3.org/2000/svg"
 10+   xmlns="http://www.w3.org/2000/svg"
 11+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 12+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 13+   width="141.89731mm"
 14+   height="141.89731mm"
 15+   viewBox="0 0 502.78573 502.78572"
 16+   id="svg2"
 17+   version="1.1"
 18+   inkscape:version="0.91 r13725"
 19+   sodipodi:docname="radlove.svg">
 20+  <defs
 21+     id="defs4" />
 22+  <sodipodi:namedview
 23+     id="base"
 24+     pagecolor="#ffffff"
 25+     bordercolor="#666666"
 26+     borderopacity="1.0"
 27+     inkscape:pageopacity="0.0"
 28+     inkscape:pageshadow="2"
 29+     inkscape:zoom="1.4"
 30+     inkscape:cx="240.22136"
 31+     inkscape:cy="248.73745"
 32+     inkscape:document-units="px"
 33+     inkscape:current-layer="g4238"
 34+     showgrid="false"
 35+     fit-margin-top="0"
 36+     fit-margin-left="0"
 37+     fit-margin-right="0"
 38+     fit-margin-bottom="0"
 39+     inkscape:window-width="1920"
 40+     inkscape:window-height="1016"
 41+     inkscape:window-x="0"
 42+     inkscape:window-y="27"
 43+     inkscape:window-maximized="1" />
 44+  <metadata
 45+     id="metadata7">
 46+    <rdf:RDF>
 47+      <cc:Work
 48+         rdf:about="">
 49+        <dc:format>image/svg+xml</dc:format>
 50+        <dc:type
 51+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 52+        <dc:title></dc:title>
 53+      </cc:Work>
 54+    </rdf:RDF>
 55+  </metadata>
 56+  <g
 57+     inkscape:label="Layer 1"
 58+     inkscape:groupmode="layer"
 59+     id="layer1"
 60+     transform="translate(-120.0357,-286.68361)">
 61+    <g
 62+       id="g4238">
 63+      <circle
 64+         r="242.39842"
 65+         cy="538.07648"
 66+         cx="371.42856"
 67+         id="path4136"
 68+         style="opacity:1;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:17.98888016;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
 69+      <path
 70+         d="m 479.19755,351.41513 a 215.53796,215.53796 0 0 1 107.76897,186.66135 l -215.53796,0 z"
 71+         sodipodi:end="0"
 72+         sodipodi:start="5.2359878"
 73+         sodipodi:ry="215.53796"
 74+         sodipodi:rx="215.53796"
 75+         sodipodi:cy="538.07648"
 76+         sodipodi:cx="371.42856"
 77+         sodipodi:type="arc"
 78+         style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:15.9955101;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 79+         id="circle4161" />
 80+      <path
 81+         d="M 155.89059,538.07647 A 215.53796,215.53796 0 0 1 263.65958,351.41513 l 107.76898,186.66135 z"
 82+         sodipodi:end="4.1887902"
 83+         sodipodi:start="3.1415927"
 84+         sodipodi:ry="215.53796"
 85+         sodipodi:rx="215.53796"
 86+         sodipodi:cy="538.07648"
 87+         sodipodi:cx="371.42856"
 88+         sodipodi:type="arc"
 89+         id="path4163"
 90+         style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:15.9955101;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
 91+      <path
 92+         style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:15.9955101;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 93+         id="path4165"
 94+         sodipodi:type="arc"
 95+         sodipodi:cx="371.42856"
 96+         sodipodi:cy="538.07648"
 97+         sodipodi:rx="215.53796"
 98+         sodipodi:ry="215.53796"
 99+         sodipodi:start="1.0471976"
100+         sodipodi:end="2.0943951"
101+         d="m 479.19753,724.73783 a 215.53796,215.53796 0 0 1 -215.53795,0 L 371.42856,538.07648 Z" />
102+    </g>
103+    <g
104+       transform="matrix(0.79020839,0,0,0.79020839,-76.502899,240.96985)"
105+       inkscape:label="Layer 1"
106+       id="layer1-7">
107+      <g
108+         transform="matrix(0.97556,0,0,0.97556,-18.264,24.845)"
109+         style="stroke:#af024c;stroke-width:2.87529993"
110+         id="g17152">
111+        <path
112+           d="m 540.37525,265.35878 c -29.691,0.61893 -55.518,19.25 -64.878,50.794 -15.808,81.974 75.349,116.47 125.55,165.46 43.586,-56.698 128.92,-71.353 124.66,-155.21 -3.7056,-18.7 -14.155,-33.925 -28.166,-44.632 -18.775,-14.365 -44.927,-19.303 -67.275,-10.718 -11.956,4.22 -22.844,11.552 -30.981,21.271 -14.141,-17.43 -36.494,-27.452 -58.909,-26.962 z"
113+           style="fill:#d40055;stroke:#000000;stroke-width:15.06948352;stroke-miterlimit:4;stroke-dasharray:none"
114+           sodipodi:nodetypes="cccccccc"
115+           id="path8148"
116+           inkscape:connector-curvature="0" />
117+      </g>
118+    </g>
119+  </g>
120+</svg>