1'name iPod Remote Interface 2'author Daniel M. Story 3'package iPod Interface 4'copyright 2007 5'version 1.0 6 7Imports System 8Imports System.IO 9Imports System.IO.Ports 10 11Public 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 193End Class