using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

using ComiLib;
using ec = ComiLib.EtherCAT.SafeNativeMethods;

namespace ComiLib.EtherCAT
{
    public static class AlStatusError
    {
        public static AlStatusErrorInfo GetError(int errorCode)
        {
            AlStatusErrorInfo errorInfo = new AlStatusErrorInfo(errorCode);
            switch (errorCode)
            {
                case 0x0:
                    errorInfo.meaning = "Unspecified error";
                    errorInfo.description = "No error code is defined for occurred error";
                    errorInfo.solution = "Read user manual or contact device manufacturer";
                    break;

                case 0x2:
                    errorInfo.meaning = "No Memory";
                    errorInfo.description = "Less hardware memory, slave needs more memory. \r\n Example: For slave configuration, application configuration files are downloaded (possibly via FoE or large CoE objects). The size of those files exceeds the local memory";
                    errorInfo.solution = "Download smaller files or objects. Check user manual.";
                    break;

                case 0x4:
                    errorInfo.meaning = "Invalid Revision";
                    errorInfo.description = "Output/Input mapping is not valid for this hardware or software revision (0x1018:03)";
                    errorInfo.solution = "Change mapping or use different hardware";
                    break;

                case 0x11:
                    errorInfo.meaning = "Invalid requested state change";
                    errorInfo.description = "The EtherCAT State Machine (ESM) defines which state changes are allowed. All other state changes are not allowed. \r\n Example: If the master requests the slave to go from OP (AL Control = 0x08) directly to BOOT (AL Control = 0x03).";
                    errorInfo.solution = "Go step-by-step from the original state to the desired state.";
                    break;

                case 0x12:
                    errorInfo.meaning = "Unknown requested state change";
                    errorInfo.description = "The ESM defines the following states. They are coded with fixed values (only lower (=right) nibble): \r\n BOOT: AL Control = 0x03. \r\n INIT: AL Control = 0x01. \r\n PREOP: AL Control = 0x02. \r\n SAFEOP: AL Control = 0x04. \r\n OP: AL Control = 0x08 \r\n The fifth bit of the AL Control (left nibble is 1) is the “Error Acknowledge Bit”. If the slave is in AL STATUS = 0x14, \r\n i.e. ERROR SAFEOP the master acknowledges this by setting the Acknowledge bit. \r\n Example: If any other value for AL Control than those specified are sent.";
                    errorInfo.solution = "Do only request the defined states";
                    break;

                case 0x13:
                    errorInfo.meaning = "Boot state not supported";
                    errorInfo.description = "Device does not support BOOT state, but the master requests the slave to go to BOOT (AL Control = 0x03";
                    errorInfo.solution = "n/a";
                    break;

                case 0x14:
                    errorInfo.meaning = "No valid firmware";
                    errorInfo.description = "This error code may be returned after a firmware download, if the downloaded file cannot be used by the application controller";
                    errorInfo.solution = "Download a firmware that can be supported by the hardware and bootloader. Check Product Code and Revision Number (CoE object 0x1018). If this cannot be read from the firmware any more you may see this in the network configuration (CoE object dictionary) or probably in the ESI file (element Profile: ObjectDictionary:Objects:Object).";
                    break;

                case 0x15:
                    errorInfo.meaning = "Invalid mailbox configuration";
                    errorInfo.description = "Mailbox communication (= acyclic parameter exchange) is done via two memory areas on the EtherCAT Slave Controller (ESC) – the “Output Mailbox” (master -> slave) and the “Input Mailbox” (slave-> master). Those memory areas are protected by SyncManagers to prevent from simultaneous access from master and salve controller at the same time. SyncManagers are hardware entities on the ESC. They are configured via certain registers in the ESC register area (starting at 0x0800). The configuration includes start address, length, and direction (output or input). If those settings differ from those expected by the host controller of the slave this error is returned";
                    errorInfo.solution = "Replace previous network description of old slave with the one of the new slave";
                    break;

                case 0x16:
                    errorInfo.meaning = "Invalid mailbox configuration";
                    errorInfo.description = "Example: The slave hardware was replaced while the network configuration remained unchanged. The new hardware expects different mailbox SyncManager settings";
                    errorInfo.solution = "Replace previous network description of old slave with the one of the new slave";
                    break;

                case 0x17:
                    errorInfo.meaning = "Invalid Sync Manager configuration";
                    errorInfo.description = "Process data communication (cyclic communication) is done via extra memory areas on the ESC, separated for outputs and inputs. The process data length and the process data SyncManager length have to be the same. If this is not the case or the start address or direction does not match this error is returned. \r\n Example: The process data configuration was changed of the slaves which also changed the length of the data. The change was not activated in the configuration so that the configuration tool would have recalculated the SyncManager settings.";
                    errorInfo.solution = "Issue a re-calculation of the EtherCAT configuration";
                    break;

                case 0x18:
                    errorInfo.meaning = "No valid inputs available";
                    errorInfo.description = "The slave application cannot provide valid input values \r\n Example: A certain hardware which needs to be connected to the slave was disconnected";
                    errorInfo.solution = "n/a";
                    break;

                case 0x19:
                    errorInfo.meaning = "No valid outputs available";
                    errorInfo.description = "The slave application cannot recieve valid output values. \r\n Example: The slave has a RxPdoToggle output or an “Output Valid” information in its process data. The RxPdoToggle does not toggle or the OutputValid is not true. Therefore the slave has no process data which the application can use. If supported, check the RxPDO Toggle Failed Counter in object 0x1C3x.0E). Also, the Synchronization may have problems (see object 0x10F1:SI2 Sync Error Counter Limit) so that process data are received too late by the slave so that the local slave cycle misses the toggle event. Another reason can be that the PLC stopped working";
                    errorInfo.solution = "The RxPdoToggle may need to be handled by the PLC program \r\n The outputs valid may have to be set by the PLC program \r\n PLC may have stopped, restart PLC";
                    break;

                case 0x1A:
                    errorInfo.meaning = "Synchronization error";
                    errorInfo.description = "If too many RxPDO Toggle error occur, i.e. the RxPDO Toggle Failed Counter increases the internal limit the slave returns to SAFEPERROR with 0x001A. Multiple synchronization errors. Device is not synchronized any more (used if the causes mirrored by the AL Status Codes 0x2C, 0x2D, 0x32, 0x33, 0x34 cannot be distinguished).";
                    errorInfo.solution = "n/a";
                    break;

                case 0x1B:
                    errorInfo.meaning = "Sync manager watchdog";
                    errorInfo.description = "The slave did not receive process data within the specified watchdog time. Usually, the WD time is 100ms. The WD is re-started every time it receives new process data, usually when the Output SyncManager (SyncManager2) is written. For devices which have only inputs usually no WD is used. Increasing the WD is not a solution. \r\n Reason: PLC stopped";
                    errorInfo.solution = "n/a";
                    break;

                case 0x1C:
                    errorInfo.meaning = "Invalid Sync Manager Types";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x1D:
                    errorInfo.meaning = "Invalid Output Configuration";
                    errorInfo.description = "SM configuration for output process data is invalid";
                    errorInfo.solution = "n/a";
                    break;

                case 0x1E:
                    errorInfo.meaning = "Invalid Input Configuration";
                    errorInfo.description = "SM configuration for input process data is invalid";
                    errorInfo.solution = "n/a";
                    break;
                    
                case 0x1F:
                    errorInfo.meaning = "Invalid Watchdog Configuration";
                    errorInfo.description = "The Watchdog is configured in the ESC register 0x0400 and 0x0420. EtherCAT defines default watchdog settings (100ms) or they are defined in the ESI file. If the slave does not accept a change of the expected settings it returns this AL Status Code Example: A slave may not accept that the WD is deactivated.";
                    errorInfo.solution = "Use default WD settings";
                    break;

                case 0x20:
                    errorInfo.meaning = "Slave needs cold start";
                    errorInfo.description = "Slave device require a power off - power on reset";
                    errorInfo.solution = "n/a";
                    break;

                case 0x21:
                    errorInfo.meaning = "Slave needs INIT";
                    errorInfo.description = "Slave application requests INIT state";
                    errorInfo.solution = "n/a";
                    break;

                case 0x22:
                    errorInfo.meaning = "Slave needs PREOP";
                    errorInfo.description = "Slave application requests PREOP state";
                    errorInfo.solution = "n/a";
                    break;

                case 0x23:
                    errorInfo.meaning = "Slave needs SAFEOP";
                    errorInfo.description = "Slave application requests SAFEOP state";
                    errorInfo.solution = "n/a";
                    break;

                case 0x24:
                    errorInfo.meaning = "Invalid Input Mapping";
                    errorInfo.description = "The process data are described by the configuration (PdoConfig) and PDO assignment (PdoAssign). \r\n PdoConfig: list of actual variables (usually indexes 0x6nnn for inputs and 0x7nnn for outputs). Variables are also called PDO entries. There can be one or several variables with in one list (i.e. within one PDO). The Input PDOs have the index 0x1Amm. The Output PDOs have the index 0x16mm. \r\n PdoAssign: The list of PDOs (object index 0x16nn, 0x1Amm) which are actually part of the process data and hence, are transferred cyclically, are listed in the PDO Assign Objects 0x1C12 (output PDOs) and 0x1C13 (input PDOs). All this can be seen in the SystemManager on the TAB “Process Data”. If the mapping which was set by the user on the Process Data tab and which was expected by the slave do not match this Status Code is returned.";
                    errorInfo.solution = "n/a";
                    break;

                case 0x25:
                    errorInfo.meaning = "Invalid Output Mapping";
                    errorInfo.description = "The process data are described by the configuration (PdoConfig) and PDO assignment (PdoAssign). \r\n PdoConfig: list of actual variables (usually indexes 0x6nnn for inputs and 0x7nnn for outputs). Variables are also called PDO entries. There can be one or several variables with in one list (i.e. within one PDO). The Input PDOs have the index 0x1Amm. The Output PDOs have the index 0x16mm. \r\n Example: Slave does only support one or certain PDO combinations but a different setting was made by the user. For a bus coupler the connected terminals differ from the configured terminals in the SystemManager";
                    errorInfo.solution = "n/a";
                    break;

                case 0x26:
                    errorInfo.meaning = "Inconsistent Settings";
                    errorInfo.description = "General settings mismatch";
                    errorInfo.solution = "n/a";
                    break;

                case 0x27:
                    errorInfo.meaning = "Freerun not supported";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x28:
                    errorInfo.meaning = "Synchronization not supported";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x29:
                    errorInfo.meaning = "Freerun needs 3 Buffer Mode";
                    errorInfo.description = "FreeRun mode, SM has to run in 3-buffer mode";
                    errorInfo.solution = "n/a";
                    break;

                case 0x2A:
                    errorInfo.meaning = "Background Watchdog";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x2B:
                    errorInfo.meaning = "No Valid Inputs and Outputs";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x2C:
                    errorInfo.meaning = "Fatal Sync Error";
                    errorInfo.description = "The hardware interrupt signal (so called Sync signal) generated by the ESC is not generated any more. The master sets and activated the cycle time of the Sync signal during state transition from PREOP to SAFEOP. If a slave was disconnected and reconnected (also due to lost frames or CRC errors) the generation of the SyncSignal may be lost.";
                    errorInfo.solution = "Set master to INIT and back to OP so that the DCs are initialized again";
                    break;

                case 0x2D:
                    errorInfo.meaning = "ana";
                    errorInfo.description = "SyncSignal not received: In SAFEOP the slave waits for the first Sync0/Sync1 events before switching to OP, if these events were not received during the SAFEOP to OP-Timeout time the slave refuses the state transition to OP";
                    errorInfo.solution = "n/a";
                    break;

                case 0x30:
                    errorInfo.meaning = "Invalid DC SYNC Configuration";
                    errorInfo.description = "Distributed Clock Configuration is invalid due to application requirements";
                    errorInfo.solution = "n/a";
                    break;
                
                case 0x31:
                    errorInfo.meaning = "nvalid DC Latch Configuration";
                    errorInfo.description = "DC Latch configuration is invalid due to application requirements";
                    errorInfo.solution = "n/a";
                    break;

                case 0x32:
                    errorInfo.meaning = "PLL Error";
                    errorInfo.description = "Master not synchronized, at least one DC event recieved";
                    errorInfo.solution = "n/a";
                    break;
                
                case 0x33:
                    errorInfo.meaning = "DC Sync IO Error";
                    errorInfo.description = "Multiple Synchronization Errors: At least one SycnSignal was received before. However, the PLL between slave and master is not synchronized any more. This may occur if the master application jitters too much";
                    errorInfo.solution = "Use specific industrial pc, standard office PCs may have power saving options, graphic accelerateds and other system services which disturb the real-time of the master. \r\n CPU power may be too small for the PLC/NC program. \r\n Increase EtherCAT and PLC/NC cycle time. \r\n Use SyncUnits for the slaves using DCs.";
                    break;

                case 0x34:
                    errorInfo.meaning = "DC Sync Timeout Error";
                    errorInfo.description = "Multiple Synchronization Errors, too much SM events missed";
                    errorInfo.solution = "n/a";
                    break;

                case 0x35:
                    errorInfo.meaning = "DC Invalid Sync Cycle Time";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x36:
                    errorInfo.meaning = "DC Sync0 Cycle Time";
                    errorInfo.description = "DC Sync0 cycle time does not fit to the application requirements";
                    errorInfo.solution = "n/a";
                    break;

                case 0x37:
                    errorInfo.meaning = "DC Sync1 Cycle Time";
                    errorInfo.description = "DC Sync1 cycle time does not fit to the application requirements";
                    errorInfo.solution = "n/a";
                    break;

                case 0x41:
                    errorInfo.meaning = "MBX_AOE";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x42:
                    errorInfo.meaning = "MBX_EOE";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x43:
                    errorInfo.meaning = "MBX_COE";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x44:
                    errorInfo.meaning = "MBX_FOE";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x45:
                    errorInfo.meaning = "MBX_SOE";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x4F:
                    errorInfo.meaning = "MBX_VOE";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x50:
                    errorInfo.meaning = "EEPROM No Access";
                    errorInfo.description = "EEPROM not assigned to PDI";
                    errorInfo.solution = "n/a";
                    break;

                case 0x51:
                    errorInfo.meaning = "EEPROM Error";
                    errorInfo.description = "EEPROM access error";
                    errorInfo.solution = "n/a";
                    break;

                case 0x60:
                    errorInfo.meaning = "Slave Requested Locally";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0x61:
                    errorInfo.meaning = "Device Identification Value updated";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                case 0xF0:
                    errorInfo.meaning = "Application Controller available";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;

                default:
                    errorInfo.meaning = "UNKNOWN";
                    errorInfo.description = "n/a";
                    errorInfo.solution = "n/a";
                    break;
            }

            return errorInfo;
        }
    }
    public class AlStatusErrorInfo
    {
        public AlStatusErrorInfo(int errorCode)
        {
            this.errorCode = errorCode;
        }

        public int errorCode;
        public string meaning;
        public string description;
        public string solution;
    }
}
