'name iPod Remote Interface 'author Daniel M. Story 'package iPod Interface 'copyright 2007 'version 1.0 Imports System Imports System.IO Imports System.IO.Ports Public Class iPodRemote Private WithEvents CommPort As SerialPort Public Event PlayButton_Down() Public Event PlayButton_Up() Public Event StopButton_Down() Public Event StopButton_Up() Public Event SkipForwardButton_Down() Public Event SkipForwardButton_Up() Public Event SkipBackwardButton_Down() Public Event SkipBackwardButton_Up() Public Event VolumeUpButton_Down() Public Event VolumeUpButton_Up() Public Event VolumeDownButton_Down() Public Event VolumeDownButton_Up() Private LastButton As Short Private buffer As ArrayList Public Sub New() buffer = New ArrayList CommPort = New SerialPort() CommPort.BaudRate = 19200 End Sub Public Property Port() As String Get Return CommPort.PortName End Get Set(ByVal value As String) CommPort.PortName = value End Set End Property Public Sub Open() CommPort.Open() End Sub Public Sub Close() CommPort.Close() End Sub Private Sub CommPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles CommPort.DataReceived Dim i As Integer Dim BufferData() As Byte ReDim BufferData(CommPort.BytesToRead - 1) 'redefine data size to fit entire response If CommPort.Read(BufferData, 0, BufferData.Length) Then For i = 0 To (BufferData.Length - 1) buffer.Add(CByte(BufferData(i))) Next i ParseBuffer() End If End Sub Private Sub ParseBuffer() 'All thanks to: http://ipodlinux.org/Apple_Accessory_Protocol Dim Header As Short '= 0xff55 (aka 22015) Dim Length As Byte '= len(mode + command + parameters) Dim Mode As Byte '= command category/mode Dim Command As Short '= command/function Dim Parameter() As Byte '= optional parameter Dim Checksum As Byte '= 0x100 - ( (sum of length, mode, command, and parameters) & 0xFF) Dim ParameterLength As Byte ReDim Parameter(0) Dim DataSum As Integer '= the datasum to get the checksum Dim MyChecksum As Byte '= the checksum I calculated Dim i As Integer '= for looping Dim offset As Integer Do Header = BitConverter.ToInt16(New Byte() {Convert.ToByte(buffer.Item(offset)), Convert.ToByte(buffer.Item(offset + 1))}, 0) 'convert the header to a short (16bit) If Header = 22015 Then 'is the correct header? If (buffer.Count - offset) < 7 Then Exit Do 'safety check Length = Convert.ToByte(buffer.Item(offset + 2)) Mode = Convert.ToByte(buffer.Item(offset + 3)) Command = BitConverter.ToInt16(New Byte() {Convert.ToByte(buffer.Item(offset + 4)), Convert.ToByte(buffer.Item(offset + 5))}, 0) ParameterLength = Length - 3 If (buffer.Count - offset) < 7 + ParameterLength Then Exit Do 'safety check If ParameterLength > 0 Then 'if have parameters (shouldn't matter since the simple remote never sends it) ReDim Parameter(ParameterLength - 1) For i = 0 To (ParameterLength - 1) Parameter(i) = Convert.ToByte(buffer.Item(offset + (i + 5))) Next i End If Checksum = Convert.ToByte(buffer.Item(offset + 6)) 'all that stuff just separates the data byte array into its categories DataSum = 0 For i = 2 To Length + 2 DataSum += Convert.ToByte(buffer.Item(offset + i)) Next i ' get the data sum (for calc-ing the sum [up next]) MyChecksum = &H100 - ((DataSum) And &HFF) 'calc the checksum of what was received If MyChecksum = Checksum Then 'check it to see if anythign failed. 'Debug.Print(Command.ToString) Select Case Command Case 0 'released Raise_LastButton() Case 256 'play If LastButton <> 0 Then If LastButton <> Command Then Raise_LastButton() End If If LastButton <> Command Then RaiseEvent PlayButton_Down() Case 512 'vol + If LastButton <> 0 Then If LastButton <> Command Then Raise_LastButton() End If If LastButton <> Command Then RaiseEvent VolumeUpButton_Down() Case 1024 'vol - If LastButton <> 0 Then If LastButton <> Command Then Raise_LastButton() End If If LastButton <> Command Then RaiseEvent VolumeDownButton_Down() Case 2048 'skip > If LastButton <> 0 Then If LastButton <> Command Then Raise_LastButton() End If If LastButton <> Command Then RaiseEvent SkipForwardButton_Down() Case 4096 'skip < If LastButton <> 0 Then If LastButton <> Command Then Raise_LastButton() End If If LastButton <> Command Then RaiseEvent SkipBackwardButton_Down() Case -32768 'stop If LastButton <> 0 Then If LastButton <> Command Then Raise_LastButton() End If If LastButton <> Command Then RaiseEvent StopButton_Down() End Select LastButton = Command End If For i = 0 To (Length + 2) buffer.RemoveAt(offset) Next i Else offset += 1 End If Loop While (offset < (buffer.Count - 1)) End Sub Private Sub Raise_LastButton() Select Case LastButton Case 256 'play RaiseEvent PlayButton_Up() Case 512 'vol + RaiseEvent VolumeUpButton_Up() Case 1024 'vol - RaiseEvent VolumeDownButton_Up() Case 2048 'skip > RaiseEvent SkipForwardButton_Up() Case 4096 'skip < RaiseEvent SkipBackwardButton_Up() Case -32768 'stop (my remote doesn't have this button, so couldn't test) RaiseEvent StopButton_Up() End Select LastButton = 0 End Sub Protected Overrides Sub Finalize() MyBase.Finalize() If Not CommPort Is Nothing Then If CommPort.IsOpen Then CommPort.Close() CommPort.Dispose() CommPort = Nothing End Sub End Class