Results 1 to 10 of 39

Thread: Project to use a pixelstick type device as a FPP remote.

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Dec 2011
    Location
    UK S80 postcode
    Posts
    1,353
    Post Thanks / Like

    Default Project to use a pixelstick type device as a FPP remote.

    Hi, if you are wondering why an old thread has come to life after nearly 18 months. I was contacted with a view to playing a .FSEQ file on an ESPixelstick, this thread had the basis of the code needed but goes a little beyond as it also synchronises with FPP and uses an SD card to store the files. The new posts at this time are using parts of this post to create a standalone player (scrapped the FFP – for now) and used SPIFFS instead of an SD card.

    Hi, this is a work in progress code that with a change of ESP8266 enables a pixelstick type device to function as a FPP remote (not all features are included). That is instead of receiving e1.31 packets of data over a network, it reads data from an xlights .PSEQ file on an SD card. The file name and synchronization are dictated by a single packet sent every 16 frames by FPP.

    Simple over view:
    Set some variables.
    Initialize stuff.
    Read a file called ‘fortytwo.txt.’ from the SD card. This contains the number of the first channel & the number of channels we will be using. These are set as variables. In future some other stuff will be added.

    Main loop:
    Listen for an Udp packet FPP on channel 32320, when this arrives it will be one of three types:
    Start: Read file name – open file. Set the show running flag & current frame number to 0.
    Stop: Clear the show running flag & close file.
    Sync: Amend current frame number if required.

    At this point we have two options:
    The show isn’t running: Do nothing & go back to listen for Udp packets.
    The show is running: Read data from the SD card based on frame number and output to lights (WS2812b only at the moment).

    Code:
    /*
    The following code is still under development by Barnabybear, use it in your show at your own risk..
    This will enable a device like a pixelstick to function as a FPP remote:
    Reading it's data from an SD card sync'ed by a packet from an FPP master in remote mode.
     */
    
    #include <SPI.h>
    #include <SD.h>
    #include <NeoPixelBus.h>
    #include <ESP8266WiFi.h>
    #include <WiFiUDP.h>
    
    #define pixelCount; // number of channels (read from file).
    #define pixelPin 2  // make sure to set this to the correct pin changed from 8 by //PC//
    bool Debug = 1; // minimum debug.
    bool PSEQ_Headder_Debug = 0; // debug .PSEQ headder.
    bool Show_Running = 0; // flag 1= show running.
    const char* ssid = "your SSID";  // your network SSID
    const char* pass = "your PASSWORD";  // your network password
    IPAddress IP_Multicast_Out(239, 255, 0, 1); // doesn't realy do much in this code.
    unsigned int Port_Multicast_Out = 5568; // doesn't realy do much in this code.
    unsigned int localPort = 32320;      // local port to listen on
    //const int chipSelect = 15;  // only needed if you don't use GPIO 15 as CS (Chip Select).
    long int First_Channel = 0;  // first channel number in .PSEQ file (read from file).
    long int Number_Pix = 170; // number of pixels for 'NeoPixelBus'.
    long int Data_Offset;  // start of data in .PSEQ file (length of headder) (read from file).
    long int Number_Channels;  //  total number of channels in .PSEQ file (read from file).
    long int Step_Lenght;  // number of frames in .PSEQ file (read from file).
    int Frame_Time;  // FPS of of frames in .PSEQ file (read from file). 
    unsigned long Time_Start;
    int j;
    char PSEQ_Data_File[13];
    char packetBuffer[31]; // buffer to hold incoming packet
    long int Current_Step;  // code current step / frame number.
    long int Frame_Number;  // FPP packet current step / frame number.
    File dataFile;  // required by SD.h.
    NeoPixelBus strip = NeoPixelBus(Number_Pix, pixelPin); // required by NeoPixelBus.h.
    WiFiUDP Udp;
    
    void setup()
    {
       Serial_Initialize(); // Initialize serial.
       Neo_Pixel_Initialize(); // Initalize Neo pixels.
       SD_Initialize(); // Initialize SD card. 
       dataFile = SD.open("fortytwo.txt"); // open SD card file "fortytwo.txt"
       fortytwo_Read();  //read setup data from file fortytwo and set variables.
       dataFile.close(); // close SD card file "fortytwo.txt"
       WiFi_Initialize(); // Initialize WiFi.
       Udp.begin(localPort); // start lisening for Udp packets.
    }
    
    void loop()
    {
          int packetSize = Udp.parsePacket(); // parse packet from FPP.
      if (packetSize) { // check there is a packet.
        int len = Udp.read(packetBuffer, 31); // read the packet into buffer.
    
          switch(packetBuffer[7]){ // 3 actions dependant on type of FPP packet.
           
          case 0: // Start Packet
          for(int i = 17; i < 29; i++){ // file name bytes.
          PSEQ_Data_File[i -17] = (packetBuffer[i]); // read FPP file name.
          }
          Serial.print("0x00 = Start_Packet");  // debug print.
          Serial.print("  "); // debug print.
          Serial.println(PSEQ_Data_File); // debug print.
          PESQ_Headder_Read(); //call 'void PESQ_Headder_Read'.
          Show_Running = 1; // set fag to show running.
          Current_Step = 0; // reset current step / frame to zero.
          break;
              
          case 1: // End Packet //
          Serial.println("0x01 = End___Packet"); // debug print.
          Show_Running = 0; // set fag to show NOT running.
          dataFile.close(); // close current SD file.
          break;              
    
          case 2: // Sync Packet //
          Serial.println("0x02 = Sync__Packet"); // debug print.
          Frame_Number = (packetBuffer[10] * 256) + (packetBuffer[9]); // add 2 bytes to get frame number.
          Current_Step = Frame_Number; // overwrite currrent frame number with FPP sync frame number.
          break;           
        }     
      }   
          switch (Show_Running){ // 2 actions dependant on show running flag.
    
            case 0: // show NOT running, go back and check for FPP packets.
            break;
    
            case 1: // show running get data from SD card and output to lights.
            if (dataFile) { // check file open.
            while(Current_Step < (Step_Lenght+1)) { // if NOT at the end of the sequence.
            dataFile.seek(((Data_Offset) -1) + First_Channel + ((Number_Channels) * Current_Step)); // first read postion = (after the file headder) + (miss out unused channels). Subcequent read postion = as above + (the number of channels in file * the number of previous reads).
            for (j =0; j < Number_Pix; j++){ // loop based on number of channels / pixels to read
            strip.SetPixelColor(j,dataFile.read(),dataFile.read(),dataFile.read()); // read 3 current pixel values into Neo pixel buffer.              
           }
            delay(Frame_Time - 20); // delay untill correct time to send to pixels.
            strip.Show(); // send data to pixels.
           Current_Step++; // add 1 to the current step postion.
           Serial.print("."); // debug print.
           break; // to check for new packets for FPP.  
           }
    //       Show_Running = 0;
    //       Current_Step = 0;
           }
           }}
    //*************** void Serial_Initialize ***************//
      void Serial_Initialize(){
      // Open serial communications and wait for port to open:
      Serial.begin(115200); // debug print.
      while (!Serial) {
        ; // wait for serial port to connect. Needed for Leonardo only.
      }
      Serial.println("Serial initialized @ 115200.");
      }
    /////////////////////////////////////////////////////////
    
    //*************** void WiFi_Initialize ***************//
    void WiFi_Initialize(){
      WiFi.begin(ssid, pass);
      Serial.print("[Connecting]"); // debug print.
      Serial.print(ssid); // debug print.
      int tries=0;
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print("."); // debug print.
        tries++;
        if (tries > 30){
          break;  
        }}
        Serial.println("Connected."); // debug print.
        }
    /////////////////////////////////////////////////////////
    
    //*************** void Neo_Pixel_Initialize ***************//
      void Neo_Pixel_Initialize(){   
        strip.Begin(); // start neo pixel.
        strip.Show(); // set all to off.
        Serial.println("Neo Pixel initialized & set to all off."); // debug print.
      }
    /////////////////////////////////////////////////////////
    
    //*************** void SD_Initialize ***************//
        void SD_Initialize() {
      Serial.print("Initializing SD card... "); // debug print.
      if (!SD.begin()) {  // see if the card is present and can be initialized.
        Serial.println("Card failed, or not present"); // debug print.
        return;
      }
      Serial.println("Card initialized."); // debug print.
        }
    /////////////////////////////////////////////////////////
    
    //*************** void fortytwo_Read ***************//
        void fortytwo_Read() { // file on SD card with setup data - first channel number - number of channels.
        if (dataFile) {
          dataFile.seek(9); // set read pionter to correct byte.
          First_Channel = (((dataFile.read()-48) *1000) + ((dataFile.read()-48) *100) + ((dataFile.read()-48) *10) + (dataFile.read()-48));
          // read first channel: number and convert from ascii then correct values and add together.
          dataFile.seek(14); // set read pionter to correct byte.
          Number_Pix = (((dataFile.read()-48) *1000) + ((dataFile.read()-48) *100) + ((dataFile.read()-48) *10) + (dataFile.read()-48));
          // read number of pixels: number and convert from ascii then correct values and add together.     
          while (Debug){ // debug print.
          dataFile.seek(0); // set read pionter to correct byte.
          Serial.println(); // debug print.
          Serial.print("File fortytwo data: "); // debug print.
          for (int i = 0; i < 22; i++){
          Serial.write(dataFile.read()); // debug print.
          }
          Serial.print(" First channel: "); // debug print.
          Serial.print(First_Channel); // debug print.
          Serial.print(" Number of pixels: "); // debug print.
          Serial.print(Number_Pix); // debug print.
          Serial.println();
          break;
          }}
         // if the file isn't open, pop up an error:
         else {
         while (Debug){ // debug print.
         Serial.println("error opening fortytwo.txt"); // debug print.
         break;  
    }}}
    /////////////////////////////////////////////////////////
    
    //*************** void PESQ_Headder_Read ***************//
    void PESQ_Headder_Read(){
      Serial.print("Opened "); // debug print.
      dataFile = SD.open(PSEQ_Data_File); // open fire referenced by FPP.
      if (dataFile) { // check file open.
    //-----------------------------------------
          dataFile.seek(4); // set read pionter to correct byte.
          Data_Offset = (dataFile.read()); // read LSB.
          Data_Offset = Data_Offset + (dataFile.read() *256); // read MSB & add to LSB.
          while (PSEQ_Headder_Debug){ // debug print.
          Serial.println(); // debug print.
          Serial.print("Data Offset: "); // debug print.
          Serial.print(Data_Offset); // debug print.
          Serial.print(" "); // debug print.
          break;
          }
    //-----------------------------------------
          dataFile.seek(10); // set read pionter to correct byte.
          Number_Channels = (dataFile.read()); // read LSB.
          Number_Channels = Number_Channels + (dataFile.read() *256); // read MSB & add to LSB.
          while (PSEQ_Headder_Debug){ // debug print.
          Serial.println(); // debug print.
          Serial.print("Channels: "); // debug print.
          Serial.print(Number_Channels); // debug print.
          Serial.print(" "); // debug print.
          break;
          }
    //-----------------------------------------
          dataFile.seek(14); // set read pionter to correct byte.
          Step_Lenght = (dataFile.read()); // read LSB.
          Step_Lenght = Step_Lenght + (dataFile.read() *256); // read MSB & add to LSB. 
          while (PSEQ_Headder_Debug){ // debug print.
          Serial.println(); // debug print.
          Serial.print("Step Length: "); // debug print.
          Serial.print(Step_Lenght); // debug print.
          Serial.print(" "); // debug print.
          break;
          }
    //-----------------------------------------
          dataFile.seek(18); // set read pionter to correct byte.
          Frame_Time = (dataFile.read()); // Read FPS.
          while (PSEQ_Headder_Debug){ // debug print.
          Serial.println(); // debug print.
          Serial.print("Frame Timing: "); // debug print.
          Serial.print(Frame_Time, DEC); // debug print.
          Serial.print(" "); // debug print.
          break;
          }
    //-----------------------------------------
         while (Debug){ // debug print.
         Serial.print(PSEQ_Data_File); // debug print.
         Serial.println(" and variables set."); // debug print.
         delay(10);
         break;
         }}
      // if the file isn't open, pop up an error:
         else {
         while (Debug){ // debug print.
         Serial.print("error opening "); // debug print.
         Serial.println(PSEQ_Data_File); // debug print.
         break;
         }}
         return;
         }
    /////////////////////////////////////////////////////////
    File fortytwo:
    Code:
    fortytwo:4036:0072:11
    
    Byte 0 -> 7	Header to check file is correct for setup data.
    Byte 9 -> 12	First channel (Decimal number must be 4 digits).
    Byte 14 -> 17	Number of pixels (Decimal number must be 4 digits).
    Byte 19		Debug main (1 on).
    Byte 20		Debug advanced (1 on).
    The details of the replacement for the ESP can be found in this post. http://doityourselfchristmas.com/for...with-ESP8266-s

    I still have some work to do on the timing correction it’s very clunky at the moment (check back for updates). I think I’ll add an option to join a show, this means that if the start packet is missed for any reason but a sync packet is received and the show is not running, it will implement the start routine and join in even if this is half way through.

    This is development – I would not base my show at this point in time until more testing has been done!

    I’ll post a video tomorrow.
    Last edited by Barnabybear; 11-20-2017 at 07:27 PM.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •