1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #import <Foundation/Foundation.h>
18 
19 #import "MIDIClient.h"
20 #import "MIDIMessage.h"
21 
22 extern NSString * const WALTClientErrorDomain;
23 
24 /** A reasonable timeout to use when reading from the WALT. */
25 extern const NSTimeInterval kWALTReadTimeout;
26 
27 typedef NS_ENUM(MIDIByte, WALTCommand) {
28   WALTDelayedPingCommand     = 'D',  // Ping with a delay
29   WALTResetCommand           = 'F',  // Reset all vars
30   WALTSendSyncCommand        = 'I',  // Send some digits for clock sync
31   WALTPingCommand            = 'P',  // Ping with a single byte
32   WALTVersionCommand         = 'V',  // Determine WALT's firmware version
33   WALTReadoutSyncCommand     = 'R',  // Read out sync times
34   WALTGShockCommand          = 'G',  // Send last shock time and watch for another
35   WALTTimeCommand            = 'T',  // Current time
36   WALTZeroSyncCommand        = 'Z',  // Initial zero
37   WALTScreenOnCommand        = 'C',  // Send a message on screen color change
38   WALTScreenOffCommand       = 'c',
39   WALTSendLastScreenCommand  = 'E',  // Send info about last screen color change
40   WALTBrightnessCurveCommand = 'U',  // Probe screen for brightness vs time curve
41   WALTLaserOnCommand         = 'L',  // Send messages on state change of the laser
42   WALTLaserOffCommand        = 'l',
43   WALTSendLastLaserCommand   = 'J',
44   WALTAudioCommand           = 'A',  // Start watching for signal on audio out line
45   WALTBeepCommand            = 'B',  // Generate a tone into the mic and send timestamp
46   WALTBeepStopCommand        = 'S',  // Stop generating tone
47   WALTMIDICommand            = 'M',  // Start listening for a MIDI message
48   WALTNoteCommand            = 'N',  // Generate a MIDI NoteOn message
49 };
50 
51 typedef struct {
52   char tag;
53   NSTimeInterval t;
54   int value;
55   unsigned int count;
56 } WALTTrigger;
57 
58 /**
59  * A client for a WALT device.
60  *
61  * The client will automatically try to connect to any available WALT device, and monitor the system
62  * for device connections/disconnections. Users should observe the "connected" key to be notified of
63  * connection changes.
64  *
65  * Most commands produce a corresponding response from the WALT. The -sendCommand:error: method
66  * should be used to send the command, and -readResponse used to collect the response.
67  */
68 @interface WALTClient : NSObject <MIDIClientDelegate>
69 @property (readonly, nonatomic, getter=isConnected) BOOL connected;
70 
71 /**
72  * Returns the base time of the WALT device.
73  *
74  * The time value is an adjusted version of -currentTime.
75  */
76 @property (readonly, nonatomic) NSTimeInterval baseTime;
77 
78 /** Returns the number of seconds the system has been awake since it was last restarted. */
79 @property (readonly, nonatomic) NSTimeInterval currentTime;
80 
81 /** Initialises the client and attempts to connect to any available WALT device. */
82 - (instancetype)initWithError:(NSError **)error;
83 
84 /** Sends a command to the WALT. */
85 - (BOOL)sendCommand:(WALTCommand)command error:(NSError **)error;
86 
87 /** Reads a response from the WALT, blocking up to timeout until one becomes available. */
88 - (NSData *)readResponseWithTimeout:(NSTimeInterval)timeout;
89 
90 /**
91  * Reads a trigger response from the WALT.
92  *
93  * If an error occurs, the trigger's tag will be '\0'.
94  */
95 - (WALTTrigger)readTriggerWithTimeout:(NSTimeInterval)timeout;
96 
97 /** Returns YES if the response data contains a valid acknowledgement for a command. */
98 - (BOOL)checkResponse:(NSData *)response forCommand:(WALTCommand)command;
99 
100 /** Forces a complete clock synchronisation with the WALT. */
101 - (BOOL)syncClocksWithError:(NSError **)error;
102 
103 /** Refreshes the min/max error synchronisation bounds. */
104 - (BOOL)updateSyncBoundsWithError:(NSError **)error;
105 
106 @property (readonly, nonatomic) int64_t minError;
107 @property (readonly, nonatomic) int64_t maxError;
108 
109 /**
110  * Confirms the connection with the WALT (by setting -isConnected).
111  *
112  * Note that this method will only return NO if there is an error in the connection process. The
113  * absence of a device is not such an error.
114  */
115 - (BOOL)checkConnectionWithError:(NSError **)error;
116 
117 /** Returns the time of the last shock detected by the WALT. */
118 - (NSTimeInterval)lastShockTimeWithError:(NSError **)error;
119 @end
120