Join Us and become a Member for a Verified Badge to access private areas with the latest PS4 PKGs.
Status
Not open for further replies.
I managed to get some time to goto my local Jaycar store and pickup some ESP8266 boards and some SD breakout boards.

I have put together a small example of a webserver with the files hosted off a SD card. Using an SD card allows you to update the payloads without needing to flash the ESP board and it allows you to have more than around 4MB of files because the ESP boards have a low amount of storage memory. It also has a DNS server built in so you can use it via the user guide on the PS4.

You can also configure the webserver and wifi access point from a file on the SD card with CONFIG.INI.

The Arduino SD library is limited to 8:3 file name format which means all the file names must be 8 characters or less and the file extension must be 3 characters or less, this would be the limit FILENAME.TXT

:alert: Make sure you use a SD card that is formatted to fat or fat32.

On my board (d1 mini compatible) the following pins are used with the SD breakout board
  • D5 = SCK
  • D6 = MISO
  • D7 = MOSI
  • D8 = SS
ESP8266 Server From SD Card for PS4 4.55 Payloads by Stooged 2.jpg

You can find datasheets online for all the different types of boards so you should be able to find the pins you need to connect to.

The ino sketch and SD files are here: https://github.com/stooged/ESP-Server

ESP8266 Server From SD Card for PS4 4.55 Payloads by Stooged.jpg@pearlxcore has a guide here on how to program the ESP8266 board using the Arduino ide.

I might look at opening up one of my PS4s and installing it inside the PS4 and soldering it in because it is pretty small.

ESP8266 Server From SD Card for PS4 4.55 Payloads by Stooged 3.jpg

ESP8266 Server From SD Card for PS4 4.55 Payloads by Stooged 4.jpg
 

Comments

@imedox
cant see much from a .bin but if you are adding sdfat the error you are getting on the update code will be invalid conversion from string to char*

change this line to

Code:
char* firmwareFile = "fwupdate.bin"; //update filename
 
yes adding sdfat changes some of the variables

sdfat does not work with my D1 mini esp8266 :(

but this should work
Code:
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <SPI.h>
#include <SdFat.h>

SdFat sd;
MD5Builder md5;
DNSServer dnsServer;
ESP8266WebServer webServer;


SoftwareSerial uartSerial(0, 2);  // pins 0 and 2 are used here as they translate to pins D3 and D4 on the "D1 Mini board"
WiFiServer uartServer(24);       // you will need to change these pins to suit pins you select on your esp board for uart RX/TX
WiFiClient uartClient;          // the uart socket port is 24 its best to just leave this unless you need to change it for some reason

char* firmwareFile = "fwupdate.bin"; //update filename
String firmwareVer = "1.05";
int hassd = 0;

//------default settings if config.ini is missing------//
String AP_SSID = "PS4_WEB_AP";
String AP_PASS = "password";
int DNS_PORT = 53;
int WEB_PORT = 80;
int UART_PORT = 24;
IPAddress Server_IP(10,1,1,1);
IPAddress Subnet_Mask(255,255,255,0);
//-----------------------------------------------------//




String split(String str, String from, String to)
{
  String tmpstr = str;
  tmpstr.toLowerCase();
  from.toLowerCase();
  to.toLowerCase();
  int pos1 = tmpstr.indexOf(from);
  int pos2 = tmpstr.indexOf(to, pos1 + from.length());  
  String retval = str.substring(pos1 + from.length() , pos2);
  return retval;
}


bool instr(String str, String search)
{
int result = str.indexOf(search);
if (result == -1)
{
  return false;
}
return true;
}


void returnOK() {
  webServer.send(200, "text/plain", "");
}


void returnFail(String msg) {
  webServer.send(500, "text/plain", msg + "\r\n");
}


bool loadFromSdCard(String path) {
  String dataType = "text/plain";
  if (instr(path,"/document/"))
  {
    path.replace("/document/" + split(path,"/document/","/ps4/") + "/ps4/", "/");
  }
  if (path.endsWith("/")) {
    path += "index.htm";
  }
  if (path.endsWith(".html")) {
    path.replace(".html",".htm");
  }
  if (path.endsWith(".src")) {
    path = path.substring(0, path.lastIndexOf("."));
  } else if (path.endsWith(".htm")) {
    dataType = "text/html";
  } else if (path.endsWith(".css")) {
    dataType = "text/css";
  } else if (path.endsWith(".js")) {
    dataType = "application/javascript";
  } else if (path.endsWith(".png")) {
    dataType = "image/png";
  } else if (path.endsWith(".gif")) {
    dataType = "image/gif";
  } else if (path.endsWith(".jpg")) {
    dataType = "image/jpeg";
  } else if (path.endsWith(".ico")) {
    dataType = "image/x-icon";
  }

  File dataFile = sd.open(path.c_str());
  if (dataFile.isDirectory()) {
    dataFile.close();
    path += "/index.htm";
    dataType = "text/html";
    dataFile = sd.open(path.c_str());
  }

  if (!dataFile) {
    return false;
  }

  if (webServer.hasArg("download")) {
    dataType = "application/octet-stream";
  }

  if (webServer.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}




void handleNotFound() {
  if (hassd == 0){
    webServer.send(200, "text/plain", "\n\nNo sd card found");
    return;
  }
  else if (loadFromSdCard(webServer.uri())) {
    return;
  }
  String message = "\n\n";
  message += "URI: ";
  message += webServer.uri();
  message += "\nMethod: ";
  message += (webServer.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += webServer.args();
  message += "\n";
  for (uint8_t i = 0; i < webServer.args(); i++) {
    message += " NAME:" + webServer.argName(i) + "\n VALUE:" + webServer.arg(i) + "\n";
  }
  webServer.send(404, "text/plain", message);
  Serial.print(message);
}



void handleUart()
{
  if(!uartClient.connected())
  {
    uartClient = uartServer.available();
  }
  else
  {
    if(uartClient.available() > 0)
    {
      char data[1024];
      int cnt = 0;
      while(uartClient.available())
      {
        data[cnt] = uartClient.read();
        cnt++;
      }  
      uartClient.flush();
      String cBuffer = String(data);
      Serial.println(cBuffer);
      //process commands to send
      //uartSerial.print(cBuffer);
    }
   
    while (uartSerial.available() > 0) {
       String sData = uartSerial.readString();  
       Serial.print(sData);
       uartClient.print(sData);
    }
    }
}


void updateFw()
{
  if (sd.exists(firmwareFile)) {
  File updateFile;
  Serial.println("Update file found");
  updateFile = sd.open(firmwareFile, FILE_READ);
 if (updateFile) {
  size_t updateSize = updateFile.size();
   if (updateSize > 0) {  
    md5.begin();
    md5.addStream(updateFile,updateSize);
    md5.calculate();
    String md5Hash = md5.toString();
    Serial.println("Update file hash: " + md5Hash);
    updateFile.close();
    updateFile = sd.open(firmwareFile, FILE_READ);
  if (updateFile) {
  pinMode(BUILTIN_LED, OUTPUT);
  digitalWrite(BUILTIN_LED, LOW);
    uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
    if (!Update.begin(maxSketchSpace, U_FLASH)) {
    Update.printError(Serial);
    digitalWrite(BUILTIN_LED, HIGH);
    updateFile.close();
    return;
    }
    int md5BufSize = md5Hash.length() + 1;
    char md5Buf[md5BufSize];
    md5Hash.toCharArray(md5Buf, md5BufSize) ;
    Update.setMD5(md5Buf);
    Serial.println("Updating firmware...");
   long bsent = 0;
   int cprog = 0;
    while (updateFile.available()) {
    uint8_t ibuffer[1];
    updateFile.read((uint8_t *)ibuffer, 1);
    Update.write(ibuffer, sizeof(ibuffer));
      bsent++;
      int progr = ((double)bsent /  updateSize)*100;
      if (progr >= cprog) {
        cprog = progr + 10;
      Serial.println(String(progr) + "%");
      }
    }
    updateFile.close();
   if (Update.end(true))
  {
  digitalWrite(BUILTIN_LED, HIGH);
  Serial.println("Installed firmware hash: " + Update.md5String());
  Serial.println("Update complete");
  sd.remove(firmwareFile);
  ESP.restart();
  }
  else
  {
    digitalWrite(BUILTIN_LED, HIGH);
    Serial.println("Update failed");
     Update.printError(Serial);
    }
  }
  }
  else {
  Serial.println("Error, file is invalid");
  updateFile.close();
  digitalWrite(BUILTIN_LED, HIGH);
  sd.remove(firmwareFile);
  return;  
  }
  }
  }
  else
  {
    Serial.println("No update file found");
  }
}



void setup(void)
{
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println("Version: " + firmwareVer);

  if (sd.begin(SS)) {
  File iniFile;
  hassd = 1;
 
  if (sd.exists("config.ini")) {
  iniFile = sd.open("config.ini", FILE_READ);
  if (iniFile) {
  String iniData;
    while (iniFile.available()) {
      char chnk = iniFile.read();
      iniData += chnk;
    }
   iniFile.close();
 
   if(instr(iniData,"SSID="))
   {
   AP_SSID = split(iniData,"SSID=","\r\n");
   AP_SSID.trim();
   }
 
   if(instr(iniData,"PASSWORD="))
   {
   AP_PASS = split(iniData,"PASSWORD=","\r\n");
   AP_PASS.trim();
   }
 
   if(instr(iniData,"WEBSERVER_PORT="))
   {
   String strWprt = split(iniData,"WEBSERVER_PORT=","\r\n");
   strWprt.trim();
   WEB_PORT = strWprt.toInt();
   }
 
   if(instr(iniData,"DNSSERVER_PORT="))
   {
   String strDprt = split(iniData,"DNSSERVER_PORT=","\r\n");
   strDprt.trim();
   DNS_PORT = strDprt.toInt();
   }

   if(instr(iniData,"WEBSERVER_IP="))
   {
    String strwIp = split(iniData,"WEBSERVER_IP=","\r\n");
    strwIp.trim();
    Server_IP.fromString(strwIp);
   }

   if(instr(iniData,"SUBNET_MASK="))
   {
    String strsIp = split(iniData,"SUBNET_MASK=","\r\n");
    strsIp.trim();
    Subnet_Mask.fromString(strsIp);
   }
 
    }
  }
  else
  {
    iniFile = sd.open("config.ini", FILE_WRITE);
    if (iniFile) {
    iniFile.print("\r\nSSID=" + AP_SSID + "\r\nPASSWORD=" + AP_PASS + "\r\n\r\nWEBSERVER_IP=" + Server_IP.toString() + "\r\nWEBSERVER_PORT=" + String(WEB_PORT) + "\r\n\r\nDNSSERVER_PORT=" + String(DNS_PORT) + "\r\n\r\nSUBNET_MASK=" + Subnet_Mask.toString() + "\r\n");
    iniFile.close();
    }
  }

  updateFw();
  }
  else
  {
    Serial.println("No sd card found");
    hassd = 0;
  }

  Serial.println("SSID: " + AP_SSID);
  Serial.println("Password: " + AP_PASS);
  Serial.print("\n");
  Serial.println("WEB Server IP: " + Server_IP.toString());
  Serial.println("Subnet: " + Subnet_Mask.toString());
  Serial.println("WEB Server Port: " + String(WEB_PORT));
  Serial.println("DNS Server IP: " + Server_IP.toString());
  Serial.println("DNS Server Port: " + String(DNS_PORT));
  Serial.print("\n\n");

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(Server_IP, Server_IP, Subnet_Mask);
  WiFi.softAP(AP_SSID.c_str(), AP_PASS.c_str());
  Serial.println("WIFI AP started");

  dnsServer.setTTL(30);
  dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
  dnsServer.start(DNS_PORT, "*", Server_IP);
  Serial.println("DNS server started");

  webServer.onNotFound(handleNotFound);
  webServer.begin(WEB_PORT);
  Serial.println("HTTP server started");

  uartSerial.setTimeout(100);
  uartSerial.begin(115200);
  uartServer.begin();
  Serial.println("UART server started");
 
}



void loop(void) {
  dnsServer.processNextRequest();
  webServer.handleClient();
  handleUart();
}
 
@stooged What should I add to the scetch so I don't need to enter for custom DNS server or settings, features automatic redirect, just connect to "PS4_WEB_AP" using "easy setting" then go to [Settings] > [User Guide]
Thank's and regards
 
@boban8

The sketch as it is allows easy / auto config.
You dont need to enter any settings like dns or ip or proxy just allow console to set it all automatically.
 
I joined the @imedox sdFat code inside the @stooged v5 sketch,
and just changed the Wi-Fi name, password and IP.

@stooged you could please keep url redirection style but, add a new one to the PS Vita browser, just to make it easier to access just by clicking on the guide icon. The link is http://manuals.playstation.net/document/pb/psvita/browser/index.html

For HENkaku installation. On the Nintendo Switch I had no problem. Thank you!
Code:
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <SPI.h>
#include <BlockDriver.h>
#include <FreeStack.h>
#include <MinimumSerial.h>
#include <SdFat.h>
#include <SdFatConfig.h>
#include <SysCall.h>

SdFat sd;
DNSServer dnsServer;
ESP8266WebServer webServer;

SoftwareSerial uartSerial(0, 2);  // pins 0 and 2 are used here as they translate to pins D3 and D4 on the "D1 Mini board"
WiFiServer uartServer(24);       // you will need to change these pins to suit pins you select on your esp board for uart RX/TX
WiFiClient uartClient;          // the uart socket port is 24 its best to just leave this unless you need to change it for some reason

String firmwareFile = "fwupdate.bin"; //update filename
String firmwareVer = "1.05";
int hasSD = 0;

//------default settings if config.ini is missing------//
String AP_SSID = "NI_PS4WIFI";
String AP_PASS = "NIPS4WIFI";
int DNS_PORT = 53;
int WEB_PORT = 80;
int UART_PORT = 24;
IPAddress Server_IP(10,10,10,11);
IPAddress Subnet_Mask(255,255,255,0);
//-----------------------------------------------------//




String split(String str, String from, String to)
{
  String tmpstr = str;
  tmpstr.toLowerCase();
  from.toLowerCase();
  to.toLowerCase();
  int pos1 = tmpstr.indexOf(from);
  int pos2 = tmpstr.indexOf(to, pos1 + from.length());  
  String retval = str.substring(pos1 + from.length() , pos2);
  return retval;
}


bool instr(String str, String search)
{
int result = str.indexOf(search);
if (result == -1)
{
  return false;
}
return true;
}


void returnOK() {
  webServer.send(200, "text/plain", "");
}


void returnFail(String msg) {
  webServer.send(500, "text/plain", msg + "\r\n");
}


bool loadFromSdCard(String path) {
  String dataType = "text/plain";
  if (instr(path,"/document/"))
  {
    path.replace("/document/" + split(path,"/document/","/ps4/") + "/ps4/", "/");
  }
  if (path.endsWith("/")) {
    path += "index.html";
  }
  if (path.endsWith(".htm")) {
    path.replace(".htm",".html");
  }
  if (path.endsWith(".src")) {
    path = path.substring(0, path.lastIndexOf("."));
  } else if (path.endsWith(".html")) {
    dataType = "text/html";
  } else if (path.endsWith(".css")) {
    dataType = "text/css";
  } else if (path.endsWith(".js")) {
    dataType = "application/javascript";
  } else if (path.endsWith(".png")) {
    dataType = "image/png";
  } else if (path.endsWith(".gif")) {
    dataType = "image/gif";
  } else if (path.endsWith(".jpg")) {
    dataType = "image/jpeg";
  } else if (path.endsWith(".ico")) {
    dataType = "image/x-icon";
  }

  File dataFile = sd.open(path.c_str());
  if (dataFile.isDirectory()) {
    dataFile.close();
    path += "/index.htm";
    dataType = "text/html";
    dataFile = sd.open(path.c_str());
  }

  if (!dataFile) {
    return false;
  }

  if (webServer.hasArg("download")) {
    dataType = "application/octet-stream";
  }

  if (webServer.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}




void handleNotFound() {
  if (hasSD == 0){
    webServer.send(200, "text/plain", "\n\nNo SD card found");
    return;
  }
  else if (loadFromSdCard(webServer.uri())) {
    return;
  }
  String message = "\n\n";
  message += "URI: ";
  message += webServer.uri();
  message += "\nMethod: ";
  message += (webServer.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += webServer.args();
  message += "\n";
  for (uint8_t i = 0; i < webServer.args(); i++) {
    message += " NAME:" + webServer.argName(i) + "\n VALUE:" + webServer.arg(i) + "\n";
  }
  webServer.send(404, "text/plain", message);
  Serial.print(message);
}



void handleUart()
{
  if(!uartClient.connected())
  {
    uartClient = uartServer.available();
  }
  else
  {
    if(uartClient.available() > 0)
    {
      char data[1024];
      int cnt = 0;
      while(uartClient.available())
      {
        data[cnt] = uartClient.read();
        cnt++;
      }  
      uartClient.flush();
      String cBuffer = String(data);
      Serial.println(cBuffer);
      //process commands to send
      //uartSerial.print(cBuffer);
    }
  
    while (uartSerial.available() > 0) {
       String sData = uartSerial.readString();  
       Serial.print(sData);
       uartClient.print(sData);
    }
    }
}

void setup(void) {

  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println("Version: " + firmwareVer);

  if (sd.begin(SS)) {
  File iniFile;
  hasSD = 1;
 
  if (sd.exists("config.ini")) {
  iniFile = sd.open("config.ini", FILE_READ);
  if (iniFile) {
  String iniData;
    while (iniFile.available()) {
      char chnk = iniFile.read();
      iniData += chnk;
    }
   iniFile.close();
  
   if(instr(iniData,"SSID="))
   {
   AP_SSID = split(iniData,"SSID=","\r\n");
   AP_SSID.trim();
   }
  
   if(instr(iniData,"PASSWORD="))
   {
   AP_PASS = split(iniData,"PASSWORD=","\r\n");
   AP_PASS.trim();
   }
  
   if(instr(iniData,"WEBSERVER_PORT="))
   {
   String strWprt = split(iniData,"WEBSERVER_PORT=","\r\n");
   strWprt.trim();
   WEB_PORT = strWprt.toInt();
   }
  
   if(instr(iniData,"DNSSERVER_PORT="))
   {
   String strDprt = split(iniData,"DNSSERVER_PORT=","\r\n");
   strDprt.trim();
   DNS_PORT = strDprt.toInt();
   }

   if(instr(iniData,"WEBSERVER_IP="))
   {
    String strwIp = split(iniData,"WEBSERVER_IP=","\r\n");
    strwIp.trim();
    Server_IP.fromString(strwIp);
   }

   if(instr(iniData,"SUBNET_MASK="))
   {
    String strsIp = split(iniData,"SUBNET_MASK=","\r\n");
    strsIp.trim();
    Subnet_Mask.fromString(strsIp);
   }
  
    }
  }
  else
  {
    iniFile = sd.open("config.ini", FILE_WRITE);
    if (iniFile) {
    iniFile.print("\r\nSSID=" + AP_SSID + "\r\nPASSWORD=" + AP_PASS + "\r\n\r\nWEBSERVER_IP=" + Server_IP.toString() + "\r\nWEBSERVER_PORT=" + String(WEB_PORT) + "\r\n\r\nDNSSERVER_PORT=" + String(DNS_PORT) + "\r\n\r\nSUBNET_MASK=" + Subnet_Mask.toString() + "\r\n");
    iniFile.close();
   }
  
    }
  }

  Serial.println("SSID: " + AP_SSID);
  Serial.println("Password: " + AP_PASS);
  Serial.print("\n");
  Serial.println("WEB Server IP: " + Server_IP.toString());
  Serial.println("Subnet: " + Subnet_Mask.toString());
  Serial.println("WEB Server Port: " + String(WEB_PORT));
  Serial.println("DNS Server IP: " + Server_IP.toString());
  Serial.println("DNS Server Port: " + String(DNS_PORT));
  Serial.print("\n\n");

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(Server_IP, Server_IP, Subnet_Mask);
  WiFi.softAP(AP_SSID.c_str(), AP_PASS.c_str());
  Serial.println("WIFI AP started");

  dnsServer.setTTL(30);
  dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
  dnsServer.start(DNS_PORT, "*", Server_IP);
  Serial.println("DNS server started");

  webServer.onNotFound(handleNotFound);
  webServer.begin(WEB_PORT);
  Serial.println("HTTP server started");

  uartSerial.setTimeout(100);
  uartSerial.begin(115200);
  uartServer.begin();
  Serial.println("UART server started");
 
}



void loop(void) {
  dnsServer.processNextRequest();
  webServer.handleClient();
  handleUart();
}
 
Status
Not open for further replies.
Back
Top