Difference between revisions of "Ethernet multi-function Interface"


From SamyGO
Jump to: navigation, search
m (How to use it)
m (Teensy(++ 2.0) sketch for accessing I2C interface)
 
(14 intermediate revisions by 3 users not shown)
Line 7: Line 7:
 
* Send IR codes to your TV, PVR or BD, with an URL in your browser
 
* Send IR codes to your TV, PVR or BD, with an URL in your browser
 
* Use telnet to have the Serial Console on your PC or smartphone
 
* Use telnet to have the Serial Console on your PC or smartphone
* Read your config eeprom
+
* Read your SoC config eeprom
 +
* Read/write micom config eeprom
 +
* See Arduino as a Samsung device in the Samsung Remote App (can be used to power on the device !)
  
  
[[File:Arduino interface.jpg|335px]]
+
[[File:Arduino interface.jpg|335px]]             [[File:EthernetInterface-SamsungRemote.png|335px]]
 
 
  
 
== Bill of materials ==
 
== Bill of materials ==
Line 22: Line 23:
  
 
== How to use it ==
 
== How to use it ==
* Upload the following [http://wiki.samygo.tv/index.php5/Ethernet_multi-function_Interface#Arduino_sketch sketch] into your Arduino
+
* Upload the following '''[[#Arduino_sketch | sketch]]''' into your Arduino
 
* Connect the IR or RED led with its resistor on pin 8 on the Arduino
 
* Connect the IR or RED led with its resistor on pin 8 on the Arduino
 
* Connect power and network
 
* Connect power and network
Line 28: Line 29:
 
* Use your browser to send an URL to the board (see format below)
 
* Use your browser to send an URL to the board (see format below)
 
* If you want to use telnet to connect to the Serial Console :
 
* If you want to use telnet to connect to the Serial Console :
  * Connect your Serial Console signals TX&RX to the Arduino board pins 0&1  (with 100 ohms resistors)
+
  * Connect your Serial Console signals TX&RX to the Arduino board pins 0&1  ({{red|with 100 ohms resistors}})
 
  * Use Putty with options 'Local Echo' and 'Local line editing' forced to OFF
 
  * Use Putty with options 'Local Echo' and 'Local line editing' forced to OFF
 
* If you want to read your config eeprom :
 
* If you want to read your config eeprom :
  * Connect the eeprom SDA&SCK signals to the Arduino board pins A4/A5 (with a 100 ohms resistors)
+
  * Connect the eeprom SDA&SCK signals to the Arduino board pins A4/A5 ({{red|with 100 ohms resistors}})
 
  * Connect the eeprom GND to 0v
 
  * Connect the eeprom GND to 0v
 +
* If you want to use the Samsung Remote feature :
 +
* Compile with SAMSUNGREMOTE defined
 +
* The program only handles BD_KEY_POWER; if you want aditional keys, it's easy to add them
  
 
== URL format to send IR codes ==
 
== URL format to send IR codes ==
Line 67: Line 71:
  
 
== URL format to read config Eeprom ==
 
== URL format to read config Eeprom ==
The format is http://IP/read?read?format=F&device=D&addr=A&size=S
+
The format is http://IP/read?format=F&device=D&addr=A&size=S&width=W
  
 
* IP is the Arduino board IP address
 
* IP is the Arduino board IP address
Line 74: Line 78:
 
* A is the starting address for reading (0 by default)
 
* A is the starting address for reading (0 by default)
 
* S is the number of bytes to read (default=256)
 
* S is the number of bytes to read (default=256)
 +
* W is the address bus width (8 bits for Micom eeprom, 16 bits for SoC eeprom); default is 16
  
  
Line 82: Line 87:
  
 
To download its whole config :
 
To download its whole config :
* http://IP/ir.htm?read?format=1&size=65536
+
* http://IP/read?format=1&size=65536
 
or :
 
or :
* http://IP/ir.htm?read?format=1&device=80&size=65536&addr=0
+
* http://IP/read?format=1&device=80&size=65536&addr=0
  
  
Line 91: Line 96:
 
[[File:Arduino_I2C_Eeprom.jpg|335px]]
 
[[File:Arduino_I2C_Eeprom.jpg|335px]]
  
 +
== URL format to write config Eeprom ==
 +
The format is http://IP/write?device=D&addr=A&data=X&width=W
 +
 +
* IP is the Arduino board IP address
 +
* D is the Eeprom device identification (80 by default)
 +
* A is the starting address for writing (0 by default)
 +
* X is the data byte to write
 +
* W is the address bus width (8 bits for Micom eeprom, 16 bits for SoC eeprom); default is 16
 +
 +
On this version, it is only possible to write one byte at once...
 +
 +
For example:
 +
http://IP/write?addr=e0&data=55&width=16 will write 0x55 at address 0xe0
  
 
== IR frames format ==  
 
== IR frames format ==  
Line 105: Line 123:
 
A frame for BD :
 
A frame for BD :
  
[[File:BD IR Frame Format.jpg|100px‎]]
+
[[File:BD_IR_Frame_Format.png‎]]
  
 +
== Arduino sketch ==
  
== Arduino sketch ==
+
This sketch has been compiled with Arduino 1.0.3 ([http://arduino.cc/en/Main/Software Download here])
  
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
   // Samsung multi-function ethernet interface  
+
   // Samsung multi-functions ethernet interface  
 
   //  - Send IR frame with http get requests
 
   //  - Send IR frame with http get requests
 
   //  - Debug console on telnet
 
   //  - Debug console on telnet
Line 120: Line 139:
 
   //    Added optionnal 'crc' url parameter for testing IR (allow to force CRC)
 
   //    Added optionnal 'crc' url parameter for testing IR (allow to force CRC)
 
   //    Added I2C interface to read/write config eeprom
 
   //    Added I2C interface to read/write config eeprom
 +
  // 09-01-2013 / v1.1.1 / oga83
 +
  //    Fixed compilation issue with Arduino 1.0.3 and typo in wiki
 +
  // 11-01-2013 / v1.1.2 / oga83
 +
  //    Modified ReadEeprom and WriteEeprom for 1-byte address eeproms
 +
  // 11-01-2013 / v1.2 / oga83
 +
  //    Added Samsung Remote protocol (Arduino seen as a samsung device)
 
   //----------------------------------------------------------------------
 
   //----------------------------------------------------------------------
 
    
 
    
 
   #include <SPI.h>
 
   #include <SPI.h>
 
   #include <Ethernet.h>
 
   #include <Ethernet.h>
 +
  #include <EthernetUdp.h>
 
   #include <Wire.h>
 
   #include <Wire.h>
 
    
 
    
 
   #define IRPIN      8    // IR led is connected on pin 8
 
   #define IRPIN      8    // IR led is connected on pin 8
 
   #define LEDPIN    9    // Onboard led - blink at 2 Hz
 
   #define LEDPIN    9    // Onboard led - blink at 2 Hz
  // Debug console TX signal connected on 0
+
                          // Debug console TX signal connected on 0
  // Debug console RX signal connected on 1
+
                          // Debug console RX signal connected on 1
  // I2C Eeprom : SDA connected on A4
+
                          // I2C Eeprom : SDA connected on A4
  // I2C Eeprom : SCK connected on A5
+
                          // I2C Eeprom : SCK connected on A5
 
    
 
    
 
    
 
    
Line 140: Line 166:
 
   EthernetServer TelnetServer(23); // Telnet is used for Serial Console
 
   EthernetServer TelnetServer(23); // Telnet is used for Serial Console
 
    
 
    
 +
  #define SAMSUNGREMOTE            // if defined, Arduino will be seen as a Samsung device
 +
  #ifdef SAMSUNGREMOTE
 +
  EthernetServer SamsungRemote(55000); // Emulates a Samsung device
 +
  EthernetUDP SamsungSSDP;  // Handles Samsung device discovery
 +
  #endif
 
    
 
    
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
Line 148: Line 179:
 
   unsigned int HexToULong(char *s)
 
   unsigned int HexToULong(char *s)
 
   {
 
   {
  unsigned long u=0;
+
    unsigned long u=0;
  while (*s)
+
    while (*s)
  {
+
    {
  char c=*s++;
+
      char c=*s++;
  // Convert to uppercase
+
      // Convert to uppercase
  if (c>='a') c&=0xdf;
+
      if (c>='a') c&=0xdf;
  // Exit if not hex digit
+
      // Exit if not hex digit
  if ((c<'0' || c>'9') && (c<'A' || c>'F')) break;
+
      if ((c<'0' || c>'9') && (c<'A' || c>'F')) break;
  // Convert digit
+
      // Convert digit
  u<<=4;
+
      u<<=4;
  u|=c-((c>'9') ? 'A'-0xa:'0');
+
      u|=c-((c>'9') ? 'A'-0xa:'0');
  }
+
    }
  return u;
+
    return u;
 +
  }
 +
 
 +
  #ifdef SAMSUNGREMOTE
 +
  // Base64 conversion
 +
  const char *sBase64TranslateTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+%";
 +
  void AsciiToBase64(char *Ascii, char *Buffer, int BufferSize)
 +
  {
 +
    int Length=0;
 +
    while (*Ascii)
 +
    {
 +
      unsigned long s32bits=0;
 +
      int i, j;
 +
      // Read 3 ASCII bytes
 +
      for (i = 2; i >= 0; i--)
 +
      {
 +
        if (*Ascii==0) break;
 +
        s32bits |= ((unsigned long)*Ascii++)<<(8*i);
 +
      }
 +
      // Convert them to four 6-bit items
 +
      for (j=3; j>=i+1; j--)
 +
      {
 +
        // Check for buffer overflow
 +
        if (++Length>=BufferSize) { *Buffer=0; return; }
 +
        // Convert 6-bit item
 +
        int c = ((s32bits >> (6 * j)) & 0x3f);
 +
        *Buffer++ = sBase64TranslateTable[c];
 +
      }
 +
      // Complete last bytes
 +
      for (/*void*/; j>=0 && ++Length<BufferSize; j--) *Buffer++='=';
 +
    }
 +
    *Buffer=0; // Trailing 0 is not needed for this project, but simplify testing
 +
  }
 +
  void Base64ToAscii(char *Base64, char *Buffer, int BufferSize)
 +
  {
 +
    int Length=0;
 +
    while (*Base64 && *Base64!='=')
 +
    {
 +
      unsigned long s24bits = 0;
 +
      // Read four 6-bit items
 +
      for (int i=3; i>=0; i--)
 +
      {
 +
        if (*Base64==0 || *Base64=='=') break;
 +
        char *p=strchr(sBase64TranslateTable, *Base64++);
 +
        if (p) s24bits |= ((unsigned long)(p-sBase64TranslateTable))<<(6*i);
 +
      }
 +
      // Convert them to three 8-bit items
 +
      for (int i=2; i>=0; i--)
 +
      {
 +
        // Check for buffer overflow
 +
        if (++Length>=BufferSize) break;
 +
        // Save byte
 +
        *Buffer++ = (char)((s24bits>>(8*i))&0xff);
 +
      }
 +
    }
 +
    *Buffer=0;
 +
  }
 +
  unsigned DecodeSamsungProtocolString(char *s, char *Buffer, int BufferSize, boolean bBase64)
 +
  {
 +
    // Get length of string in message
 +
    unsigned Length=s[0] | (((unsigned)s[1])<<8);
 +
    // Get the string
 +
    if (bBase64)
 +
    {
 +
      // Force trailing 0 into Base64 string
 +
      // (dirty but will work in this project, as the Base64 string is in a frame buffer...)
 +
      char c=s[Length+2]; s[Length+2]=0;
 +
      Base64ToAscii(s+2, Buffer, BufferSize);
 +
      // Restore corrupted char
 +
      s[Length+2]=c;
 +
    }
 +
    else
 +
    {
 +
      // Check for buffer overflow
 +
      unsigned MaxLength=(Length>BufferSize-1) ? BufferSize-1:Length;
 +
      // Just copy string
 +
      strncpy(Buffer, s+2, MaxLength);
 +
      Buffer[MaxLength]=0;
 +
    }
 +
    // Returns length of initial buffer
 +
    return Length+2;
 +
  }
 +
  unsigned EncodeSamsungProtocolString(char *s, char *Buffer, int BufferSize, boolean bBase64)
 +
  {
 +
    unsigned Length;
 +
    if (bBase64)
 +
    {
 +
      // Encode string in Base64
 +
      AsciiToBase64(s, Buffer+2, BufferSize-2);
 +
      Length=strlen(Buffer+2);
 +
    }
 +
    else
 +
    {
 +
      // Leave string in Ascii - No trailing 0
 +
      Length=strlen(s);
 +
      if (Length>BufferSize-2) Length=BufferSize-2;
 +
      strncpy(Buffer+2, s, Length);
 +
    }
 +
   
 +
    // Add size of string in message
 +
    Buffer[0]=Length; Buffer[1]=Length>>8;
 +
    return Length+2;  
 
   }
 
   }
 +
  #endif
 
    
 
    
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
Line 169: Line 302:
 
   class Samsung
 
   class Samsung
 
   {
 
   {
  private:
+
    private:
  // Send a 36kHz-modulated pulse
+
    // Send a 36kHz-modulated pulse
  static void Pulse(void)
+
    static void Pulse(void)
  {
+
    {
  byte i;
+
      byte i;
  for (i=0; i<21; i++)
+
      for (i=0; i<21; i++)
  {
+
      {
  digitalWrite(IRPIN, HIGH);
+
        digitalWrite(IRPIN, HIGH);
  delayMicroseconds(10); // Value adjusted with oscilloscope
+
        delayMicroseconds(10); // Value adjusted with oscilloscope
  digitalWrite(IRPIN, LOW);
+
        digitalWrite(IRPIN, LOW);
  delayMicroseconds(10); // Value adjusted with oscilloscope
+
        delayMicroseconds(10); // Value adjusted with oscilloscope
  }
+
      }
  }
+
    }
  // Send a bit
+
    // Send a bit
  static void SendIRBit(byte b)
+
    static void SendIRBit(byte b)
  {
+
    {
  Pulse();  
+
      Pulse();  
  if (b)  
+
      if (b)  
  delayMicroseconds(1390);
+
        delayMicroseconds(1390);
  else
+
      else
  delayMicroseconds(430);
+
        delayMicroseconds(430);
  }
+
    }
  // Send 4 bits
+
    // Send 4 bits
  static void SendIRNibble(byte b)
+
    static void SendIRNibble(byte b)
  {
+
    {
  byte i;
+
      byte i;
  for (i=0; i<4; i++)
+
      for (i=0; i<4; i++)
  SendIRBit((b>>i)&1);
+
        SendIRBit((b>>i)&1);
  }
+
    }
  // Send a byte
+
    // Send a byte
  static void SendIRByte(byte b)
+
    static void SendIRByte(byte b)
  {
+
    {
  byte i;
+
      byte i;
  for (i=0; i<8; i++)
+
      for (i=0; i<8; i++)
  SendIRBit((b>>i)&1);
+
        SendIRBit((b>>i)&1);
  }
+
    }
 
    
 
    
  public:
+
    public:
  // Send an IR command
+
    // Send an IR command
  // Type is 0 for TV, 1 for BD
+
    // Type is 0 for TV, 1 for BD
  // Device is 0x0707 for TV, 0x301A for BD
+
    // Device is 0x0707 for TV, 0x301A for BD
  // Crc should be ~Command, except for tests
+
    // Crc should be ~Command, except for tests
  static void SendCommand(char Type, unsigned int Device, unsigned int Command, unsigned char Crc)
+
    static void SendCommand(char Type, unsigned int Device, unsigned int Command, unsigned char Crc)
  {
+
    {
  byte i;
+
      byte i;
 
      
 
      
  // Disable interrupts
+
      // Disable interrupts
  cli();
+
      cli();
 
      
 
      
  // Start bit
+
      // Start bit
  for (i=0; i<8; i++) Pulse();
+
      for (i=0; i<8; i++) Pulse();
  delayMicroseconds(4500);
+
      delayMicroseconds(4500);
 
    
 
    
  // Send Device Id
+
      // Send Device Id
  SendIRByte(Device>>8);
+
      SendIRByte(Device>>8);
  SendIRByte(Device&0xff);
+
      SendIRByte(Device&0xff);
 
    
 
    
  // BD Player
+
      // BD Player
  if (Type==1)
+
      if (Type==1)
  {
+
      {
  // Stop bit
+
        // Stop bit
  Pulse();
+
        Pulse();
  delayMicroseconds(4500);
+
        delayMicroseconds(4500);
  // Send Data
+
        // Send Data
  SendIRNibble(Command>>8);
+
        SendIRNibble(Command>>8);
  }
+
      }
 
        
 
        
  SendIRByte(Command);
+
      SendIRByte(Command);
  SendIRByte(Crc);
+
      SendIRByte(Crc);
 
    
 
    
  // Stop bit
+
      // Stop bit
  Pulse();
+
      Pulse();
  delayMicroseconds(4500);
+
      delayMicroseconds(4500);
 
      
 
      
  // Re-enable interrupts
+
      // Re-enable interrupts
  sei();
+
      sei();
  }
+
    }
  // Read Eeprom
+
    // Read Eeprom
  static void ReadEeprom(byte device, long addr, byte *data, int count)
+
    static void ReadEeprom(byte device, long addr, byte *data, int count)
  {
+
    {
  if (addr!=0xffffffff)
+
      if (addr!=0xffffffff)
  {
+
      {
  Wire.beginTransmission(device);
+
        Wire.beginTransmission(device);
  Wire.write(addr>>8);
+
        if (bEeprom2ByteAddress) Wire.write(addr>>8);
  Wire.write(addr);
+
        Wire.write(addr);
  Wire.endTransmission();
+
        Wire.endTransmission();
  }
+
      }
  Wire.requestFrom((int)device, count);
+
      Wire.requestFrom((int)device, count);
  for (int i=0; i<count; i++)
+
      for (int i=0; i<count; i++)
  {
+
      {
  if (!Wire.available()) break;
+
        if (!Wire.available()) break;
  data[i]=Wire.read();
+
        data[i]=Wire.read();
  }
+
      }
  }
+
    }
  // Write Eeprom
+
    // Write Eeprom
  static void WriteEeprom(byte device, long addr, byte *data, int count)
+
    static void WriteEeprom(byte device, long addr, byte *data, int count)
  {
+
    {
  Wire.beginTransmission(device);
+
      Wire.beginTransmission(device);
  Wire.write(addr>>8);
+
      if (bEeprom2ByteAddress) Wire.write(addr>>8);
  Wire.write(addr);
+
      Wire.write(addr);
  for (int i=0; i<count; i++) Wire.write(data[i]);
+
      for (int i=0; i<count; i++) Wire.write(data[i]);
  Wire.endTransmission();
+
      Wire.endTransmission();
  }
+
    }
 +
    static boolean bEeprom2ByteAddress;
 
   };
 
   };
 +
  boolean Samsung::bEeprom2ByteAddress=true;
 
    
 
    
 
    
 
    
Line 281: Line 416:
 
   void setup()
 
   void setup()
 
   {
 
   {
  // Led
+
    // Led
  pinMode(LEDPIN, OUTPUT);
+
    pinMode(LEDPIN, OUTPUT);
  digitalWrite(LEDPIN, HIGH);
+
    digitalWrite(LEDPIN, HIGH);
 
 
  // IR Led
 
  pinMode(IRPIN, OUTPUT);
 
  digitalWrite(IRPIN, HIGH);
 
 
    
 
    
  // I2C
+
    // IR Led
  Wire.begin();
+
    pinMode(IRPIN, OUTPUT);
 +
    digitalWrite(IRPIN, HIGH);
 
    
 
    
  // Serial Console
+
    // I2C
  Serial.begin(115200);
+
    Wire.begin();
 
    
 
    
  // Initialize Ethernet. Try DHCP, otherwise static IP
+
    // Serial Console
  if (Ethernet.begin(mac)==0)
+
    Serial.begin(115200);
  Ethernet.begin(mac, ip);
 
  // Initialize HTTP server
 
 
    
 
    
  HttpServer.begin();
+
    // Initialize Ethernet. Try DHCP, otherwise static IP
  // Initialize Telnet server
+
    if (Ethernet.begin(mac)==0)
  TelnetServer.begin();
+
      Ethernet.begin(mac, ip);
 +
    // Initialize HTTP server
 +
    HttpServer.begin();
 +
    // Initialize Telnet server
 +
    TelnetServer.begin();
 +
    #ifdef SAMSUNGREMOTE
 +
    // Initialize Samsung Remote server
 +
    SamsungRemote.begin();
 +
    // Initialize SSDP
 +
    SamsungSSDP.begin(1900);
 +
    #endif
 
   }
 
   }
 
    
 
    
Line 310: Line 450:
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
 
    
 
    
   char HttpFrame[256];          // General buffer for Http frames
+
   char HttpFrame[256];          // General buffer for Http and Samsung protocol frames
 
   char TelnetFrame[256];        // General buffer for Telnet frames
 
   char TelnetFrame[256];        // General buffer for Telnet frames
 
   char Buffer[32];              // General buffer
 
   char Buffer[32];              // General buffer
Line 318: Line 458:
 
   void loop()
 
   void loop()
 
   {
 
   {
  // -------------------------------------------------
+
    // -------------------------------------------------
  // LED blinks at 2Hz
+
    // LED blinks at 2Hz
  // -------------------------------------------------
+
    // -------------------------------------------------
  if (millis()>timeLastLedMs+250)
+
    if (millis()>timeLastLedMs+250)
  {
+
    {
  timeLastLedMs=millis();
+
      timeLastLedMs=millis();
  digitalWrite(LEDPIN, (iStateLed) ? HIGH:LOW);
+
      digitalWrite(LEDPIN, (iStateLed) ? HIGH:LOW);
  iStateLed=!iStateLed;
+
      iStateLed=!iStateLed;
  }
+
    }
 
    
 
    
  // -------------------------------------------------
+
    // -------------------------------------------------
  // Handle HTTP requests
+
    // Handle HTTP requests
  // Example :  
+
    // Example :  
  //  To send KEY_1 on BD :
+
    //  To send KEY_1 on BD :
  //  http://IP/ir.htm?data=81&type=1&device=301a
+
    //  http://IP/ir.htm?data=81&type=1&device=301a
  // -------------------------------------------------
+
    // -------------------------------------------------
  EthernetClient client = HttpServer.available();
+
    EthernetClient client = HttpServer.available();
  if (client)  
+
    if (client)  
  {
+
    {
  char *ptr=HttpFrame;
+
      char *ptr=HttpFrame;
  int n=0;
+
      int n=0;
  while (client.connected() && client.available())
+
      while (client.connected() && client.available())
  {
+
      {
  if (n++<sizeof(HttpFrame))
+
        if (n++<sizeof(HttpFrame))
  *ptr++=client.read();
+
          *ptr++=client.read();
  else
+
        else
  client.flush();  
+
          client.flush();  
  }
+
      }
  *ptr=0;
+
      *ptr=0;
  if (n>0)
+
      if (n>0)
  {
+
      {
  __FlashStringHelper *HtmlHeader=F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
+
        const __FlashStringHelper *HtmlHeader=F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
 
    
 
    
  // -------------------------------------------------
+
        // -------------------------------------------------
  // Send Samsung IR command
+
        // Send Samsung IR command
  // -------------------------------------------------
+
        // -------------------------------------------------
  ptr=strstr(HttpFrame, "/ir.htm?");
+
        ptr=strstr(HttpFrame, "/ir.htm?");
  if (ptr)
+
        if (ptr)
  {
+
        {
  byte Type=0, Crc;
+
          byte Type=0, Crc;
  unsigned int Device=0x0707, Data=0;
+
          unsigned int Device=0x0707, Data=0;
 
    
 
    
  ptr=strstr(HttpFrame, "data=");
+
          ptr=strstr(HttpFrame, "data=");
  if (ptr) Data=HexToULong(ptr+5);
+
          if (ptr) Data=HexToULong(ptr+5);
  ptr=strstr(HttpFrame, "type=");
+
          ptr=strstr(HttpFrame, "type=");
  if (ptr) Type=HexToULong(ptr+5);
+
          if (ptr) Type=HexToULong(ptr+5);
  ptr=strstr(HttpFrame, "device=");
+
          ptr=strstr(HttpFrame, "device=");
  if (ptr) Device=HexToULong(ptr+7);
+
          if (ptr) Device=HexToULong(ptr+7);
 
            
 
            
  // Next parameter is optional and can be used for tests
+
          // Next parameter is optional and can be used for tests
  Crc=~Data;
+
          Crc=~Data;
  ptr=strstr(HttpFrame, "crc=");
+
          ptr=strstr(HttpFrame, "crc=");
  if (ptr) Crc=HexToULong(ptr+4);
+
          if (ptr) Crc=HexToULong(ptr+4);
 
    
 
    
  Samsung::SendCommand(Type, Device, Data, Crc);
+
          Samsung::SendCommand(Type, Device, Data, Crc);
  client.println(HtmlHeader);
+
          client.println(HtmlHeader);
  client.println("OK !");
+
          client.println("OK !");
  client.stop();
+
          client.stop();
  return;
+
          return;
  }
+
        }
 
    
 
    
  // -------------------------------------------------
+
        // -------------------------------------------------
  // Read Eeprom
+
        // Read Eeprom
  // -------------------------------------------------
+
        // -------------------------------------------------
  ptr=strstr(HttpFrame, "/read");
+
        ptr=strstr(HttpFrame, "/read");
  if (ptr)
+
        if (ptr)
  {
+
        {
  byte Device=0, Format=0x50;
+
          byte Device=80, Format=0x50; // hedak: changed eeprom device id to 80 to comply with description above
  unsigned long Size=0x100, Addr=0;
+
          unsigned long Size=0x100, Addr=0;
 
    
 
    
  ptr=strstr(HttpFrame, "addr=");
+
          ptr=strstr(HttpFrame, "addr=");
  if (ptr) Addr=HexToULong(ptr+5);
+
          if (ptr) Addr=HexToULong(ptr+5);
  ptr=strstr(HttpFrame, "size=");
+
          ptr=strstr(HttpFrame, "size=");
  if (ptr) Size=atol(ptr+5);
+
          if (ptr) Size=atol(ptr+5);
  ptr=strstr(HttpFrame, "device=");
+
          ptr=strstr(HttpFrame, "device=");
  if (ptr) Device=atoi(ptr+7);
+
          if (ptr) Device=atoi(ptr+7);
  ptr=strstr(HttpFrame, "format=");
+
          ptr=strstr(HttpFrame, "format=");
  if (ptr) Format=atoi(ptr+7);
+
          if (ptr) Format=atoi(ptr+7);
 +
          ptr=strstr(HttpFrame, "width=8");
 +
          Samsung::bEeprom2ByteAddress=(ptr==0);
 
    
 
    
  if (Format==0)  
+
          if (Format==0)  
  {
+
          {
  client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
+
            client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
  }
+
          }
  else
+
          else
  client.println("HTTP/1.1 200 OK\r\nContent-Type: binary/octet-stream\r\n");
+
            client.println("HTTP/1.1 200 OK\r\nContent-Type: binary/octet-stream\r\n");
 
    
 
    
  byte bSequential=0;     
+
          byte bSequential=0;     
  for ((long i=Addr; i<Addr+Size; i+=32)
+
          for (long i=Addr; i<Addr+Size; i+=32)
  {
+
          {
  unsigned char Data[32];  
+
            unsigned char Data[32];  
  for (int i=0; i<32; i++) Data[i]=0xff;
+
            for (int i=0; i<32; i++) Data[i]=0xff;
  Samsung::ReadEeprom(Device, (bSequential) ? -1:i, Data, 32);
+
            Samsung::ReadEeprom(Device, (bSequential) ? -1:i, Data, 32);
  bSequential=1;
+
            bSequential=1;
 
    
 
    
  if (Format==0)
+
            if (Format==0)
  {           
+
            {           
  sprintf(Buffer, "%04lx: ", i); client.print(Buffer);
+
              sprintf(Buffer, "%04lx: ", i); client.print(Buffer);
  for (int j=0; j<32; j++)
+
              for (int j=0; j<32; j++)
  { sprintf(Buffer, "%02X ", Data[j]); client.print(Buffer); }
+
                { sprintf(Buffer, "%02X ", Data[j]); client.print(Buffer); }
  for (int j=0; j<32; j++)
+
              for (int j=0; j<32; j++)
  { client.write((Data[j]<=0x20 || Data[j]>0x7f) ? '.':Data[j]); }
+
                { client.write((Data[j]<=0x20 || Data[j]>0x7f) ? '.':Data[j]); }
  client.println("");
+
              client.println("");
  client.flush();
+
              client.flush();
  }
+
            }
  else
+
            else
  {
+
            {
  for (int j=0; j<32; j++)
+
              for (int j=0; j<32; j++)
  client.write(Data[j]);
+
                client.write(Data[j]);
  }
+
            }
  }
+
          }
 
    
 
    
  client.stop();
+
          client.stop();
  return;
+
          return;
  }
+
        }
 
    
 
    
  // -------------------------------------------------
+
        // -------------------------------------------------
  // Write Eeprom
+
        // Write Eeprom
  // -------------------------------------------------
+
        // -------------------------------------------------
  ptr=strstr(HttpFrame, "/write");
+
        ptr=strstr(HttpFrame, "/write");
  char *ptrAddr=strstr(HttpFrame, "addr=");
+
        char *ptrAddr=strstr(HttpFrame, "addr=");
  char *ptrData=strstr(HttpFrame, "data=");
+
        char *ptrData=strstr(HttpFrame, "data=");
  if (ptr && ptrAddr && ptrData)
+
        if (ptr && ptrAddr && ptrData)
  {
+
        {
  byte Device=0, Data;
+
          byte Device=80, Data; // hedak: changed eeprom device id to 80 to comply with description above
  unsigned long Addr;
+
          unsigned long Addr;
 
            
 
            
  Addr=HexToULong(ptrAddr+5);
+
          Addr=HexToULong(ptrAddr+5);
  Data=HexToULong(ptrData+5);
+
          Data=HexToULong(ptrData+5);
  ptr=strstr(HttpFrame, "device=");
+
          ptr=strstr(HttpFrame, "device=");
  if (ptr) Device=atoi(ptr+7);
+
          if (ptr) Device=atoi(ptr+7);
 +
          ptr=strstr(HttpFrame, "width=8");
 +
          Samsung::bEeprom2ByteAddress=(ptr==0);
 
    
 
    
  Samsung::WriteEeprom(Device, Addr, &Data, 1);
+
          Samsung::WriteEeprom(Device, Addr, &Data, 1);
  client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
+
          client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
  Data=~Data;
+
          Data=~Data;
  Samsung::ReadEeprom(Device, Addr, &Data, 1);     
+
          Samsung::ReadEeprom(Device, Addr, &Data, 1);     
  sprintf(Buffer, "%02X ", Data);  
+
          sprintf(Buffer, "%02X ", Data);  
  client.print(Buffer);
+
          client.print(Buffer);
 
    
 
    
  client.stop();
+
          client.stop();
  return;
+
          return;
  }
+
        }
 
    
 
    
  // send an error !
+
        #ifdef SAMSUNGREMOTE
  client.println(HtmlHeader);
+
        // -------------------------------------------------
  client.println(F("Error !"));
+
        // Device info - used for Samsung Remote Protocol
  delay(1);
+
        // -------------------------------------------------
  }
+
        ptr=strstr(HttpFrame, "/smp_2_");
  client.stop();
+
        if (ptr)
  }
+
        {
 +
          client.println(F("HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n"));
 +
          client.println(F("<?xml version=\"1.0\"?>"));
 +
          client.println(F("<root xmlns='urn:schemas-upnp-org:device-1-0' xmlns:sec='http://www.sec.co.kr/dlna' xmlns:dlna='urn:schemas-dlna-org:device-1-0'>"));
 +
          client.println(F(" <specVersion>"));
 +
          client.println(F("  <major>1</major>"));
 +
          client.println(F("  <minor>0</minor>"));
 +
          client.println(F(" </specVersion>"));
 +
          client.println(F(" <device>"));
 +
          client.println(F("  <deviceType>urn:samsung.com:device:RemoteControlReceiver:1</deviceType>"));
 +
          client.println(F("  <friendlyName>SamyGO</friendlyName>"));
 +
          client.println(F("  <manufacturer>Samsung Electronics</manufacturer>"));
 +
          client.println(F("  <manufacturerURL>http://www.samsung.com/sec</manufacturerURL>"));
 +
          client.println(F("  <modelDescription>Samsung BD RCR</modelDescription>"));
 +
          client.println(F(" <modelName>BD-E8500</modelName>"));
 +
          client.println(F("  <modelNumber>1.0</modelNumber>"));
 +
          client.println(F("  <modelURL>http://www.samsung.com/sec</modelURL>"));
 +
          client.println(F("  <serialNumber>12345678RCR</serialNumber>"));
 +
          client.println(F("  <UDN>uuid:11111111-2222-3333-4444-555555555555</UDN>"));
 +
          client.println(F("  <sec:deviceID>ABCDEFGHIJKLM</sec:deviceID>"));
 +
          client.println(F("  <sec:ProductCap>Resolution:1280X720,ImageZoom,ImageRotate,Y2012</sec:ProductCap>"));
 +
          client.println(F("  <serviceList>"));
 +
          client.println(F("  <service>"));
 +
          client.println(F("    <serviceType>urn:samsung.com:service:TestRCRService:1</serviceType>"));
 +
          client.println(F("    <serviceId>urn:samsung.com:serviceId:TestRCRService</serviceId>"));
 +
          client.println(F("    <controlURL>/smp_4_</controlURL>"));
 +
          client.println(F("    <eventSubURL>/smp_5_</eventSubURL>"));
 +
          client.println(F("    <SCPDURL>/smp_3_</SCPDURL>"));
 +
          client.println(F("  </service>"));
 +
          client.println(F("  </serviceList>"));
 +
          client.println(F(" </device>"));
 +
          client.println(F("</root>"));
 +
          client.stop();
 +
          return;
 +
        }
 +
        #endif
 
    
 
    
  // -------------------------------------------------
+
        // send an error !
  // Telnet Serial Console Interface
+
        client.println(HtmlHeader);
  // Configure Putty with :
+
        client.println(F("Error !"));
  //  - "Local Echo : Force off"
+
        delay(1);
  //   - "Local line editing : Force off"
+
      }
  // -------------------------------------------------
+
      client.stop();
  client = TelnetServer.available();
+
    }
  if (client)  
+
 
  {
+
    #ifdef SAMSUNGREMOTE
  char *ptr=TelnetFrame;
+
    // -------------------------------------------------
  int n=0;
+
    // Samsung Remote Protocol
  while (client.connected() && client.available())
+
    // -------------------------------------------------
  if (n++<sizeof(TelnetFrame)) *ptr++=client.read();
+
    client = SamsungRemote.available();
  *ptr=0;
+
    if (client)  
 +
    {
 +
      //Serial.println("Incoming frame...");
 
        
 
        
  // Sends telnet buffer to Serial Console
+
      // Read incoming frame
  if (n>0) Serial.write(TelnetFrame);
+
      char *ptr=HttpFrame;
  }
+
      int n=0;
  // Anything received from Serial Console ?
+
      while (client.connected() && client.available())
  char *ptr=TelnetFrame;
+
        if (n++<sizeof(HttpFrame)) *ptr++=client.read();
  int n=0;
+
 
  while (Serial.available())
+
 
  if (n++<sizeof(TelnetFrame)) *ptr++=Serial.read();
+
      ptr=HttpFrame+1;
  *ptr=0;
+
      // Decode App Name
  // Send it to telnet
+
      ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), false);
  if (n>0) TelnetServer.write(TelnetFrame);
+
      //Serial.print("Name="); Serial.println(Buffer);
 +
 
 +
      // Ignore message length
 +
      ptr+=2;
 +
 
 +
      // Decode command
 +
      unsigned Cmd=*ptr++; Cmd|=(*ptr++)<<8;
 +
      //Serial.print("Cmd="); Serial.println(Cmd);
 +
 
 +
      // Connection frame ?
 +
      if (Cmd==0x64)
 +
      {
 +
        // Decode remote IP
 +
        ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
 +
        //Serial.print("IP="); Serial.println(Buffer);
 +
 
 +
        // Decode remote MAC address
 +
        ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
 +
        //Serial.print("MAC="); Serial.println(Buffer);
 +
 
 +
        // Decode machine name
 +
        ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
 +
        //Serial.print("Machine="); Serial.println(Buffer);
 +
        delay(5);
 +
      }
 +
 
 +
      // Key frame ?
 +
      else if (Cmd==0x00)
 +
      {
 +
        ptr++; // Skip first byte
 +
        ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
 +
        //Serial.print("KeyName="); Serial.print(Buffer); Serial.println("----");
 +
        if (!strcmp(Buffer, "BD_KEY_POWER"))
 +
        {
 +
          // Power key for BD
 +
          Samsung::SendCommand(1, 0x301a, 0x91, ~0x91);
 +
        }
 +
      }
 +
 
 +
      // Answer
 +
      HttpFrame[0]=0;
 +
      int len=1;
 +
      len+=EncodeSamsungProtocolString("iapp.samsung", HttpFrame+1, sizeof(HttpFrame), false);
 +
      if (Cmd==0x64)
 +
      {
 +
        byte answer[]={0x04,0x00,0x64,0x00,0x01,0x00};
 +
        memcpy(HttpFrame+len, answer, sizeof(answer));
 +
        len+=sizeof(answer);
 +
      }
 +
      else
 +
      {
 +
        byte answer[]={0x04,0x00,0x00,0x00,0x00,0x00};
 +
        memcpy(HttpFrame+len, answer, sizeof(answer));
 +
        len+=sizeof(answer);
 +
      }
 +
      client.write((byte *)HttpFrame, len);
 +
      delay(5);
 +
    }
 +
 
 +
    // SSDP discovery protocol
 +
    int PacketSize=SamsungSSDP.parsePacket();
 +
    if (PacketSize)
 +
    {
 +
      // Read incoming frame
 +
      char *ptr=HttpFrame;
 +
      int n=0;
 +
      while (SamsungSSDP.available())
 +
        if (n++<sizeof(HttpFrame)) *ptr++=SamsungSSDP.read();
 +
 
 +
      // Discovery request ?
 +
      if (strstr(HttpFrame, "M-SEARCH *") && strstr(HttpFrame, "urn:samsung.com:device:RemoteControlReceiver:1"))
 +
      {
 +
        //Serial.print("SSDP Discovery from : IP="); Serial.print(SamsungSSDP.remoteIP()); Serial.print(":"); Serial.println(SamsungSSDP.remotePort());
 +
        SamsungSSDP.beginPacket(SamsungSSDP.remoteIP(), SamsungSSDP.remotePort());
 +
        SamsungSSDP.println(F("HTTP/1.1 200 OK"));
 +
        SamsungSSDP.println(F("CACHE-CONTROL: max-age= 1800"));
 +
        SamsungSSDP.println(F("Date: Sat, 01 Jan 2012 00:00:00 GMT"));
 +
        SamsungSSDP.println(F("EXT: "));
 +
        SamsungSSDP.print(F("LOCATION: http://")); SamsungSSDP.print(Ethernet.localIP()); SamsungSSDP.println(F(":80/smp_2_"));
 +
        SamsungSSDP.println(F("SERVER: SHP, UPnP/1.0, Samsung UPnP SDK/1.0"));
 +
        SamsungSSDP.println(F("ST: urn:samsung.com:device:RemoteControlReceiver:1"));
 +
        SamsungSSDP.println(F("USN: uuid:11111111-2222-3333-4444-555555555555::urn:samsung.com:device:RemoteControlReceiver:1"));
 +
        SamsungSSDP.println(F("Content-Length: 0"));
 +
        SamsungSSDP.endPacket();
 +
      }
 +
    }
 +
    #endif
 +
 
 +
    // -------------------------------------------------
 +
    // Telnet Serial Console Interface
 +
    // Configure Putty with :
 +
    //  - "Local Echo : Force off"
 +
    //  - "Local line editing : Force off"
 +
    // -------------------------------------------------
 +
    client = TelnetServer.available();
 +
    if (client)
 +
    {
 +
      char *ptr=TelnetFrame;
 +
      int n=0;
 +
      while (client.connected() && client.available())
 +
        if (n++<sizeof(TelnetFrame)) *ptr++=client.read();
 +
      *ptr=0;
 +
     
 +
      // Sends telnet buffer to Serial Console
 +
      if (n>0) Serial.write(TelnetFrame);
 +
    }
 +
    // Anything received from Serial Console ?
 +
    char *ptr=TelnetFrame;
 +
    int n=0;
 +
    while (Serial.available())
 +
      if (n++<sizeof(TelnetFrame)) *ptr++=Serial.read();
 +
    *ptr=0;
 +
      // Send it to telnet
 +
    if (n>0) TelnetServer.write(TelnetFrame);
 
   }
 
   }
 
    
 
    
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
 +
 +
== Teensy(++ 2.0) sketch for accessing I2C interface ==
 +
 +
This sketch has been compiled with Arduino 1.0.5.
 +
It's a limited version compared to the arduino sketch above. Only the I2C interface to read/write tv's eeprom is implemented and instead of the ethernet interface there's a usb interface (Hint: sketch becomes active only if DTR on pc side is set). Usage of the I2C feature is the same anyway.
 +
 +
// ---------------------------------------------------------------------
 +
// Samsung I2C interface based on oga83's 'Samsung multi-functions ethernet interface' v1.2
 +
//  - Read & Write I2C config eeprom
 +
//
 +
// 07-03-2014 / v1.1 / hedak
 +
//----------------------------------------------------------------------
 +
 +
#include <SPI.h>
 +
#include <Wire.h>
 +
#include "utility\twi.h" //hedak: for outputting I2C frequency
 +
 +
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
 +
 +
#define LEDPIN    CORE_LED0_PIN    // Onboard led - blink at 2 Hz
 +
                        // I2C Eeprom : SDA connected on D1
 +
                        // I2C Eeprom : SCL connected on D0
 +
 +
// ---------------------------------------------------------------------
 +
// Utilities
 +
// ---------------------------------------------------------------------
 +
 +
// Convert a hex string to unsigned int
 +
unsigned long HexToULong(char *s)
 +
{
 +
  unsigned long u=0;
 +
  while (*s)
 +
  {
 +
    char c=*s++;
 +
    // Convert to uppercase
 +
    if (c>='a') c&=0xdf;
 +
    // Exit if not hex digit
 +
    if ((c<'0' || c>'9') && (c<'A' || c>'F')) break;
 +
    // Convert digit
 +
    u<<=4;
 +
    u|=c-((c>'9') ? 'A'-0xa:'0');
 +
  }
 +
  return u;
 +
}
 +
 +
 +
// ---------------------------------------------------------------------
 +
// Samsung class
 +
// ---------------------------------------------------------------------
 +
 +
class Samsung
 +
{
 +
  public:
 +
  // Read Eeprom
 +
  static void ReadEeprom(byte device, long addr, byte *data, int count)
 +
  {
 +
    if (addr!=0xffffffff)
 +
    {
 +
      Wire.beginTransmission(device);
 +
      if (bEeprom2ByteAddress) Wire.write(addr>>8);
 +
      Wire.write(addr);
 +
      Wire.endTransmission();
 +
    }
 +
    Wire.requestFrom((int)device, count);
 +
    for (int i=0; i<count; i++)
 +
    {
 +
      if (!Wire.available()) break;
 +
      data[i]=Wire.read();
 +
    }
 +
  }
 +
  // Write Eeprom
 +
  static void WriteEeprom(byte device, long addr, byte *data, int count)
 +
  {
 +
    Wire.beginTransmission(device);
 +
    if (bEeprom2ByteAddress) Wire.write(addr>>8);
 +
    Wire.write(addr);
 +
    for (int i=0; i<count; i++) Wire.write(data[i]);
 +
    Wire.endTransmission();
 +
  }
 +
  static boolean bEeprom2ByteAddress;
 +
};
 +
boolean Samsung::bEeprom2ByteAddress=true;
 +
 +
// ---------------------------------------------------------------------
 +
// Main Program
 +
// ---------------------------------------------------------------------
 +
 +
char HttpFrame[256];          // General buffer for Http and Samsung protocol frames
 +
char Buffer[32];              // General buffer
 +
boolean iStateLed=false;      // Used for led blinking
 +
unsigned long timeLastLedMs=0; // Used for blinking delay
 +
 +
void loop()
 +
{
 +
  // -------------------------------------------------
 +
  // LED blinks at 2Hz
 +
  // -------------------------------------------------
 +
  if (millis()>timeLastLedMs+250)
 +
  {
 +
    timeLastLedMs=millis();
 +
    digitalWrite(LEDPIN, (iStateLed) ? HIGH:LOW);
 +
    iStateLed=!iStateLed;
 +
  }
 +
 +
  // -------------------------------------------------
 +
  // Handle HTTP requests
 +
  // Example :
 +
  //  To read a whole EEPROM dump :
 +
  //  http://IP/read?format=1&device=80&size=256
 +
  // -------------------------------------------------
 +
    char *ptr=HttpFrame;
 +
    int n=0;
 +
    while (Serial.available())
 +
    {
 +
      if (n++<sizeof(HttpFrame))
 +
        *ptr++=Serial.read();
 +
      else
 +
        Serial.flush();
 +
    }
 +
    *ptr=0;
 +
    Serial.write(HttpFrame);
 +
    if (n>0)
 +
    {
 +
      // -------------------------------------------------
 +
      // Read Eeprom
 +
      // -------------------------------------------------
 +
      ptr=strstr(HttpFrame, "/read");
 +
      if (ptr)
 +
      {
 +
        byte Device=80, Format=0x50; // hedak: fixed wrong default value for 'Device'
 +
        unsigned long Size=0x100, Addr=0;
 +
 +
        ptr=strstr(HttpFrame, "addr=");
 +
        if (ptr) Addr=HexToULong(ptr+5);
 +
        ptr=strstr(HttpFrame, "size=");
 +
        if (ptr) Size=atol(ptr+5);
 +
        ptr=strstr(HttpFrame, "device=");
 +
        if (ptr) Device=atoi(ptr+7);
 +
        ptr=strstr(HttpFrame, "format=");
 +
        if (ptr) Format=atoi(ptr+7);
 +
        ptr=strstr(HttpFrame, "width=8");
 +
        Samsung::bEeprom2ByteAddress=(ptr==0);
 +
 +
        sprintf(Buffer, "Start reading @ address: %lX\r\n", Addr);
 +
        Serial.write(Buffer);
 +
       
 +
        if (Format==0)
 +
        {
 +
          Serial.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
 +
        }
 +
        else
 +
          Serial.write("HTTP/1.1 200 OK\r\nContent-Type: binary/octet-stream\r\n");
 +
 +
        byte bSequential=0;   
 +
        for (long i=Addr; i<Addr+Size; i+=32)
 +
        {
 +
          unsigned char Data[32];
 +
          for (int i=0; i<32; i++) Data[i]=0xff;
 +
          Samsung::ReadEeprom(Device, (bSequential) ? -1:i, Data, 32);
 +
          bSequential=1;
 +
 +
          if (Format==0)
 +
          {         
 +
            sprintf(Buffer, "%04lx: ", i); Serial.write(Buffer);
 +
            for (int j=0; j<32; j++)
 +
              { sprintf(Buffer, "%02X ", Data[j]); Serial.write(Buffer); }
 +
            for (int j=0; j<32; j++)
 +
              { Serial.write((Data[j]<=0x20 || Data[j]>0x7f) ? '.':Data[j]); }
 +
            Serial.write("\r\n");
 +
            Serial.flush();
 +
          }
 +
          else
 +
          {
 +
            for (int j=0; j<32; j++)
 +
              Serial.write(Data[j]);
 +
          }
 +
        }
 +
        return;
 +
      }
 +
 +
      // -------------------------------------------------
 +
      // Write Eeprom
 +
      // -------------------------------------------------
 +
      ptr=strstr(HttpFrame, "/write");
 +
      Serial.write("Remove the following 'return;' line to activate write feature!\r\n");
 +
      return;
 +
      char *ptrAddr=strstr(HttpFrame, "addr=");
 +
      char *ptrData=strstr(HttpFrame, "data=");
 +
      if (ptr && ptrAddr && ptrData)
 +
      {
 +
        byte Device=0, Data;
 +
        unsigned long Addr;
 +
       
 +
        Addr=HexToULong(ptrAddr+5);
 +
        Data=HexToULong(ptrData+5);
 +
        ptr=strstr(HttpFrame, "device=");
 +
        if (ptr) Device=atoi(ptr+7);
 +
        ptr=strstr(HttpFrame, "width=8");
 +
        Samsung::bEeprom2ByteAddress=(ptr==0);
 +
 +
        Samsung::WriteEeprom(Device, Addr, &Data, 1);
 +
        Serial.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
 +
        Data=~Data;
 +
        Samsung::ReadEeprom(Device, Addr, &Data, 1);   
 +
        sprintf(Buffer, "%02X ", Data);
 +
        Serial.write(Buffer);
 +
        return;
 +
      }
 +
      // send an error !
 +
      Serial.write("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
 +
      Serial.write("Error !\r\n");
 +
      delay(1);
 +
    }
 +
}
 +
 +
// ---------------------------------------------------------------------
 +
// Initialization
 +
// ---------------------------------------------------------------------
 +
 +
void setup()
 +
{
 +
#if (F_CPU == 8000000)
 +
    // set for 8 MHz clock because of operating at 3.3 volts
 +
    CPU_PRESCALE(0x01);
 +
#else
 +
    // set for external 16 MHz clock
 +
    CPU_PRESCALE(0x00);
 +
#endif
 +
  // Led
 +
  pinMode(LEDPIN, OUTPUT);
 +
  digitalWrite(LEDPIN, HIGH);
 +
 +
  // I2C
 +
  Wire.begin();
 +
 +
  // Serial Console
 +
  Serial.begin(115200);
 +
 
 +
  // wait for the user to run their terminal emulator program
 +
  // which sets DTR to indicate it is ready to receive.
 +
  while (!Serial.dtr()) /* wait */ ;
 +
  sprintf(Buffer, "TWI_FREQ: %ld", TWI_FREQ);
 +
  Serial.write(Buffer);
 +
}
 +
 +
// ---------------------------------------------------------------------
 +
 +
== References ==
 +
Any discussion on related [http://forum.samygo.tv/viewtopic.php?f=51&t=5307#p38502 forum topic].
 +
Thread using teensy sketch is [http://forum.samygo.tv/viewtopic.php?f=15&t=7117#p53751 here].

Latest revision as of 20:08, 7 March 2014

Using an Arduino Ethernet board, you can send IR codes to your TV or BD

With the same board, you can also interface to the Serial Console, and read your device config eeprom.


What you can do

  • Send IR codes to your TV, PVR or BD, with an URL in your browser
  • Use telnet to have the Serial Console on your PC or smartphone
  • Read your SoC config eeprom
  • Read/write micom config eeprom
  • See Arduino as a Samsung device in the Samsung Remote App (can be used to power on the device !)


Arduino interface.jpg EthernetInterface-SamsungRemote.png

Bill of materials

  • Arduino Ethernet board (see Arduino)

Alternatively, an Arduino Uno with an Ethernet shield could also be used

  • IR led (SFH4510 for example) or RED Led (Clear Type RED LED's are emitting more than enough light at IR spectrum)
  • 220 ohms resistor to limit current in the IR led
  • If you plan to use the telnet interface to the Serial Console, make sure you have a 100 ohms resistor on both RX and TX signals (Arduino TX/RX are 5v !)


How to use it

  • Upload the following sketch into your Arduino
  • Connect the IR or RED led with its resistor on pin 8 on the Arduino
  • Connect power and network
  • Find the IP address of the board on your DHCP (or use the static IP embedded in the sketch if you don't have DHCP)
  • Use your browser to send an URL to the board (see format below)
  • If you want to use telnet to connect to the Serial Console :
* Connect your Serial Console signals TX&RX to the Arduino board pins 0&1  (with 100 ohms resistors)
* Use Putty with options 'Local Echo' and 'Local line editing' forced to OFF
  • If you want to read your config eeprom :
* Connect the eeprom SDA&SCK signals to the Arduino board pins A4/A5 (with 100 ohms resistors)
* Connect the eeprom GND to 0v
  • If you want to use the Samsung Remote feature :
* Compile with SAMSUNGREMOTE defined
* The program only handles BD_KEY_POWER; if you want aditional keys, it's easy to add them

URL format to send IR codes

The format is http://IP/ir.htm?data=XX&type=Y&device=ZZZZ where

  • IP is the Arduino board IP address
  • XX is the IR code to send
  • Y is 0 for TV/PVR frame format and 1 for BD frame format
  • ZZZZ is the device code (0707 for TV, 0505 for PVR, 301A for BD)


The IR codes are listed at Key codes

  • For TV/PVR, use the 'code' column
  • For BD, use the 'BD-IR code' column


For example:


To get the Service Menu on your TV, use the 2 following URLs :

Please note that you cannot send KEY_FACTORY to a BD, as the corresponding code is not know yet


To have a kind of Wake Up on LAN on your BD player, use


To switch to channel 1 :


URL format to read config Eeprom

The format is http://IP/read?format=F&device=D&addr=A&size=S&width=W

  • IP is the Arduino board IP address
  • F is 0 to get the result in html, 1 to download a binary file
  • D is the Eeprom device identification (80 by default)
  • A is the starting address for reading (0 by default)
  • S is the number of bytes to read (default=256)
  • W is the address bus width (8 bits for Micom eeprom, 16 bits for SoC eeprom); default is 16


For example:


BD-E8300 is equiped with a 24512 eeprom (64 kbytes)

To download its whole config :

or :


Eeprom connection :

Arduino I2C Eeprom.jpg

URL format to write config Eeprom

The format is http://IP/write?device=D&addr=A&data=X&width=W

  • IP is the Arduino board IP address
  • D is the Eeprom device identification (80 by default)
  • A is the starting address for writing (0 by default)
  • X is the data byte to write
  • W is the address bus width (8 bits for Micom eeprom, 16 bits for SoC eeprom); default is 16

On this version, it is only possible to write one byte at once...

For example: http://IP/write?addr=e0&data=55&width=16 will write 0x55 at address 0xe0

IR frames format

BD players use a modified IR frame format that TV and PVR. The reason is that samsung increased the data field length from 8 to 12 bits The general format is now :

  • Start bit
  • Device ID (16 bits - 0707 for TV, 301A for BD)
  • For BD only : Stop bit and data MSB on 4 bits
  • Data LSB
  • Data LSB 1's complement


A frame for BD :

BD IR Frame Format.png

Arduino sketch

This sketch has been compiled with Arduino 1.0.3 (Download here)

 // ---------------------------------------------------------------------
 // Samsung multi-functions ethernet interface 
 //   - Send IR frame with http get requests
 //   - Debug console on telnet
 //   - Read & Write I2C config eeprom
 //
 // 29-06-2012 / v1.1 / oga83
 // 11-09-2012 / v1.1 / oga83
 //    Added optionnal 'crc' url parameter for testing IR (allow to force CRC)
 //    Added I2C interface to read/write config eeprom
 // 09-01-2013 / v1.1.1 / oga83
 //    Fixed compilation issue with Arduino 1.0.3 and typo in wiki
 // 11-01-2013 / v1.1.2 / oga83
 //    Modified ReadEeprom and WriteEeprom for 1-byte address eeproms
 // 11-01-2013 / v1.2 / oga83
 //    Added Samsung Remote protocol (Arduino seen as a samsung device)
 //----------------------------------------------------------------------
 
 #include <SPI.h>
 #include <Ethernet.h>
 #include <EthernetUdp.h>
 #include <Wire.h>
 
 #define IRPIN      8    // IR led is connected on pin 8
 #define LEDPIN     9    // Onboard led - blink at 2 Hz
                         // Debug console TX signal connected on 0
                         // Debug console RX signal connected on 1
                         // I2C Eeprom : SDA connected on A4
                         // I2C Eeprom : SCK connected on A5
 
 
 byte mac[] = { 0x90, 0xA2, 0xda, 0x00, 0xe6, 0x5e }; // Arduino Ethernet board MAC address
 
 IPAddress ip(192,168,1,178);     // Default static IP if no DHCP 
 EthernetServer HttpServer(80);   // HTTP is used to send IR commands
 EthernetServer TelnetServer(23); // Telnet is used for Serial Console
 
 #define SAMSUNGREMOTE            // if defined, Arduino will be seen as a Samsung device
 #ifdef SAMSUNGREMOTE
 EthernetServer SamsungRemote(55000); // Emulates a Samsung device
 EthernetUDP SamsungSSDP;  // Handles Samsung device discovery
 #endif
 
 // ---------------------------------------------------------------------
 // Utilities
 // ---------------------------------------------------------------------
 
 // Convert a hex string to unsigned int
 unsigned int HexToULong(char *s)
 {
   unsigned long u=0;
   while (*s)
   {
     char c=*s++;
     // Convert to uppercase
     if (c>='a') c&=0xdf;
     // Exit if not hex digit
     if ((c<'0' || c>'9') && (c<'A' || c>'F')) break;
     // Convert digit
     u<<=4;
     u|=c-((c>'9') ? 'A'-0xa:'0');
   }
   return u;
 }
 
 #ifdef SAMSUNGREMOTE
 // Base64 conversion
 const char *sBase64TranslateTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+%";
 void AsciiToBase64(char *Ascii, char *Buffer, int BufferSize)
 {
   int Length=0;
   while (*Ascii)
   {
     unsigned long s32bits=0;
     int i, j;
     // Read 3 ASCII bytes
     for (i = 2; i >= 0; i--)
     {
       if (*Ascii==0) break;
       s32bits |= ((unsigned long)*Ascii++)<<(8*i);
     }
     // Convert them to four 6-bit items 
     for (j=3; j>=i+1; j--)
     {
       // Check for buffer overflow
       if (++Length>=BufferSize) { *Buffer=0; return; }
       // Convert 6-bit item
       int c = ((s32bits >> (6 * j)) & 0x3f);
       *Buffer++ = sBase64TranslateTable[c];
     }
     // Complete last bytes
     for (/*void*/; j>=0 && ++Length<BufferSize; j--) *Buffer++='=';
   }
   *Buffer=0; // Trailing 0 is not needed for this project, but simplify testing
 }
 void Base64ToAscii(char *Base64, char *Buffer, int BufferSize)
 {
   int Length=0;
   while (*Base64 && *Base64!='=')
   {
     unsigned long s24bits = 0;
     // Read four 6-bit items
     for (int i=3; i>=0; i--)
     {
       if (*Base64==0 || *Base64=='=') break;
       char *p=strchr(sBase64TranslateTable, *Base64++);
       if (p) s24bits |= ((unsigned long)(p-sBase64TranslateTable))<<(6*i);
     }
     // Convert them to three 8-bit items 
     for (int i=2; i>=0; i--) 
     {
       // Check for buffer overflow
       if (++Length>=BufferSize) break;
       // Save byte
       *Buffer++ = (char)((s24bits>>(8*i))&0xff);
     }
   }
   *Buffer=0;
 }
 unsigned DecodeSamsungProtocolString(char *s, char *Buffer, int BufferSize, boolean bBase64)
 {
   // Get length of string in message
   unsigned Length=s[0] | (((unsigned)s[1])<<8);
   // Get the string
   if (bBase64)
   {
     // Force trailing 0 into Base64 string 
     // (dirty but will work in this project, as the Base64 string is in a frame buffer...)
     char c=s[Length+2]; s[Length+2]=0;
     Base64ToAscii(s+2, Buffer, BufferSize);
     // Restore corrupted char
     s[Length+2]=c;
   }
   else
   {
     // Check for buffer overflow
     unsigned MaxLength=(Length>BufferSize-1) ? BufferSize-1:Length;
     // Just copy string
     strncpy(Buffer, s+2, MaxLength);
     Buffer[MaxLength]=0;
   }
   // Returns length of initial buffer 
   return Length+2;
 }
 unsigned EncodeSamsungProtocolString(char *s, char *Buffer, int BufferSize, boolean bBase64)
 {
   unsigned Length;
   if (bBase64) 
   {
     // Encode string in Base64
     AsciiToBase64(s, Buffer+2, BufferSize-2); 
     Length=strlen(Buffer+2);
   }
   else
   {
     // Leave string in Ascii - No trailing 0
     Length=strlen(s);
     if (Length>BufferSize-2) Length=BufferSize-2;
     strncpy(Buffer+2, s, Length);
   }
   
   // Add size of string in message
   Buffer[0]=Length; Buffer[1]=Length>>8;
   return Length+2; 
 }
 #endif
 
 // ---------------------------------------------------------------------
 // Samsung IR class
 // ---------------------------------------------------------------------
 
 class Samsung
 {
   private:
   // Send a 36kHz-modulated pulse
   static void Pulse(void)
   {
     byte i;
     for (i=0; i<21; i++)
     {
       digitalWrite(IRPIN, HIGH);
       delayMicroseconds(10); // Value adjusted with oscilloscope
       digitalWrite(IRPIN, LOW);
       delayMicroseconds(10); // Value adjusted with oscilloscope
     }
   }
   // Send a bit
   static void SendIRBit(byte b)
   {
     Pulse(); 
     if (b) 
       delayMicroseconds(1390);
     else
       delayMicroseconds(430);
   }
   // Send 4 bits
   static void SendIRNibble(byte b)
   {
     byte i;
     for (i=0; i<4; i++)
       SendIRBit((b>>i)&1);
   }
   // Send a byte
   static void SendIRByte(byte b)
   {
     byte i;
     for (i=0; i<8; i++)
       SendIRBit((b>>i)&1);
   }
 
   public:
   // Send an IR command
   // Type is 0 for TV, 1 for BD
   // Device is 0x0707 for TV, 0x301A for BD
   // Crc should be ~Command, except for tests
   static void SendCommand(char Type, unsigned int Device, unsigned int Command, unsigned char Crc)
   {
     byte i;
    
     // Disable interrupts
     cli();
   
     // Start bit
     for (i=0; i<8; i++)	Pulse();
     delayMicroseconds(4500);
 
     // Send Device Id
     SendIRByte(Device>>8);
     SendIRByte(Device&0xff);
 
     // BD Player
     if (Type==1)
     {
       // Stop bit
       Pulse();
       delayMicroseconds(4500);
       // Send Data
       SendIRNibble(Command>>8);
     }
     
     SendIRByte(Command);
     SendIRByte(Crc);
 
     // Stop bit
     Pulse();
     delayMicroseconds(4500);
   
     // Re-enable interrupts
     sei();
   }
   // Read Eeprom
   static void ReadEeprom(byte device, long addr, byte *data, int count)
   {
     if (addr!=0xffffffff)
     {
       Wire.beginTransmission(device);
       if (bEeprom2ByteAddress) Wire.write(addr>>8);
       Wire.write(addr);
       Wire.endTransmission();
     }
     Wire.requestFrom((int)device, count);
     for (int i=0; i<count; i++)
     {
       if (!Wire.available()) break;
       data[i]=Wire.read();
     }
   }
   // Write Eeprom
   static void WriteEeprom(byte device, long addr, byte *data, int count)
   {
     Wire.beginTransmission(device);
     if (bEeprom2ByteAddress) Wire.write(addr>>8);
     Wire.write(addr);
     for (int i=0; i<count; i++) Wire.write(data[i]);
     Wire.endTransmission();
   }
   static boolean bEeprom2ByteAddress;
 };
 boolean Samsung::bEeprom2ByteAddress=true;
 
 
 // ---------------------------------------------------------------------
 // Initialization
 // ---------------------------------------------------------------------
 
 void setup()
 {
   // Led
   pinMode(LEDPIN, OUTPUT);
   digitalWrite(LEDPIN, HIGH);
 
   // IR Led
   pinMode(IRPIN, OUTPUT);
   digitalWrite(IRPIN, HIGH);
 
   // I2C
   Wire.begin();
 
   // Serial Console
   Serial.begin(115200);
 
   // Initialize Ethernet. Try DHCP, otherwise static IP
   if (Ethernet.begin(mac)==0)
     Ethernet.begin(mac, ip);
   // Initialize HTTP server
   HttpServer.begin();
   // Initialize Telnet server
   TelnetServer.begin();
   #ifdef SAMSUNGREMOTE
   // Initialize Samsung Remote server
   SamsungRemote.begin();
   // Initialize SSDP
   SamsungSSDP.begin(1900);
   #endif
 }
 
 
 // ---------------------------------------------------------------------
 // Main Program
 // ---------------------------------------------------------------------
 
 char HttpFrame[256];           // General buffer for Http and Samsung protocol frames
 char TelnetFrame[256];         // General buffer for Telnet frames
 char Buffer[32];               // General buffer
 boolean iStateLed=false;       // Used for led blinking
 unsigned long timeLastLedMs=0; // Used for blinking delay
 
 void loop()
 {
   // -------------------------------------------------
   // LED blinks at 2Hz
   // -------------------------------------------------
   if (millis()>timeLastLedMs+250)
   {
     timeLastLedMs=millis();
     digitalWrite(LEDPIN, (iStateLed) ? HIGH:LOW);
     iStateLed=!iStateLed;
   }
 
   // -------------------------------------------------
   // Handle HTTP requests
   // Example : 
   //   To send KEY_1 on BD :
   //   http://IP/ir.htm?data=81&type=1&device=301a
   // -------------------------------------------------
   EthernetClient client = HttpServer.available();
   if (client) 
   {
     char *ptr=HttpFrame;
     int n=0;
     while (client.connected() && client.available())
     {
       if (n++<sizeof(HttpFrame))
         *ptr++=client.read();
       else
         client.flush(); 
     }
     *ptr=0;
     if (n>0)
     {
       const __FlashStringHelper *HtmlHeader=F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
 
       // -------------------------------------------------
       // Send Samsung IR command
       // -------------------------------------------------
       ptr=strstr(HttpFrame, "/ir.htm?");
       if (ptr)
       {
         byte Type=0, Crc;
         unsigned int Device=0x0707, Data=0;
 
         ptr=strstr(HttpFrame, "data=");
         if (ptr) Data=HexToULong(ptr+5);
         ptr=strstr(HttpFrame, "type=");
         if (ptr) Type=HexToULong(ptr+5);
         ptr=strstr(HttpFrame, "device=");
         if (ptr) Device=HexToULong(ptr+7);
         
         // Next parameter is optional and can be used for tests
         Crc=~Data;
         ptr=strstr(HttpFrame, "crc=");
         if (ptr) Crc=HexToULong(ptr+4);
 
         Samsung::SendCommand(Type, Device, Data, Crc);
         client.println(HtmlHeader);
         client.println("OK !");
         client.stop();
         return;
       }
 
       // -------------------------------------------------
       // Read Eeprom
       // -------------------------------------------------
       ptr=strstr(HttpFrame, "/read");
       if (ptr)
       {
         byte Device=80, Format=0x50; // hedak: changed eeprom device id to 80 to comply with description above
         unsigned long Size=0x100, Addr=0;
 
         ptr=strstr(HttpFrame, "addr=");
         if (ptr) Addr=HexToULong(ptr+5);
         ptr=strstr(HttpFrame, "size=");
         if (ptr) Size=atol(ptr+5);
         ptr=strstr(HttpFrame, "device=");
         if (ptr) Device=atoi(ptr+7);
         ptr=strstr(HttpFrame, "format=");
         if (ptr) Format=atoi(ptr+7);
         ptr=strstr(HttpFrame, "width=8");
         Samsung::bEeprom2ByteAddress=(ptr==0);
 
         if (Format==0) 
         {
           client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
         }
         else
           client.println("HTTP/1.1 200 OK\r\nContent-Type: binary/octet-stream\r\n");
 
         byte bSequential=0;    
         for (long i=Addr; i<Addr+Size; i+=32)
         {
           unsigned char Data[32]; 
           for (int i=0; i<32; i++) Data[i]=0xff;
           Samsung::ReadEeprom(Device, (bSequential) ? -1:i, Data, 32);
           bSequential=1;
 
           if (Format==0)
           {          
             sprintf(Buffer, "%04lx: ", i); client.print(Buffer);
             for (int j=0; j<32; j++)
               { sprintf(Buffer, "%02X ", Data[j]); client.print(Buffer); }
             for (int j=0; j<32; j++)
               { client.write((Data[j]<=0x20 || Data[j]>0x7f) ? '.':Data[j]); }
             client.println("");
             client.flush();
           }
           else
           {
             for (int j=0; j<32; j++)
               client.write(Data[j]);
           }
         }
 
         client.stop();
         return;
       }
 
       // -------------------------------------------------
       // Write Eeprom
       // -------------------------------------------------
       ptr=strstr(HttpFrame, "/write");
       char *ptrAddr=strstr(HttpFrame, "addr=");
       char *ptrData=strstr(HttpFrame, "data=");
       if (ptr && ptrAddr && ptrData)
       {
         byte Device=80, Data; // hedak: changed eeprom device id to 80 to comply with description above
         unsigned long Addr;
         
         Addr=HexToULong(ptrAddr+5);
         Data=HexToULong(ptrData+5);
         ptr=strstr(HttpFrame, "device=");
         if (ptr) Device=atoi(ptr+7);
         ptr=strstr(HttpFrame, "width=8");
         Samsung::bEeprom2ByteAddress=(ptr==0);
 
         Samsung::WriteEeprom(Device, Addr, &Data, 1);
         client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
         Data=~Data;
         Samsung::ReadEeprom(Device, Addr, &Data, 1);    
         sprintf(Buffer, "%02X ", Data); 
         client.print(Buffer);
 
         client.stop();
         return;
       }
 
       #ifdef SAMSUNGREMOTE
       // -------------------------------------------------
       // Device info - used for Samsung Remote Protocol
       // -------------------------------------------------
       ptr=strstr(HttpFrame, "/smp_2_");
       if (ptr)
       {
         client.println(F("HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n"));
         client.println(F("<?xml version=\"1.0\"?>"));
         client.println(F("<root xmlns='urn:schemas-upnp-org:device-1-0' xmlns:sec='http://www.sec.co.kr/dlna' xmlns:dlna='urn:schemas-dlna-org:device-1-0'>"));
         client.println(F(" <specVersion>"));
         client.println(F("  <major>1</major>"));
         client.println(F("  <minor>0</minor>"));
         client.println(F(" </specVersion>"));
         client.println(F(" <device>"));
         client.println(F("  <deviceType>urn:samsung.com:device:RemoteControlReceiver:1</deviceType>"));
         client.println(F("  <friendlyName>SamyGO</friendlyName>"));
         client.println(F("  <manufacturer>Samsung Electronics</manufacturer>"));
         client.println(F("  <manufacturerURL>http://www.samsung.com/sec</manufacturerURL>"));
         client.println(F("  <modelDescription>Samsung BD RCR</modelDescription>"));
         client.println(F("  <modelName>BD-E8500</modelName>"));
         client.println(F("  <modelNumber>1.0</modelNumber>"));
         client.println(F("  <modelURL>http://www.samsung.com/sec</modelURL>"));
         client.println(F("  <serialNumber>12345678RCR</serialNumber>"));
         client.println(F("  <UDN>uuid:11111111-2222-3333-4444-555555555555</UDN>"));
         client.println(F("  <sec:deviceID>ABCDEFGHIJKLM</sec:deviceID>"));
         client.println(F("  <sec:ProductCap>Resolution:1280X720,ImageZoom,ImageRotate,Y2012</sec:ProductCap>"));
         client.println(F("  <serviceList>"));
         client.println(F("   <service>"));
         client.println(F("    <serviceType>urn:samsung.com:service:TestRCRService:1</serviceType>"));
         client.println(F("    <serviceId>urn:samsung.com:serviceId:TestRCRService</serviceId>"));
         client.println(F("    <controlURL>/smp_4_</controlURL>"));
         client.println(F("    <eventSubURL>/smp_5_</eventSubURL>"));
         client.println(F("    <SCPDURL>/smp_3_</SCPDURL>"));
         client.println(F("   </service>"));
         client.println(F("  </serviceList>"));
         client.println(F(" </device>"));
         client.println(F("</root>"));
         client.stop();
         return;
       }
       #endif
 
       // send an error !
       client.println(HtmlHeader);
       client.println(F("Error !"));
       delay(1);
     }
     client.stop();
   }
 
   #ifdef SAMSUNGREMOTE
   // -------------------------------------------------
   // Samsung Remote Protocol
   // -------------------------------------------------
   client = SamsungRemote.available();
   if (client) 
   {
     //Serial.println("Incoming frame...");
     
     // Read incoming frame
     char *ptr=HttpFrame;
     int n=0;
     while (client.connected() && client.available())
       if (n++<sizeof(HttpFrame)) *ptr++=client.read();
 
 
     ptr=HttpFrame+1;
     // Decode App Name
     ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), false);
     //Serial.print("Name="); Serial.println(Buffer);
 
     // Ignore message length
     ptr+=2;
 
     // Decode command
     unsigned Cmd=*ptr++; Cmd|=(*ptr++)<<8;
     //Serial.print("Cmd="); Serial.println(Cmd);
 
     // Connection frame ?
     if (Cmd==0x64)
     {
       // Decode remote IP
       ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
       //Serial.print("IP="); Serial.println(Buffer);
 
       // Decode remote MAC address
       ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
       //Serial.print("MAC="); Serial.println(Buffer);
 
       // Decode machine name
       ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
       //Serial.print("Machine="); Serial.println(Buffer);
       delay(5);
     }
 
     // Key frame ?
     else if (Cmd==0x00)
     {
       ptr++; // Skip first byte
       ptr+=DecodeSamsungProtocolString(ptr, Buffer, sizeof(Buffer), true);
       //Serial.print("KeyName="); Serial.print(Buffer); Serial.println("----");
       if (!strcmp(Buffer, "BD_KEY_POWER"))
       {
         // Power key for BD
         Samsung::SendCommand(1, 0x301a, 0x91, ~0x91);
       }
     }
 
     // Answer
     HttpFrame[0]=0;
     int len=1;
     len+=EncodeSamsungProtocolString("iapp.samsung", HttpFrame+1, sizeof(HttpFrame), false);
     if (Cmd==0x64)
     {
       byte answer[]={0x04,0x00,0x64,0x00,0x01,0x00};
       memcpy(HttpFrame+len, answer, sizeof(answer));
       len+=sizeof(answer);
     }
     else
     {
       byte answer[]={0x04,0x00,0x00,0x00,0x00,0x00};
       memcpy(HttpFrame+len, answer, sizeof(answer));
       len+=sizeof(answer);
     }
     client.write((byte *)HttpFrame, len);
     delay(5);
   }
 
   // SSDP discovery protocol
   int PacketSize=SamsungSSDP.parsePacket();
   if (PacketSize)
   {
     // Read incoming frame
     char *ptr=HttpFrame;
     int n=0;
     while (SamsungSSDP.available())
       if (n++<sizeof(HttpFrame)) *ptr++=SamsungSSDP.read();
 
     // Discovery request ?
     if (strstr(HttpFrame, "M-SEARCH *") && strstr(HttpFrame, "urn:samsung.com:device:RemoteControlReceiver:1"))
     {
       //Serial.print("SSDP Discovery from : IP="); Serial.print(SamsungSSDP.remoteIP()); Serial.print(":"); Serial.println(SamsungSSDP.remotePort());
       SamsungSSDP.beginPacket(SamsungSSDP.remoteIP(), SamsungSSDP.remotePort());
       SamsungSSDP.println(F("HTTP/1.1 200 OK"));
       SamsungSSDP.println(F("CACHE-CONTROL: max-age= 1800"));
       SamsungSSDP.println(F("Date: Sat, 01 Jan 2012 00:00:00 GMT"));
       SamsungSSDP.println(F("EXT: "));
       SamsungSSDP.print(F("LOCATION: http://")); SamsungSSDP.print(Ethernet.localIP()); SamsungSSDP.println(F(":80/smp_2_"));
       SamsungSSDP.println(F("SERVER: SHP, UPnP/1.0, Samsung UPnP SDK/1.0"));
       SamsungSSDP.println(F("ST: urn:samsung.com:device:RemoteControlReceiver:1"));
       SamsungSSDP.println(F("USN: uuid:11111111-2222-3333-4444-555555555555::urn:samsung.com:device:RemoteControlReceiver:1"));
       SamsungSSDP.println(F("Content-Length: 0"));
       SamsungSSDP.endPacket();
     }
   }
   #endif
 
   // -------------------------------------------------
   // Telnet Serial Console Interface
   // Configure Putty with :
   //   - "Local Echo : Force off"
   //   - "Local line editing : Force off"
   // -------------------------------------------------
   client = TelnetServer.available();
   if (client) 
   {
     char *ptr=TelnetFrame;
     int n=0;
     while (client.connected() && client.available())
       if (n++<sizeof(TelnetFrame)) *ptr++=client.read();
     *ptr=0;
     
     // Sends telnet buffer to Serial Console
     if (n>0) Serial.write(TelnetFrame);
   }
   // Anything received from Serial Console ?
   char *ptr=TelnetFrame;
   int n=0;
   while (Serial.available())
     if (n++<sizeof(TelnetFrame)) *ptr++=Serial.read();
   *ptr=0;
     // Send it to telnet
   if (n>0) TelnetServer.write(TelnetFrame);
 }
 
 // ---------------------------------------------------------------------

Teensy(++ 2.0) sketch for accessing I2C interface

This sketch has been compiled with Arduino 1.0.5. It's a limited version compared to the arduino sketch above. Only the I2C interface to read/write tv's eeprom is implemented and instead of the ethernet interface there's a usb interface (Hint: sketch becomes active only if DTR on pc side is set). Usage of the I2C feature is the same anyway.

// ---------------------------------------------------------------------
// Samsung I2C interface based on oga83's 'Samsung multi-functions ethernet interface' v1.2
//   - Read & Write I2C config eeprom
//
// 07-03-2014 / v1.1 / hedak
//----------------------------------------------------------------------

#include <SPI.h>
#include <Wire.h>
#include "utility\twi.h" //hedak: for outputting I2C frequency

#define CPU_PRESCALE(n)	(CLKPR = 0x80, CLKPR = (n))

#define LEDPIN     CORE_LED0_PIN    // Onboard led - blink at 2 Hz
                        // I2C Eeprom : SDA connected on D1
                        // I2C Eeprom : SCL connected on D0

// ---------------------------------------------------------------------
// Utilities
// ---------------------------------------------------------------------

// Convert a hex string to unsigned int
unsigned long HexToULong(char *s)
{
  unsigned long u=0;
  while (*s)
  {
    char c=*s++;
    // Convert to uppercase
    if (c>='a') c&=0xdf;
    // Exit if not hex digit
    if ((c<'0' || c>'9') && (c<'A' || c>'F')) break;
    // Convert digit
    u<<=4;
    u|=c-((c>'9') ? 'A'-0xa:'0');
  }
  return u;
}


// ---------------------------------------------------------------------
// Samsung class
// ---------------------------------------------------------------------

class Samsung
{
  public:
  // Read Eeprom
  static void ReadEeprom(byte device, long addr, byte *data, int count)
  {
    if (addr!=0xffffffff)
    {
      Wire.beginTransmission(device);
      if (bEeprom2ByteAddress) Wire.write(addr>>8);
      Wire.write(addr);
      Wire.endTransmission();
    }
    Wire.requestFrom((int)device, count);
    for (int i=0; i<count; i++)
    {
      if (!Wire.available()) break;
      data[i]=Wire.read();
    }
  }
  // Write Eeprom
  static void WriteEeprom(byte device, long addr, byte *data, int count)
  {
    Wire.beginTransmission(device);
    if (bEeprom2ByteAddress) Wire.write(addr>>8);
    Wire.write(addr);
    for (int i=0; i<count; i++) Wire.write(data[i]);
    Wire.endTransmission();
  }
  static boolean bEeprom2ByteAddress;
};
boolean Samsung::bEeprom2ByteAddress=true; 

// ---------------------------------------------------------------------
// Main Program
// ---------------------------------------------------------------------

char HttpFrame[256];           // General buffer for Http and Samsung protocol frames
char Buffer[32];               // General buffer
boolean iStateLed=false;       // Used for led blinking
unsigned long timeLastLedMs=0; // Used for blinking delay

void loop()
{
  // -------------------------------------------------
  // LED blinks at 2Hz
  // -------------------------------------------------
  if (millis()>timeLastLedMs+250)
  {
    timeLastLedMs=millis();
    digitalWrite(LEDPIN, (iStateLed) ? HIGH:LOW);
    iStateLed=!iStateLed;
  }

  // -------------------------------------------------
  // Handle HTTP requests
  // Example : 
  //   To read a whole EEPROM dump :
  //   http://IP/read?format=1&device=80&size=256
  // -------------------------------------------------
    char *ptr=HttpFrame;
    int n=0;
    while (Serial.available())
    {
      if (n++<sizeof(HttpFrame))
        *ptr++=Serial.read();
      else
        Serial.flush(); 
    }
    *ptr=0;
    Serial.write(HttpFrame);
    if (n>0)
    {
      // -------------------------------------------------
      // Read Eeprom
      // -------------------------------------------------
      ptr=strstr(HttpFrame, "/read");
      if (ptr)
      {
        byte Device=80, Format=0x50; // hedak: fixed wrong default value for 'Device'
        unsigned long Size=0x100, Addr=0;

        ptr=strstr(HttpFrame, "addr=");
        if (ptr) Addr=HexToULong(ptr+5);
        ptr=strstr(HttpFrame, "size=");
        if (ptr) Size=atol(ptr+5);
        ptr=strstr(HttpFrame, "device=");
        if (ptr) Device=atoi(ptr+7);
        ptr=strstr(HttpFrame, "format=");
        if (ptr) Format=atoi(ptr+7);
        ptr=strstr(HttpFrame, "width=8");
        Samsung::bEeprom2ByteAddress=(ptr==0);

        sprintf(Buffer, "Start reading @ address: %lX\r\n", Addr);
        Serial.write(Buffer);
        
        if (Format==0) 
        {
          Serial.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
        }
        else
          Serial.write("HTTP/1.1 200 OK\r\nContent-Type: binary/octet-stream\r\n");

        byte bSequential=0;    
        for (long i=Addr; i<Addr+Size; i+=32)
        {
          unsigned char Data[32]; 
          for (int i=0; i<32; i++) Data[i]=0xff;
          Samsung::ReadEeprom(Device, (bSequential) ? -1:i, Data, 32);
          bSequential=1;

          if (Format==0)
          {          
            sprintf(Buffer, "%04lx: ", i); Serial.write(Buffer);
            for (int j=0; j<32; j++)
              { sprintf(Buffer, "%02X ", Data[j]); Serial.write(Buffer); }
            for (int j=0; j<32; j++)
              { Serial.write((Data[j]<=0x20 || Data[j]>0x7f) ? '.':Data[j]); }
            Serial.write("\r\n");
            Serial.flush();
          }
          else
          {
            for (int j=0; j<32; j++)
              Serial.write(Data[j]);
          }
        }
        return;
      }

      // -------------------------------------------------
      // Write Eeprom
      // -------------------------------------------------
      ptr=strstr(HttpFrame, "/write");
      Serial.write("Remove the following 'return;' line to activate write feature!\r\n");
      return;
      char *ptrAddr=strstr(HttpFrame, "addr=");
      char *ptrData=strstr(HttpFrame, "data=");
      if (ptr && ptrAddr && ptrData)
      {
        byte Device=0, Data;
        unsigned long Addr;
        
        Addr=HexToULong(ptrAddr+5);
        Data=HexToULong(ptrData+5);
        ptr=strstr(HttpFrame, "device=");
        if (ptr) Device=atoi(ptr+7);
        ptr=strstr(HttpFrame, "width=8");
        Samsung::bEeprom2ByteAddress=(ptr==0);

        Samsung::WriteEeprom(Device, Addr, &Data, 1);
        Serial.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
        Data=~Data;
        Samsung::ReadEeprom(Device, Addr, &Data, 1);    
        sprintf(Buffer, "%02X ", Data); 
        Serial.write(Buffer);
        return;
      }
      // send an error !
      Serial.write("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
      Serial.write("Error !\r\n");
      delay(1);
    }
}

// ---------------------------------------------------------------------
// Initialization
// ---------------------------------------------------------------------

void setup()
{
#if (F_CPU == 8000000)
   // set for 8 MHz clock because of operating at 3.3 volts
   CPU_PRESCALE(0x01);
#else
   // set for external 16 MHz clock
   CPU_PRESCALE(0x00);
#endif
  // Led
  pinMode(LEDPIN, OUTPUT);
  digitalWrite(LEDPIN, HIGH);

  // I2C
  Wire.begin();

  // Serial Console
  Serial.begin(115200);
  
  // wait for the user to run their terminal emulator program
  // which sets DTR to indicate it is ready to receive.
  while (!Serial.dtr()) /* wait */ ;
  sprintf(Buffer, "TWI_FREQ: %ld", TWI_FREQ);
  Serial.write(Buffer);
}

// ---------------------------------------------------------------------

References

Any discussion on related forum topic. Thread using teensy sketch is here.