Difference between revisions of "Ethernet multi-function Interface"
(Added Config Eeprom interface) |
m (moved Ethernet to IR and Serial Console Interface to Ethernet multi-function Interface: Added new functions - title is no more correct) |
(No difference)
|
Revision as of 17:15, 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.
Contents
[hide]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
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 :
- 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
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 :
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 :
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); } // ---------------------------------------------------------------------