source: orbit/iOS/Orbit/Orbit/ViewController.m @ 66477ef

RawEEGRaw_EEG_PlotServoTab_Interfacepyramid
Last change on this file since 66477ef was 66477ef, checked in by Jonathon Horsman <jonathon@…>, 7 years ago

Initial checkin of working iOS app

  • Property mode set to 100644
File size: 7.6 KB
Line 
1//
2//  ViewController.m
3//  Orbit
4//
5//  Created by Jonathon Horsman on 17/12/2012.
6//  Copyright (c) 2012 Jonathon Horsman. All rights reserved.
7//
8
9#import "ViewController.h"
10#import <AVFoundation/AVFoundation.h>
11
12#define AUDIO_FILE_NAME @"throttle_hover_android_common.wav"
13#define POOR_SIGNAL_KEY @"poorSignal"
14#define ATTENTION_KEY @"eSenseAttention"
15#define MEDITATION_KEY @"eSenseMeditation"
16
17@implementation ViewController {
18    // these 2 arrays hold the values of the thrust which should be applied to the helicopter
19    // (by way of volume level through the headphones) at each level of attention and meditation.
20    // this could be calculated on the fly, but because it happens ~20 times per second, the
21    // better option is to store all the values in arrays, and recalculate when the sliders are changed.
22    float attentionPower[101];
23    float meditationPower[101];
24   
25    int currentAttentionLevel, currentMeditationLevel; // the latest readings from the headset
26    BOOL demoRunning;
27}
28
29@synthesize log, attention, meditation, signal, power, attentionThreshold, meditationThreshold, demoButton;
30
31- (void)viewDidLoad
32{
33    [super viewDidLoad];
34    [self prepareAudio];
35    [self.attentionThreshold addTarget:self action:@selector(calculatePowerValues) forControlEvents:UIControlEventValueChanged];
36    [self.meditationThreshold addTarget:self action:@selector(calculatePowerValues) forControlEvents:UIControlEventValueChanged];
37    [self calculatePowerValues];
38}
39
40- (void)didReceiveMemoryWarning
41{
42    [super didReceiveMemoryWarning];
43    // Dispose of any resources that can be recreated.
44    [self stopDemo];
45}
46
47- (void) appForegrounded
48{
49    if ([[TGAccessoryManager sharedTGAccessoryManager] accessory] != nil) {
50        [[TGAccessoryManager sharedTGAccessoryManager] startStream];
51    }
52    [self resetViews];
53}
54
55- (void) resetViews
56{
57    [self showSignalStrength:[NSNumber numberWithInt:200]];
58    [self setAttentionLevel:[NSNumber numberWithInt:0]];
59    [self setMeditationLevel:[NSNumber numberWithInt:0]];
60    [self showPowerLevel];
61    self.log.text = @"";
62}
63
64- (void) appClosed
65{
66    [self stopDemo];
67    if ([[TGAccessoryManager sharedTGAccessoryManager] connected]) {
68        [[TGAccessoryManager sharedTGAccessoryManager] stopStream];
69    }
70}
71
72- (void) prepareAudio
73{
74    NSURL *audioFilePath = [[NSBundle mainBundle] URLForResource:AUDIO_FILE_NAME withExtension:nil];
75
76    NSError *error;
77    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFilePath error:&error];
78    if (!audioPlayer) {
79        NSLog(@"Failed to initialize audio player: %@", [error debugDescription]);
80    } else {
81        [audioPlayer prepareToPlay];
82    }
83}
84
85- (void) logMessage:(NSString *) str
86{
87    log.text = [[NSString alloc] initWithFormat:@"%@\n%@", str, log.text];
88}
89
90#pragma mark - TGAccessoryDelegate methods
91
92- (void)dataReceived:(NSDictionary *)data {
93    [self performSelectorOnMainThread:@selector(updatedSignalReceived:)
94                           withObject:data
95                        waitUntilDone:NO];
96}
97
98- (void) updatedSignalReceived:(NSDictionary *) data
99{
100    [self showSignalStrength:(NSNumber *)[data valueForKey:POOR_SIGNAL_KEY]];
101    [self setAttentionLevel:(NSNumber *)[data valueForKey:ATTENTION_KEY]];
102    [self setMeditationLevel:(NSNumber *)[data valueForKey:MEDITATION_KEY]];
103    [self showPowerLevel];
104    [self playAudio];
105}
106
107- (void)accessoryDidConnect:(EAAccessory *)accessory {
108    [self logMessage:[NSString stringWithFormat:@"%@ was connected to this device.", [accessory name]]];
109}
110
111- (void)accessoryDidDisconnect {
112    [self logMessage:@"An accessory was disconnected."];
113}
114
115#pragma mark - display calculation and update methods
116
117// when the user adjusts one of the 2 threshold sliders we recalculate the power values at each of the 101 possible levels
118- (void) calculatePowerValues
119{
120    float threshold = self.attentionThreshold.value; // this is the user-selected minimum threshold - between 0 and 1
121    for (int i = 0; i < 101; i++) {
122        attentionPower[i] = [self calculatePowerAt:(float)i/100 withThreshold:threshold];
123    }
124    threshold = self.meditationThreshold.value; // this is the user-selected minimum threshold - between 0 and 1
125    for (int i = 0; i < 101; i++) {
126        meditationPower[i] = [self calculatePowerAt:(float)i/100 withThreshold:threshold];
127    }
128}
129
130// Convert a value (attention or meditation) into the corresponding power output (which is the volume level)
131// given the threshold is set at specified value.
132// The threshold is the value set by the user as the minimum value (attention or meditation) to be reached
133// before the helicopter is given the signal to fly.
134// If the value if below the threshold, the value will be zero (threshold not yet met).
135// Otherwise the returned power value will be between 0 and 1.
136- (float) calculatePowerAt:(float)value withThreshold:(float)threshold
137{
138    if (value < threshold) { // threshold not met
139        return 0;
140    }
141    // e.g. if the threshold is 0.55 and the current value is 0.7:
142    // there is 0.45 remaining of the threshold slider, and the value is 0.15 past the threshold (0.7 - 0.55), which is 0.33 (0.15 / 0.45)
143    return (value - threshold) / (1 - threshold);
144}
145
146- (void) showSignalStrength:(NSNumber *) value
147{
148    if (value != nil) {
149        self.signal.progress = (200 - [value intValue]) / 100;
150    }
151}
152
153- (void) setAttentionLevel:(NSNumber *) value
154{
155    if (value != nil) {
156        currentAttentionLevel = [value intValue];
157        self.attention.progress = (float)currentAttentionLevel / 100;
158    }   
159}
160
161- (void) setMeditationLevel:(NSNumber *) value
162{
163    if (value != nil) {
164        currentMeditationLevel = [value intValue];
165        self.meditation.progress = (float)currentMeditationLevel / 100;
166    }
167}
168
169// updates the power output progress bar
170- (void) showPowerLevel
171{
172    self.power.progress = [self currentPowerLevel];
173}
174
175// calculate the total power level to output through the headphones, a value between zero and 1.
176// this is the attention signal level and meditation signal level added together
177- (float) currentPowerLevel
178{
179    float powerLevel = attentionPower[currentAttentionLevel] + meditationPower[currentMeditationLevel];
180    if (powerLevel > 1) {
181        return 1.0;
182    }
183    return powerLevel;
184}
185
186- (void) playAudio
187{
188    audioPlayer.volume = [self currentPowerLevel];
189    [audioPlayer play];
190}
191
192#pragma mark - button press events
193
194// allow simulation of values being generated by a headset and being received on the phone
195- (IBAction) demoButtonPressed:(id) sender
196{
197    if (demoRunning) {
198        [self stopDemo];
199    } else {
200        [self startDemo];
201    }
202}
203
204- (void) stopDemo
205{
206    demoRunning = NO;
207    [demoButton setTitle:@"Demo" forState:UIControlStateNormal];
208    if (audioPlayer != NULL && [audioPlayer isPlaying]) {
209        [audioPlayer stop];
210    }
211}
212
213- (void) startDemo
214{
215    demoRunning = YES;
216    [self logMessage:@"Running demo"];
217    [demoButton setTitle:@"Stop" forState:UIControlStateNormal];
218    [self performSelectorInBackground:@selector(generateDemoData) withObject:nil];
219}
220
221// generate some data in a background thread and invoke the methods the headset would invoke with the data
222// for testing without a headset.
223- (void) generateDemoData
224{
225    for (int i = 0; i < 100; i++) {
226        if (!demoRunning) {
227            break; // break out if we stop the demo
228        }
229        NSDictionary *values = [NSDictionary dictionaryWithObjectsAndKeys:
230                                [NSNumber numberWithInt:i], ATTENTION_KEY,
231                                [NSNumber numberWithInt:i], MEDITATION_KEY,
232                                [NSNumber numberWithInt:0], POOR_SIGNAL_KEY,
233                                nil];
234        [self dataReceived:values];
235        [NSThread sleepForTimeInterval:1];
236    }
237}
238@end
Note: See TracBrowser for help on using the repository browser.