iPodRemote Class
Daniel Story
Daniel Story
1'name iPod Remote Interface 2
'author Daniel M. Story 3
'package iPod Interface 4
'copyright 2007 5
'version 1.0 6
7
Imports System 8
Imports System.IO 9
Imports System.IO.Ports 10
11
Public Class iPodRemote 12
Private WithEvents CommPort As SerialPort 13
14
Public Event PlayButton_Down() 15
Public Event PlayButton_Up() 16
Public Event StopButton_Down() 17
Public Event StopButton_Up() 18
Public Event SkipForwardButton_Down() 19
Public Event SkipForwardButton_Up() 20
Public Event SkipBackwardButton_Down() 21
Public Event SkipBackwardButton_Up() 22
Public Event VolumeUpButton_Down() 23
Public Event VolumeUpButton_Up() 24
Public Event VolumeDownButton_Down() 25
Public Event VolumeDownButton_Up() 26
27
Private LastButton As Short 28
Private buffer As ArrayList 29
30
Public Sub New() 31
buffer = New ArrayList 32
CommPort = New SerialPort() 33
CommPort.BaudRate = 19200 34
End Sub 35
36
Public Property Port() As String 37
Get 38
Return CommPort.PortName 39
End Get 40
Set(ByVal value As String) 41
CommPort.PortName = value 42
End Set 43
End Property 44
45
Public Sub Open() 46
CommPort.Open() 47
End Sub 48
49
Public Sub Close() 50
CommPort.Close() 51
End Sub 52
53
Private Sub CommPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles CommPort.DataReceived 54
Dim i As Integer 55
Dim BufferData() As Byte 56
ReDim BufferData(CommPort.BytesToRead - 1) 'redefine data size to fit entire response 57
If CommPort.Read(BufferData, 0, BufferData.Length) Then 58
For i = 0 To (BufferData.Length - 1) 59
buffer.Add(CByte(BufferData(i))) 60
Next i 61
ParseBuffer() 62
End If 63
End Sub 64
65
Private Sub ParseBuffer() 66
'All thanks to: http://ipodlinux.org/Apple_Accessory_Protocol 67
68
Dim Header As Short '= 0xff55 (aka 22015) 69
Dim Length As Byte '= len(mode + command + parameters) 70
Dim Mode As Byte '= command category/mode 71
Dim Command As Short '= command/function 72
Dim Parameter() As Byte '= optional parameter 73
Dim Checksum As Byte '= 0x100 - ( (sum of length, mode, command, and parameters) & 0xFF) 74
75
Dim ParameterLength As Byte 76
ReDim Parameter(0) 77
78
Dim DataSum As Integer '= the datasum to get the checksum 79
Dim MyChecksum As Byte '= the checksum I calculated 80
Dim i As Integer '= for looping 81
Dim offset As Integer 82
83
Do 84
Header = BitConverter.ToInt16(New Byte() {Convert.ToByte(buffer.Item(offset)), Convert.ToByte(buffer.Item(offset + 1))}, 0) 'convert the header to a short (16bit) 85
If Header = 22015 Then 'is the correct header? 86
If (buffer.Count - offset) < 7 Then Exit Do 'safety check 87
Length = Convert.ToByte(buffer.Item(offset + 2)) 88
Mode = Convert.ToByte(buffer.Item(offset + 3)) 89
Command = BitConverter.ToInt16(New Byte() {Convert.ToByte(buffer.Item(offset + 4)), Convert.ToByte(buffer.Item(offset + 5))}, 0) 90
ParameterLength = Length - 3 91
If (buffer.Count - offset) < 7 + ParameterLength Then Exit Do 'safety check 92
If ParameterLength > 0 Then 'if have parameters (shouldn't matter since the simple remote never sends it) 93
ReDim Parameter(ParameterLength - 1) 94
For i = 0 To (ParameterLength - 1) 95
Parameter(i) = Convert.ToByte(buffer.Item(offset + (i + 5))) 96
Next i 97
End If 98
Checksum = Convert.ToByte(buffer.Item(offset + 6)) 99
'all that stuff just separates the data byte array into its categories 100
101
DataSum = 0 102
For i = 2 To Length + 2 103
DataSum += Convert.ToByte(buffer.Item(offset + i)) 104
Next i 105
' get the data sum (for calc-ing the sum [up next]) 106
107
MyChecksum = &H100 - ((DataSum) And &HFF) 108
'calc the checksum of what was received 109
If MyChecksum = Checksum Then 'check it to see if anythign failed. 110
'Debug.Print(Command.ToString) 111
Select Case Command 112
Case 0 113
'released 114
Raise_LastButton() 115
Case 256 116
'play 117
If LastButton <> 0 Then 118
If LastButton <> Command Then Raise_LastButton() 119
End If 120
If LastButton <> Command Then RaiseEvent PlayButton_Down() 121
Case 512 122
'vol + 123
If LastButton <> 0 Then 124
If LastButton <> Command Then Raise_LastButton() 125
End If 126
If LastButton <> Command Then RaiseEvent VolumeUpButton_Down() 127
Case 1024 128
'vol - 129
If LastButton <> 0 Then 130
If LastButton <> Command Then Raise_LastButton() 131
End If 132
If LastButton <> Command Then RaiseEvent VolumeDownButton_Down() 133
Case 2048 134
'skip > 135
If LastButton <> 0 Then 136
If LastButton <> Command Then Raise_LastButton() 137
End If 138
If LastButton <> Command Then RaiseEvent SkipForwardButton_Down() 139
Case 4096 140
'skip < 141
If LastButton <> 0 Then 142
If LastButton <> Command Then Raise_LastButton() 143
End If 144
If LastButton <> Command Then RaiseEvent SkipBackwardButton_Down() 145
Case -32768 146
'stop 147
If LastButton <> 0 Then 148
If LastButton <> Command Then Raise_LastButton() 149
End If 150
If LastButton <> Command Then RaiseEvent StopButton_Down() 151
End Select 152
LastButton = Command 153
End If 154
For i = 0 To (Length + 2) 155
buffer.RemoveAt(offset) 156
Next i 157
Else 158
offset += 1 159
End If 160
Loop While (offset < (buffer.Count - 1)) 161
End Sub 162
163
Private Sub Raise_LastButton() 164
Select Case LastButton 165
Case 256 166
'play 167
RaiseEvent PlayButton_Up() 168
Case 512 169
'vol + 170
RaiseEvent VolumeUpButton_Up() 171
Case 1024 172
'vol - 173
RaiseEvent VolumeDownButton_Up() 174
Case 2048 175
'skip > 176
RaiseEvent SkipForwardButton_Up() 177
Case 4096 178
'skip < 179
RaiseEvent SkipBackwardButton_Up() 180
Case -32768 181
'stop (my remote doesn't have this button, so couldn't test) 182
RaiseEvent StopButton_Up() 183
End Select 184
LastButton = 0 185
End Sub 186
187
Protected Overrides Sub Finalize() 188
MyBase.Finalize() 189
If Not CommPort Is Nothing Then If CommPort.IsOpen Then CommPort.Close() 190
CommPort.Dispose() 191
CommPort = Nothing 192
End Sub 193
End Class




