RSeries astromech firmware
PSIMatrix.h
Go to the documentation of this file.
1 #ifndef PSIMatrix_h
2 #define PSIMatrix_h
3 
4 #include "ReelTwo.h"
5 #include "core/SetupEvent.h"
6 #include "core/AnimatedEvent.h"
7 #include <SoftwareWire.h>
8 
9 #define DISPLAY_ADDRESS 0x65
10 #define SWIPE_SPEED 75 // Speed of swipe
11 #define SWIPE_FRONT_ONE 0xb1 // First colour of front PSI
12 #define SWIPE_FRONT_TWO 0 // Second colour of front PSI
13 #define SWIPE_REAR_ONE 0x5e // First colour of rear PSI
14 #define SWIPE_REAR_TWO 0x24 // Second colour of rear PSI
15 #define SWIPE_DELAY 500 // Base delay between swipes
16 
17 #ifdef USE_DEBUG
18  #define PSI_DEBUG
19 #endif
20 
21 
39 class PSIMatrix :
40  public SoftwareWire, AnimatedEvent, SetupEvent, CommandEvent
41 {
42 public:
44  {
45  kNormalVal = 0
46  };
47 
48  enum Sequence
49  {
50  kNormal = 0,
51  kSolid = 1,
52  kHeart = 2,
53  kMalf = 3,
54  };
55 
56  enum PSIID
57  {
59  kFrontPSI = 1,
61  kRearPSI = 2,
62  };
63 
64  virtual void setup() override
65  {
66  }
67 
71  PSIMatrix(const byte sdaPin, const byte sclPin, const byte psi) :
72  SoftwareWire(sdaPin, sclPin),
73  fPSI(psi)
74  {
75  #ifdef PSI_DEBUG
76  DEBUG_PRINTF("PSI#");
77  DEBUG_PRINTLN(fPSI);
78  #endif
79  }
80 
81 
89  void selectEffect(long inputNum)
90  {
91  }
92 
97  virtual void handleCommand(const char* cmd) override
98  {
99  if (*cmd++ == 'P' && *cmd++ == 'S')
100  {
101  long int cmdvalue = 0;
102  const char* c = cmd;
103  while (*c >= '0' && *c <= '9')
104  {
105  cmdvalue = cmdvalue * 10 + (*c++ - '0');
106  }
107  selectEffect(cmdvalue);
108  }
109  }
110 
114  inline void setSequence(Sequence seq = kNormal, uint8_t speedScale = 0, uint8_t numSeconds = 0)
115  {
116  selectEffect((long int)seq * 10000L + (long int)speedScale * 100 + numSeconds);
117  }
118 
122  virtual void animate() override
123  {
124  unsigned long currentMillis = millis();
125  if (currentMillis >= fSwipeSpeed)
126  {
127  swipe_main(swipe_position,100, true, 1);
128  if (swipe_direction == 0) {
129  if (swipe_position > 7) {
130  swipe_direction = 1;
131  fSwipeSpeed = currentMillis + random(500, 2000);
132  swipe_position--;
133  } else {
134  fSwipeSpeed = fSwipeMillis + SWIPE_SPEED;
135  swipe_position++;
136  }
137  } else {
138  if (swipe_position <= 0) {
139  swipe_direction = 0;
140  fSwipeSpeed = currentMillis + random(500, 2000);
141  swipe_position++;
142  } else {
143  fSwipeSpeed = fSwipeMillis + SWIPE_SPEED;
144  swipe_position--;
145  }
146  }
147  }
148  }
149 
150 private:
151  int fPSI;
152  int swipe_direction = 0;
153  int swipe_position = 0;
154  unsigned long fSwipeSpeed;
155  unsigned long fSwipeMillis;
156 
157  // Heart animation
158  uint64_t heart[32] = {
159 
160  0xff0000ffff0000ff,
161  0x0000000000000000,
162  0x0000000000000000,
163  0x0000000000000000,
164  0xff000000000000ff,
165  0xffff00000000ffff,
166  0xffffff0000ffffff,
167  0xffffffffffffffff,
168 
169  0xffffffffffffffff,
170  0xffff00ffff00ffff,
171  0xff000000000000ff,
172  0xff000000000000ff,
173  0xffff00000000ffff,
174  0xffffff0000ffffff,
175  0xffffffffffffffff,
176  0xffffffffffffffff,
177 
178  0xffffffffffffffff,
179  0xffffffffffffffff,
180  0xffff00ffff00ffff,
181  0xffff00000000ffff,
182  0xffffff0000ffffff,
183  0xffffffffffffffff,
184  0xffffffffffffffff,
185  0xffffffffffffffff,
186 
187  0xffffffffffffffff,
188  0xffff00ffff00ffff,
189  0xff000000000000ff,
190  0xff000000000000ff,
191  0xffff00000000ffff,
192  0xffffff0000ffffff,
193  0xffffffffffffffff,
194  0xffffffffffffffff
195  };
196 
198  int i2cSendBytes(uint8_t *data, uint8_t len)
199  {
200  int ret = 0;
201  beginTransmission(DISPLAY_ADDRESS);
202  ret = write(data, len);
203  endTransmission();
204  return ret;
205  }
206 
208  void displayFrames(uint64_t *buffer, uint16_t duration_time, bool forever_flag, uint8_t frames_number)
209  {
210  int ret = 0;
211  uint8_t data[72] = {0, };
212  // max 5 frames in storage
213  if (frames_number > 5) frames_number = 5;
214  else if (frames_number == 0) return;
215 
216  data[0] = 0x05;
217  data[1] = 0x0;
218  data[2] = 0x0;
219  data[3] = 0x0;
220  data[4] = frames_number;
221 
222  for (int i=frames_number-1;i>=0;i--)
223  {
224  data[5] = i;
225  // different from uint8_t buffer
226  for (int j = 0; j< 8; j++)
227  {
228  for (int k = 7; k >= 0; k--)
229  {
230  data[8+j*8+(7-k)] = ((uint8_t *)buffer)[j*8+k+i*64];
231  }
232  }
233 
234  if (i == 0)
235  {
236  // display when everything is finished.
237  data[1] = (uint8_t)(duration_time & 0xff);
238  data[2] = (uint8_t)((duration_time >> 8) & 0xff);
239  data[3] = forever_flag;
240  }
241 
242  i2cSendBytes(data, 72);
243  }
244  }
245 
247  void displayFrames(uint8_t *buffer, uint16_t duration_time, bool forever_flag, uint8_t frames_number)
248  {
249  uint8_t data[72] = {0, };
250  // max 5 frames in storage
251  if (frames_number > 5) frames_number = 5;
252  else if (frames_number == 0) return;
253 
254  data[0] = 0x05;
255  data[1] = 0x0;
256  data[2] = 0x0;
257  data[3] = 0x0;
258  data[4] = frames_number;
259 
260  for (int i=frames_number-1;i>=0;i--)
261  {
262  data[5] = i;
263  for (int j=0;j<64;j++) data[8+j] = buffer[j+i*64];
264  if (i == 0)
265  {
266  // display when everything is finished.
267  data[1] = (uint8_t)(duration_time & 0xff);
268  data[2] = (uint8_t)((duration_time >> 8) & 0xff);
269  data[3] = forever_flag;
270  }
271  i2cSendBytes(data, 72);
272  }
273  }
274 
276  void swipe_main(uint8_t pos, uint16_t duration_time, bool forever_flag, uint8_t frames_number)
277  {
278  int ret = 0;
279  int colour = 0;
280  uint8_t data[72] = {0, };
281 
282  data[0] = 0x05;
283  data[1] = 0x0;
284  data[2] = 0x0;
285  data[3] = 0x0;
286  data[4] = frames_number;
287  data[5] = 0;
288  // different from uint8_t buffer
289  for (int j = 0; j< 8; j++)
290  {
291  for (int k = 7; k >= 0; k--)
292  {
293  if (pos > k) {
294  if (fPSI == 1) {
295  colour = SWIPE_FRONT_ONE;
296  } else {
297  colour = SWIPE_REAR_ONE;
298  }
299  } else {
300  if (fPSI == 1) {
301  colour = SWIPE_FRONT_TWO;
302  } else {
303  colour = SWIPE_REAR_TWO;
304  }
305  }
306  //data[8+j*8+(7-k)] = ((uint8_t *)buffer)[j*8+k+i*64];
307  data[8+j*8+(7-k)] = colour;
308  }
309  }
310  data[1] = (uint8_t)(duration_time & 0xff);
311  data[2] = (uint8_t)((duration_time >> 8) & 0xff);
312  data[3] = forever_flag;
313 #ifdef PSI_DEBUG
314  DEBUG_PRINTF("SWIPE: Position - ");
315  DEBUG_PRINT(swipe_position);
316  DEBUG_PRINTF(" Direction - ");
317  DEBUG_PRINTLN(swipe_direction);
318 #endif
319  i2cSendBytes(data, 72);
320 
321  }
322 
324  // Routine to display a pulsing heart
325  void do_heart(uint8_t cycles, uint8_t pulse_speed)
326  {
327  for(int i=0;i<cycles;i++)
328  {
329  for (int i=0;i<4;i++)
330  {
331  displayFrames(heart+i*8, 100, true, 1);
332  delay(pulse_speed);
333  }
334  }
335  }
336 
338  // Routine to do <cycles> of random pixels. As it loops through <cycles>
339  // the frequency of pixels reduces
340  void do_random(uint8_t cycles, uint8_t pulse_speed)
341  {
342  uint8_t data[64] = {0, };
343  int pixel;
344  int colour;
345  for(int i=0;i<=cycles;i++)
346  {
347  for (int j = 0; j< 8; j++)
348  {
349  for (int k = 7; k >= 0; k--)
350  {
351  pixel = random(0,cycles);
352  if (pixel < cycles-i)
353  {
354  // Pixel on
355  colour = random(0,250);
356  } else {
357  colour = 0xff;
358  }
359  data[j*8+(7-k)] = colour;
360  }
361  }
362  displayFrames(data, 100, true, 1);
363  delay(pulse_speed);
364  }
365  uint8_t blank[64] = {0xff, };
366  for( int i = 0; i < sizeof(blank); ++i )
367  blank[i] = (char)255;
368  displayFrames(blank, 100, true, 1);
369  delay(2000);
370  }
371 
372 
373 };
374 
375 #endif
#define SWIPE_REAR_ONE
Definition: PSIMatrix.h:13
#define SWIPE_FRONT_ONE
Definition: PSIMatrix.h:11
#define DISPLAY_ADDRESS
Definition: PSIMatrix.h:9
#define SWIPE_REAR_TWO
Definition: PSIMatrix.h:14
#define SWIPE_SPEED
Definition: PSIMatrix.h:10
#define SWIPE_FRONT_TWO
Definition: PSIMatrix.h:12
#define DEBUG_PRINT(s)
Definition: ReelTwo.h:154
#define DEBUG_PRINTF(s)
Definition: ReelTwo.h:155
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:152
Base class for all animated devices.
Definition: AnimatedEvent.h:19
Base class for all command enabled devices.
Definition: CommandEvent.h:18
PSIMatrix by Darren Poulson daz@r2djp.co.uk
Definition: PSIMatrix.h:41
virtual void setup() override
Subclasses must implement this function to perform any necessary setup that cannot happen in the cons...
Definition: PSIMatrix.h:64
void selectEffect(long inputNum)
Select the specified effect using a 32-bit integer.
Definition: PSIMatrix.h:89
EffectValue
Definition: PSIMatrix.h:44
@ kNormalVal
Definition: PSIMatrix.h:45
PSIID
Definition: PSIMatrix.h:57
@ kRearPSI
Rear PSI ID.
Definition: PSIMatrix.h:61
@ kFrontPSI
Front PSI ID.
Definition: PSIMatrix.h:59
PSIMatrix(const byte sdaPin, const byte sclPin, const byte psi)
Constructor.
Definition: PSIMatrix.h:71
void setSequence(Sequence seq=kNormal, uint8_t speedScale=0, uint8_t numSeconds=0)
Select the specified effect sequence.
Definition: PSIMatrix.h:114
virtual void handleCommand(const char *cmd) override
Command Prefix: PS.
Definition: PSIMatrix.h:97
Sequence
Definition: PSIMatrix.h:49
@ kHeart
Definition: PSIMatrix.h:52
@ kNormal
Definition: PSIMatrix.h:50
@ kMalf
Definition: PSIMatrix.h:53
@ kSolid
Definition: PSIMatrix.h:51
virtual void animate() override
Perform a single frame of LED animation based on the selected sequence.
Definition: PSIMatrix.h:122
Utility class to control a VMusic2 module.
Definition: SetupEvent.h:16