source: orbit/iOS/Orbit/Orbit/controllers/FlightViewController.m @ fc960da

Servo
Last change on this file since fc960da was fc960da, checked in by Steve Castellotti <sc@…>, 6 years ago
  • Property mode set to 100644
File size: 10.5 KB
Line 
1//
2//  FlightViewController.m
3//  Orbit
4//
5//  Copyright (c) 2013 Puzzlebox Productions, LLC. All rights reserved.
6//  Originally created by Jonathon Horsman.
7//
8//  This code is released under the GNU Public License (GPL) version 2
9//  For more information please refer to http://www.gnu.org/copyleft/gpl.html
10//
11
12#import <QuartzCore/QuartzCore.h>
13#import "FlightViewController.h"
14#import "AppDelegate.h"
15#import "SignalConverter.h"
16
17//#import "StatisticsViewController.h"
18
19//#import "HistoryAppDataObject.h"
20//#import "AppDelegateProtocol.h"
21
22#define STATUS_DEFAULT 0
23#define STATUS_CONNECTING 1
24#define STATUS_CONNECTED 2
25#define STATUS_PROCESSING 3
26#define STATUS_ACTIVE 4
27
28@implementation FlightViewController {
29   SignalConverter *signalConverter;
30   int deviceStatus;
31   BOOL warned;
32}
33
34@synthesize attention, meditation, signal, power, attentionThreshold, meditationThreshold, connectButton, testButton, statusImage, signalPercent, attentionPercent, meditationPercent, powerPercent;
35
36//- (HistoryAppDataObject*) theAppDataObject;
37//{
38//      id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
39//      HistoryAppDataObject* theDataObject;
40//      theDataObject = (HistoryAppDataObject*) theDelegate.theAppDataObject;
41//      return theDataObject;
42//}
43
44- (void)viewDidLoad
45{
46   [super viewDidLoad];
47   
48   attention.progressTintColor = [UIColor redColor];
49   self.attentionThreshold.minimumTrackTintColor = [UIColor grayColor];
50   meditation.progressTintColor = [UIColor blueColor];
51   self.meditationThreshold.minimumTrackTintColor = [UIColor grayColor];
52   self.meditationThreshold.value = 0;
53   
54   AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
55   signalConverter = appDelegate.signalConverter;
56   
57   signalConverter.delegate = self;
58   [self setThresholds];
59   [self.attentionThreshold addTarget:self action:@selector(setThresholds) forControlEvents:UIControlEventValueChanged];
60   [self.meditationThreshold addTarget:self action:@selector(setThresholds) forControlEvents:UIControlEventValueChanged];
61   
62}
63
64#pragma mark view updates
65
66// Set all levels back to zero
67- (void) resetViews
68{
69   signal.progress = 0;
70   signalPercent.text = @"0%";
71   attention.progress = 0;
72   attentionPercent.text = @"0%";
73   meditation.progress = 0;
74   meditationPercent.text = @"0%";
75   power.progress = 0;
76   powerPercent.text = @"0%";
77   [self updateStatusImage:STATUS_DEFAULT];
78   connectButton.title = @"Connect";
79}
80
81- (void) updateStatusImage:(int) statusNo
82{
83   if (statusNo != deviceStatus) {
84      [statusImage setImage: [UIImage imageNamed:[NSString stringWithFormat:@"status_%u", statusNo]]];
85      deviceStatus = statusNo;
86   }
87}
88
89- (void) setThresholds
90{
91   [signalConverter setValuesForAttention:attentionThreshold.value meditation:meditationThreshold.value];
92}
93
94#pragma mark - SignalConverterDelegate methods
95
96- (void) updatedValuesForSignal: (float)signalStrength
97                      attention: (float)attentionLevel
98                     meditation: (float)meditationLevel
99                          power: (float)powerLevel
100{
101   
102   // Set Attention and Meditation to zero if we've lost signal
103   if (signalStrength < 100.0) {
104      attentionLevel = 0.000000;
105      meditationLevel = 0.000000;
106      powerLevel = 0.000000;
107   }
108   
109   self.signal.progress = signalStrength / 100;
110   self.signalPercent.text = [NSString stringWithFormat:@"%i%%", (int)(signalStrength)];
111   self.attention.progress = attentionLevel;
112   self.attentionPercent.text = [NSString stringWithFormat:@"%i%%", (int)(attentionLevel * 100)];
113   self.meditation.progress = meditationLevel;
114   self.meditationPercent.text = [NSString stringWithFormat:@"%i%%", (int)(meditationLevel * 100)];
115   self.power.progress = powerLevel;
116   self.powerPercent.text = [NSString stringWithFormat:@"%i%%", (int)(powerLevel * 100)];
117   [self updateStatusImage:[self statusFromSignal:signalStrength power:powerLevel]];
118   
119   [self updateScores];
120   
121}
122
123- (int) statusFromSignal: (float)signalLevel power:(float)powerLevel
124{
125   
126   //   NSLog(@"signalLevel: %f | powerLevel: %f", signalLevel, powerLevel);
127   
128   if (signalLevel == 0.0) { // no signal
129      return STATUS_CONNECTING;
130   }
131   
132   if (signalLevel < 100.0) { // poor signal
133      return STATUS_CONNECTED;
134   }
135   
136   if (powerLevel == 0.0) { // strong signal but thresholds not met
137      return STATUS_PROCESSING;
138   } else { // flight command sent to orbit
139      return STATUS_ACTIVE;
140   }
141   
142}
143
144- (void) notifyHeadsetConnect
145{
146   [self updateStatusImage:STATUS_CONNECTING];
147}
148
149- (void) notifyHeadsetDisconnect
150{
151   // Reset the outputs back to zero
152   [self resetViews];
153}
154
155- (void) notifyDeviceConnected:(NSString *)name
156{
157   [self updateStatusImage:STATUS_CONNECTING];
158   connectButton.title = @"Disconnect";
159}
160
161- (void) appStopped
162{
163   [self resetViews]; // just in case it didn't happen on close
164}
165
166#pragma mark - button press events
167
168- (IBAction) connectButtonPressed:(id) sender {
169   
170   if (signalConverter.running) {
171      [signalConverter stopProcessing];
172      [self resetViews];
173   } else {
174      BOOL volumeMax  = [signalConverter isVolumeMax];
175      BOOL headphones = [signalConverter isAudioJackPlugged];
176     
177      if (!warned && !volumeMax && !headphones) {
178         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Check Volume & Transmitter" message:@"Ensure the volume is at max and the transmitter is plugged into the headphones" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
179         [alert show];
180      } else if (!warned && !volumeMax) {
181         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Turn Up The Volume" message:@"Your device volume must be at the maximum for proper operation" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
182         [alert show];
183      } else if (!warned && !headphones) {
184         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Plug In The Transmitter" message:@"Ensure the infrared transmitter is plugged into the headphone jack" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
185         [alert show];
186      } else if (!signalConverter.isBluetoothReady) {
187         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Device not found" message:@"No Bluetooth device detected. Ensure Bluetooth is on and the Mindwave headset is paired" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
188         [alert show];
189      } else if ([signalConverter startProcessing]) {
190         connectButton.title = @"Disconnect";
191      } else {
192         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failed to connect" message:@"Check the device is correctly paired on Bluetooth" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
193         [alert show];
194      }
195      warned = YES;
196   }
197}
198
199- (IBAction) testButtonPressed:(id) sender {
200   
201   //   NSLog(@"Available fonts: %@", [UIFont familyNames]);
202   
203//   StatisticsViewController *statisticsViewController=[[StatisticsViewController alloc] init];
204//   [statisticsViewController.graphBottom reloadData];
205   
206   [signalConverter isAudioJackPlugged];
207   if (signalConverter.running) {
208      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Signal Processing Active" message:@"Please press the Disconnect button before sending a Test signal" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
209      [alert show];
210   } else {
211      if (signalConverter.testing) {
212         testButton.title = @"Test";
213         [signalConverter stopTestSound];
214      } else {
215         testButton.title = @"Stop";
216         [signalConverter playTestSound];
217      }
218   }
219}
220
221- (void) updateScores
222{
223   
224   /**
225    * Score points based on target slider levels
226    * If you pass your goal with either Attention or Meditation
227    * the higher target of the two will counts as points per second.
228    *
229    * Minimum threshold for points is set as "minimumScoreTarget"
230    *
231    * For example, assume minimumScoreTarget is 40%.
232    * If your target Attention is 60% and you go past to reach 80%
233    * you will receive 20 points per second (60-40). If your
234    * target is 80% and you reach 80% you will receive 40
235    * points per second (80-40).
236    *
237    * You can set both Attention and Meditation targets at the
238    * same time. Reaching either will fly the helicopter but you
239    * will only receive points for the higher-scoring target of
240    * the two.
241    *
242    */
243   
244   int eegAttentionScore = 0;
245   int eegAttention = self.attention.progress * 100;
246   int eegAttentionTarget = self.attentionThreshold.value * 100;
247   
248   int eegMeditationScore = 0;
249   int eegMeditation = self.meditation.progress * 100;
250   int eegMeditationTarget = self.meditationThreshold.value * 100;
251   
252   
253   if ((eegAttention >= eegAttentionTarget) &&
254       (eegAttentionTarget > minimumScoreTarget))
255      eegAttentionScore = eegAttentionTarget - minimumScoreTarget;
256   
257   if ((eegMeditation >= eegMeditationTarget) &&
258       (eegMeditationTarget > minimumScoreTarget))
259      eegMeditationScore = eegMeditationTarget - minimumScoreTarget;
260   
261   if (eegAttentionScore > eegMeditationScore)
262      scoreCurrent = scoreCurrent + eegAttentionScore;
263   else
264      scoreCurrent = scoreCurrent + eegMeditationScore;
265   
266   
267   // High score
268   if (scoreCurrent > scoreHigh) {
269      scoreHigh = scoreCurrent;
270   }
271   
272   // Reset score
273   if (power.progress == 0)
274      [self resetCurrentScore];
275   
276   
277   // Catch anyone gaming the system with one slider
278   // below the minimum threshold and the other over.
279   // For example, setting Meditation to 1% will keep helicopter
280   // activated even if Attention is below target
281   if ((eegAttention < eegAttentionTarget) && (eegMeditation < minimumScoreTarget))
282      [self resetCurrentScore];
283   
284   if ((eegMeditation < eegMeditationTarget) && (eegAttention < minimumScoreTarget))
285      [self resetCurrentScore];
286   
287   if ((eegAttention < minimumScoreTarget) && (eegMeditation < minimumScoreTarget))
288      [self resetCurrentScore];
289   
290   
291   [self displayScore];
292   
293}
294
295- (void) displayScore
296{
297   
298   NSString* newScore = [NSString stringWithFormat:@"Scores      Current: %i    Last: %i    High: %i", (int)scoreCurrent, (int)scoreLast, (int)scoreHigh];
299   
300   if (newScore.length >= 50)
301      newScore = [NSString stringWithFormat:@"Scores  Current: %i  Last: %i  High: %i", (int)scoreCurrent, (int)scoreLast, (int)scoreHigh];
302
303   if (newScore.length >= 50)
304      newScore = [NSString stringWithFormat:@"Scores Current: %i Last: %i High: %i", (int)scoreCurrent, (int)scoreLast, (int)scoreHigh];
305
306   self.scoresDisplay.text = newScore;
307}
308
309- (void) resetCurrentScore
310{
311   if (scoreCurrent > 0)
312      scoreLast = scoreCurrent;
313   
314   scoreCurrent = 0;
315   
316}
317
318@end
Note: See TracBrowser for help on using the repository browser.