Difference between revisions of "Ethernet multi-function Interface"


From SamyGO
Jump to: navigation, search
(How to use it)
(Added Config Eeprom interface)
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
  
  
Line 27: Line 28:
 
* 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 to RX/TX on the Arduino board (with 100 ohms resistors)
+
* 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
+
* 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 a 100 ohms resistors)
 +
* Connect the eeprom GND to 0v
  
 
== URL format to send IR codes ==
 
== URL format to send IR codes ==
Line 44: Line 48:
  
  
== Examples ==
+
For example:
 +
 
 +
 
 
To get the Service Menu on your TV, use the 2 following URLs :
 
To get the Service Menu on your TV, use the 2 following URLs :
 
* http://IP/ir.htm?data=1F&type=0&device=0707
 
* http://IP/ir.htm?data=1F&type=0&device=0707
Line 58: Line 64:
 
* On a TV : http://IP/ir.htm?data=65&type=0&device=0707
 
* On a TV : http://IP/ir.htm?data=65&type=0&device=0707
 
* On a BD : http://IP/ir.htm?data=81&type=0&device=301A
 
* On a BD : http://IP/ir.htm?data=81&type=0&device=301A
 +
 +
 +
== URL format to read config Eeprom ==
 +
The format is http://IP/read?read?format=F&device=D&addr=A&size=S
 +
 +
* 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)
 +
 +
 +
For example:
 +
 +
 +
BD-E8300 is equiped with a 24512 eeprom (64 kbytes)
 +
 +
To download its whole config :
 +
* http://IP/ir.htm?read?format=1&size=65536
 +
or :
 +
* http://IP/ir.htm?read?format=1&device=80&size=65536&addr=0
 +
 +
 +
Eeprom connection :
 +
 +
[[File:Arduino_I2C_Eeprom.jpg|335px]]
  
  
Line 73: Line 105:
 
A frame for BD :
 
A frame for BD :
  
[[File:BD IR Frame Format.jpg|335px‎]]
+
[[File:BD IR Frame Format.jpg|100px‎]]
  
  
Line 79: Line 111:
  
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
   // Samsung IR and Serial Console Ethernet Interface
+
   // Samsung multi-functions ethernet interface
   // 29-06-2012 / Initial version / oga83
+
  //  - 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
 
   //----------------------------------------------------------------------
 
   //----------------------------------------------------------------------
 
    
 
    
 
   #include <SPI.h>
 
   #include <SPI.h>
 
   #include <Ethernet.h>
 
   #include <Ethernet.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 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
 
   byte mac[] = { 0x90, 0xA2, 0xda, 0x00, 0xe6, 0x5e }; // Arduino Ethernet board MAC address
Line 95: Line 140:
 
   EthernetServer TelnetServer(23); // Telnet is used for Serial Console
 
   EthernetServer TelnetServer(23); // Telnet is used for Serial Console
 
    
 
    
 +
 
 +
  // ---------------------------------------------------------------------
 +
  // Utilities
 +
  // ---------------------------------------------------------------------
 
    
 
    
 
   // Convert a hex string to unsigned int
 
   // Convert a hex string to unsigned int
   unsigned int HexToUInt(char *s)
+
   unsigned int HexToULong(char *s)
 
   {
 
   {
    unsigned 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;
 
   }
 
   }
 
 
 
    
 
    
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
Line 121: Line 169:
 
   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
    static void SendCommand(char Type, unsigned int Device, unsigned int Command)
+
  // Crc should be ~Command, except for tests
    {
+
  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(~Command);
+
  SendIRByte(Crc);
 
    
 
    
      // Stop bit
+
  // Stop bit
      Pulse();
+
  Pulse();
      delayMicroseconds(4500);
+
  delayMicroseconds(4500);
 
      
 
      
      // Re-enable interrupts
+
  // Re-enable interrupts
      sei();
+
  sei();
    }
+
  }
 +
  // Read Eeprom
 +
  static void ReadEeprom(byte device, long addr, byte *data, int count)
 +
  {
 +
  if (addr!=0xffffffff)
 +
  {
 +
  Wire.beginTransmission(device);
 +
  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);
 +
  Wire.write(addr>>8);
 +
  Wire.write(addr);
 +
  for (int i=0; i<count; i++) Wire.write(data[i]);
 +
  Wire.endTransmission();
 +
  }
 
   };
 
   };
 
    
 
    
Line 206: Line 281:
 
   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);
 
    
 
    
    // IR Led
+
  // I2C
    pinMode(IRPIN, OUTPUT);
+
  Wire.begin();
    digitalWrite(IRPIN, HIGH);
 
 
    
 
    
    // Serial Console
+
  // Serial Console
    Serial.begin(115200);
+
  Serial.begin(115200);
 
    
 
    
    // Initialize Ethernet. Try DHCP, otherwise static IP
+
  // Initialize Ethernet. Try DHCP, otherwise static IP
    if (Ethernet.begin(mac)==0)
+
  if (Ethernet.begin(mac)==0)
      Ethernet.begin(mac, ip);
+
  Ethernet.begin(mac, ip);
    // Initialize HTTP server
+
  // Initialize HTTP server
 
    
 
    
    HttpServer.begin();
+
  HttpServer.begin();
    // Initialize Telnet server
+
  // Initialize Telnet server
    TelnetServer.begin();
+
  TelnetServer.begin();
 
   }
 
   }
 
    
 
    
Line 232: Line 310:
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------
 
    
 
    
   char NetworkFrame[256];       // General buffer for frames
+
   char HttpFrame[256];           // General buffer for Http frames
 +
  char TelnetFrame[256];        // General buffer for Telnet frames
 +
  char Buffer[32];              // General buffer
 
   boolean iStateLed=false;      // Used for led blinking
 
   boolean iStateLed=false;      // Used for led blinking
 
   unsigned long timeLastLedMs=0; // Used for blinking delay
 
   unsigned long timeLastLedMs=0; // Used for blinking delay
Line 238: Line 318:
 
   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
 +
  // 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)
 +
  {
 +
  __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=0, Format=0x50;
 +
  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);
 +
 
 +
  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<Size; i+=32)
 +
  {
 +
  unsigned char Data[32];
 +
  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;
 +
  }
 
    
 
    
    // -------------------------------------------------
+
  // -------------------------------------------------
    // Handle HTTP requests
+
  // Write Eeprom
    // Example :
+
  // -------------------------------------------------
    //  To send KEY_1 on BD :
+
  ptr=strstr(HttpFrame, "/write");
    //  http://IP/ir.htm?data=81&type=1&device=301a
+
  char *ptrAddr=strstr(HttpFrame, "addr=");
    // -------------------------------------------------
+
  char *ptrData=strstr(HttpFrame, "data=");
    EthernetClient client = HttpServer.available();
+
  if (ptr && ptrAddr && ptrData)
    if (client)  
+
  {
    {
+
  byte Device=0, Data;
      char *ptr=NetworkFrame;
+
  unsigned long Addr;
      int n=0;
+
            
      while (client.connected() && client.available())
+
  Addr=HexToULong(ptrAddr+5);
      {
+
  Data=HexToULong(ptrData+5);
        if (n++<sizeof(NetworkFrame))
+
  ptr=strstr(HttpFrame, "device=");
           *ptr++=client.read();
+
  if (ptr) Device=atoi(ptr+7);
        else
 
          client.flush();  
 
      }
 
      *ptr=0;
 
      if (n>0)
 
      {
 
        __FlashStringHelper *Header=F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
 
 
    
 
    
        // -------------------------------------------------
+
  Samsung::WriteEeprom(Device, Addr, &Data, 1);
        // Samsung IR command
+
  client.println("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n");
        // -------------------------------------------------
+
  Data=~Data;
        ptr=strstr(NetworkFrame, "/ir.htm?data=");
+
  Samsung::ReadEeprom(Device, Addr, &Data, 1);  
        if (ptr)
+
  sprintf(Buffer, "%02X ", Data);  
        {
+
  client.print(Buffer);
          ptr+=13;
 
          byte Type=0;
 
          unsigned int Device=0x0707, Data=HexToUInt(ptr);
 
          ptr=strstr(ptr, "type=");
 
          if (ptr) Type=HexToUInt(ptr+5);
 
          ptr=strstr(ptr, "device=");
 
          if (ptr) Device=HexToUInt(ptr+7);
 
 
    
 
    
          Samsung::SendCommand(Type, Device, Data);
+
  client.stop();
          client.println(Header);
+
  return;
          client.println("OK !");
+
  }
          delay(100);
 
          client.stop();
 
          return;
 
        }
 
 
    
 
    
        // send an error !
+
  // send an error !
        client.println(Header);
+
  client.println(HtmlHeader);
        client.println(F("Error !"));
+
  client.println(F("Error !"));
        delay(1);
+
  delay(1);
      }
+
  }
      client.stop();
+
  client.stop();
    }
+
  }
 
    
 
    
    // -------------------------------------------------
+
  // -------------------------------------------------
    // Telnet Serial Console Interface
+
  // Telnet Serial Console Interface
    // Configure Putty with :
+
  // Configure Putty with :
    //  - "Local Echo : Force off"
+
  //  - "Local Echo : Force off"
    //  - "Local line editing : Force off"
+
  //  - "Local line editing : Force off"
    // -------------------------------------------------
+
  // -------------------------------------------------
    client = TelnetServer.available();
+
  client = TelnetServer.available();
    if (client)  
+
  if (client)  
    {
+
  {
      char *ptr=NetworkFrame;
+
  char *ptr=TelnetFrame;
      int n=0;
+
  int n=0;
      while (client.connected() && client.available())
+
  while (client.connected() && client.available())
        if (n++<sizeof(NetworkFrame)) *ptr++=client.read();
+
  if (n++<sizeof(TelnetFrame)) *ptr++=client.read();
      *ptr=0;
+
  *ptr=0;
 
        
 
        
      // Sends telnet buffer to Serial Console
+
  // Sends telnet buffer to Serial Console
      if (n>0) Serial.write(NetworkFrame);
+
  if (n>0) Serial.write(TelnetFrame);
    }
+
  }
    // Anything received from Serial Console ?
+
  // Anything received from Serial Console ?
    char *ptr=NetworkFrame;
+
  char *ptr=TelnetFrame;
    int n=0;
+
  int n=0;
    while (Serial.available())
+
  while (Serial.available())
      if (n++<sizeof(NetworkFrame)) *ptr++=Serial.read();
+
  if (n++<sizeof(TelnetFrame)) *ptr++=Serial.read();
    *ptr=0;
+
  *ptr=0;
      // Send it to telnet
+
  // Send it to telnet
    if (n>0) TelnetServer.write(NetworkFrame);
+
  if (n>0) TelnetServer.write(TelnetFrame);
 
   }
 
   }
 
    
 
    
 
   // ---------------------------------------------------------------------
 
   // ---------------------------------------------------------------------

Revision as of 17:12, 11 September 2012

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.


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 config eeprom


Arduino interface.jpg


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 a 100 ohms resistors)
* Connect the eeprom GND to 0v

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?read?format=F&device=D&addr=A&size=S

  • 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)


For example:


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

To download its whole config :

or :


Eeprom connection :

Arduino I2C Eeprom.jpg


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 :

100px‎


Arduino sketch

 // ---------------------------------------------------------------------
 // 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
 //----------------------------------------------------------------------
 
 #include <SPI.h>
 #include <Ethernet.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
 
 
 // ---------------------------------------------------------------------
 // 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;
 }
 
 // ---------------------------------------------------------------------
 // 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);
 		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);
 	Wire.write(addr>>8);
 	Wire.write(addr);
 	for (int i=0; i<count; i++) Wire.write(data[i]);
 	Wire.endTransmission();
 	}
 };
 
 
 // ---------------------------------------------------------------------
 // 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();
 }
 
 
 // ---------------------------------------------------------------------
 // Main Program
 // ---------------------------------------------------------------------
 
 char HttpFrame[256];           // General buffer for Http 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)
 	{
 		__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=0, Format=0x50;
 		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);
 
 		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<Size; i+=32)
 		{
 			unsigned char Data[32]; 
 			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=0, Data;
 		unsigned long Addr;
         
 		Addr=HexToULong(ptrAddr+5);
 		Data=HexToULong(ptrData+5);
 		ptr=strstr(HttpFrame, "device=");
 		if (ptr) Device=atoi(ptr+7);
 
 		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;
 		}
 
 		// send an error !
 		client.println(HtmlHeader);
 		client.println(F("Error !"));
 		delay(1);
 	}
 	client.stop();
 	}
 
 	// -------------------------------------------------
 	// 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);
 }
 
 // ---------------------------------------------------------------------