package rpc import ( "fmt" "reflect" ) // ErrorCode for DI-Net RPC reply message type ErrorCode uint32 // Error object for DI-Net RPC reply message type Error struct { Code ErrorCode `json:"code" msgpack:"code"` Descr string `json:"descr,omitempty" msgpack:"descr,omitempty"` Data interface{} `json:"data,omitempty" msgpack:"data,omitempty"` } // Error returns a descriptive error message func (e Error) Error() string { if e.Data != nil { return fmt.Sprintf("%s (%+v)", e.Code.Error(), e.Code.Error()) } return e.Code.Error() } // GetError constructs an error object. It automatically fills in the description based on the given error code. // When error Ok is given, nil is returned func GetError(err ErrorCode, data ...interface{}) *Error { if err == Ok { return nil } var v interface{} if len(data) > 0 { v = data[0] } return &Error{ Code: err, Descr: err.String(), Data: v, } } // ErrorCode constants const ( // Generic Ok ErrorCode = 0 // Generic EParam ErrorCode = 1 ERange ErrorCode = 2 ENodev ErrorCode = 3 ENores ErrorCode = 4 EBusy ErrorCode = 5 EOpnotsupp ErrorCode = 6 EProto ErrorCode = 7 EChecksum ErrorCode = 8 ETimeout ErrorCode = 9 EDisconnected ErrorCode = 10 EAgain ErrorCode = 11 EOpdenied ErrorCode = 12 EIofailed ErrorCode = 13 ENotfound ErrorCode = 14 ENomem ErrorCode = 15 // Secure server ESecsDuplicateProject ErrorCode = 256 ESecsInvalidProjectState ErrorCode = 257 ESecsInvalidMutation ErrorCode = 258 ESecsInvalidAction ErrorCode = 259 ESecsProjectChanged ErrorCode = 260 ESecsPlanningChanged ErrorCode = 261 ESecsDesignChanged ErrorCode = 262 ESecsDatabaseError ErrorCode = 263 ESecsNoProjectData ErrorCode = 264 ESecsInvalidProject ErrorCode = 265 ESecsInvalidRequest ErrorCode = 266 ESecsInternalError ErrorCode = 267 ESecsNoBackend ErrorCode = 268 ESecsBackendInvalidMessage ErrorCode = 269 ESecsSetupChanged ErrorCode = 270 ESecsInvalidProjectType ErrorCode = 271 ESecsNoProjectGroup ErrorCode = 273 // Backend EBackendDuplicateProject ErrorCode = 512 EBackendInvalidProject ErrorCode = 513 EBackendDeviceError ErrorCode = 514 EBackendInternalError ErrorCode = 515 EBackendInvalidMutation ErrorCode = 516 //Deprecated: Use a more specific error code EBackendInvalidGroup ErrorCode = 517 EBackendAlreadyActivated ErrorCode = 518 EBackendAlreadyDeactivated ErrorCode = 519 EBackendMissingActivateGroups ErrorCode = 520 EBackendMissingDeactivateGroups ErrorCode = 521 EBackendCp3000CommError ErrorCode = 522 // Firmware/device EFirmwareTilt ErrorCode = 1024 //Deprecated: Use a more specific error code EFirmwareUltrasonic ErrorCode = 1025 EFirmwareSpeaker ErrorCode = 1026 EFirmwareEeprom ErrorCode = 1027 EFirmwareCalibration ErrorCode = 1028 EFirmwareBa ErrorCode = 1029 EFirmwareVref ErrorCode = 1030 EFirmwareVrefClipping ErrorCode = 1031 EFirmwareLeaderFailure ErrorCode = 1032 EFirmwareFollowerFailure ErrorCode = 1033 EFirmwareRotation ErrorCode = 1034 EFirmwareDetectionbutton ErrorCode = 1035 EFirmwareDeadmansTimeout ErrorCode = 1036 //Deprecated: Use a more specific error code EFirmwareBatteryTooLow ErrorCode = 1037 EFirmwareSwitchComm ErrorCode = 1038 EFirmwareLeaderConflict ErrorCode = 1039 EFirmwareTemperature ErrorCode = 1040 EFirmwareMeasurement ErrorCode = 1041 EFirmwareGps ErrorCode = 1042 EFirmwareMcuComm ErrorCode = 1043 EFirmwareDuStrikeRoleUnknown ErrorCode = 1044 EFirmwareModemUartFraming ErrorCode = 1045 EFirmwareBatteryBoard ErrorCode = 1046 EFirmwareSpeakerL ErrorCode = 1047 EFirmwareSpeakerF ErrorCode = 1048 EFirmwareEepromL ErrorCode = 1049 EFirmwareEepromF ErrorCode = 1050 //Deprecated: Use a more specific error code EFirmwareBatteryTooLowL ErrorCode = 1051 //Deprecated: Use a more specific error code EFirmwareBatteryTooLowF ErrorCode = 1052 EFirmwareNoMeasurement ErrorCode = 1053 EFirmwareBattery1Low ErrorCode = 1054 EFirmwareBattery1Critical ErrorCode = 1055 EFirmwareBattery1Empty ErrorCode = 1056 EFirmwareBattery1Removed ErrorCode = 1057 EFirmwareBattery2Low ErrorCode = 1058 EFirmwareBattery2Critical ErrorCode = 1059 EFirmwareBattery2Empty ErrorCode = 1060 EFirmwareBattery2Removed ErrorCode = 1061 EFirmwareKeyswitchNotOperational ErrorCode = 1062 EFirmwareDeviceContainsErrors ErrorCode = 1063 EFirmwareDeviceService ErrorCode = 1064 EFirmwareDeviceArmed ErrorCode = 1065 EFirmwareDeviceActive ErrorCode = 1066 EFirmwareDeviceIdle ErrorCode = 1067 EFirmwareDncmNoReqrepBuffer ErrorCode = 1068 EFirmwareMismatchToken ErrorCode = 1069 EFirmwareReleaseSwitchComm ErrorCode = 1070 EFirmwareActivateSwitchComm ErrorCode = 1071 EFirmwareDeactivateSwitchComm ErrorCode = 1072 EFirmwareActivateShortNotEnabled ErrorCode = 1073 EFirmwareDeactivateShortEnabled ErrorCode = 1074 EFirmwareUltrasonicCurrent1 ErrorCode = 1075 EFirmwareUltrasonicCurrent2 ErrorCode = 1076 EFirmwareUltrasonicCurrentBoth ErrorCode = 1077 EFirmwareUltrasonicIo1 ErrorCode = 1078 EFirmwareUltrasonicIo2 ErrorCode = 1079 EFirmwareUltrasonicIoBoth ErrorCode = 1080 EFirmwareIoFailedI2c ErrorCode = 1081 EFirmwareIoFailedAdc ErrorCode = 1082 // CAN-bus and protocol ECanInval ErrorCode = 3000 ECanIo ErrorCode = 3001 ECanTimeout ErrorCode = 3002 ECanAgain ErrorCode = 3003 ECanNobufs ErrorCode = 3004 ECanProto ErrorCode = 3005 ECanCrc ErrorCode = 3006 // Backend warnings EWrnBackendDeviceWarning ErrorCode = 2000512 // Firmware/device warnings EWrnFirmwareActivateShortPresent ErrorCode = 2001024 EWrnFirmwareDeactivateShortPresent ErrorCode = 2001025 EWrnFirmwareBattery1Low ErrorCode = 2001026 EWrnFirmwareBattery1Critical ErrorCode = 2001027 EWrnFirmwareBattery1Empty ErrorCode = 2001028 EWrnFirmwareBattery1Removed ErrorCode = 2001029 EWrnFirmwareBattery2Low ErrorCode = 2001030 EWrnFirmwareBattery2Critical ErrorCode = 2001031 EWrnFirmwareBattery2Empty ErrorCode = 2001032 EWrnFirmwareBattery2Removed ErrorCode = 2001033 EWrnFirmwareUltrasonicCurrent1 ErrorCode = 2001034 EWrnFirmwareUltrasonicCurrent2 ErrorCode = 2001035 EWrnFirmwareUltrasonicCurrentBoth ErrorCode = 2001036 EWrnFirmwareUltrasonicIo1 ErrorCode = 2001037 EWrnFirmwareUltrasonicIo2 ErrorCode = 2001038 EWrnFirmwareUltrasonicIoBoth ErrorCode = 2001039 EWrnFirmwareActivateDetectionNok ErrorCode = 2001040 EWrnFirmwareNeedsReboot ErrorCode = 2001041 ) // Error returns a descriptive error message func (err ErrorCode) Error() string { return fmt.Sprintf("dinet error: %d", err) } // String returns a long description of ErrorCode // nolint func (err ErrorCode) String() string { switch err { case Ok: return "OK" // Generic case EParam: return "Invalid parameter" case ERange: return "Value/parameter out of range" case ENodev: return "No such device" case ENores: return "No such resource" case EBusy: return "Device or resource busy" case EOpnotsupp: return "Operation not supported" case EProto: return "Protocol error" case EChecksum: return "Checksum error" case ETimeout: return "Timeout" case EDisconnected: return "Disconnected" case EAgain: return "Try again" case EOpdenied: return "Operation denied" case EIofailed: return "I/O operation failed" case ENotfound: return "Not found" case ENomem: return "Out of memory" // Secure server case ESecsDuplicateProject: return "Duplicate project found" case ESecsInvalidProjectState: return "Invalid project state reached" case ESecsInvalidMutation: return "Invalid mutation requested" case ESecsInvalidAction: return "Invalid action specified" case ESecsProjectChanged: return "Project data changed" case ESecsPlanningChanged: return "Project planning changed" case ESecsDesignChanged: return "Project design changed" case ESecsDatabaseError: return "Database error occurred" case ESecsNoProjectData: return "No project data supplied" case ESecsInvalidProject: return "Invalid project selected" case ESecsInvalidRequest: return "Invalid request supplied" case ESecsInternalError: return "Internal error supplied" case ESecsNoBackend: return "Backend is not connected" case ESecsBackendInvalidMessage: return "Backend sent an invalid message" case ESecsSetupChanged: return "Project setup changed" case ESecsInvalidProjectType: return "Project type not recognized" case ESecsNoProjectGroup: return "No project groups provided" // Backend case EBackendDuplicateProject: return "Duplicate project" case EBackendInvalidProject: return "Invalid project" case EBackendDeviceError: return "Device error" case EBackendInternalError: return "Backend internal error" case EBackendInvalidMutation: return "Invalid mutation requested" case EBackendInvalidGroup: return "Invalid group action" case EBackendAlreadyActivated: return "Group already activated" case EBackendAlreadyDeactivated: return "Group already deactivated" case EBackendMissingActivateGroups: return "Missing activate groups" case EBackendMissingDeactivateGroups: return "Missing deactivate groups" case EBackendCp3000CommError: return "CP3000 communication to legacy device failed" // Firmware/device case EFirmwareTilt: return "Tilt position error" case EFirmwareUltrasonic: return "Ultrasonic error" case EFirmwareSpeaker: return "Speaker error" case EFirmwareEeprom: return "EEPROM error" case EFirmwareCalibration: return "Calibration error" case EFirmwareBa: return "BA error" case EFirmwareVref: return "Vref error" case EFirmwareVrefClipping: return "Vref clipping" case EFirmwareLeaderFailure: return "Leader failed (failsafe)" case EFirmwareFollowerFailure: return "Follower failed (failsafe)" case EFirmwareRotation: return "Rotation position error" case EFirmwareDetectionbutton: return "Detection button error" case EFirmwareDeadmansTimeout: return "Deadmans timeout" case EFirmwareBatteryTooLow: return "One or more device batteries are too low" case EFirmwareSwitchComm: return "Switch communication error" case EFirmwareLeaderConflict: return "Leader conflict" case EFirmwareTemperature: return "Temperature sensor failure" case EFirmwareMeasurement: return "Measurement error" case EFirmwareGps: return "GPS error" case EFirmwareMcuComm: return "MCU communication error" case EFirmwareDuStrikeRoleUnknown: return "Detection unit strike role unknown" case EFirmwareModemUartFraming: return "Modem UART framing error" case EFirmwareBatteryBoard: return "At least 1 battery section broken" case EFirmwareSpeakerL: return "Speaker error Main board" case EFirmwareSpeakerF: return "Speaker error Monitor board" case EFirmwareEepromL: return "EEPROM error Main board" case EFirmwareEepromF: return "EEPROM error Monitor board" case EFirmwareBatteryTooLowL: return "Battery too low Main board" case EFirmwareBatteryTooLowF: return "Battery too low Monitor board" case EFirmwareNoMeasurement: return "There is no measurement available" case EFirmwareBattery1Low: return "Battery 1 is low" case EFirmwareBattery1Critical: return "Battery 1 is critical" case EFirmwareBattery1Empty: return "Battery 1 is empty" case EFirmwareBattery1Removed: return "Battery 1 is removed" case EFirmwareBattery2Low: return "Battery 2 is low" case EFirmwareBattery2Critical: return "Battery 2 is critical" case EFirmwareBattery2Empty: return "Battery 2 is empty" case EFirmwareBattery2Removed: return "Battery 2 is removed" case EFirmwareKeyswitchNotOperational: return "Keyswitch is not operational" case EFirmwareDeviceContainsErrors: return "Device contains errors" case EFirmwareDeviceService: return "State transition not allowed, device is service" case EFirmwareDeviceArmed: return "State transition not allowed, device is armed" case EFirmwareDeviceActive: return "State transition not allowed, device is active" case EFirmwareDeviceIdle: return "State transition not allowed, device is idle" case EFirmwareDncmNoReqrepBuffer: return "No space for request in buffer" case EFirmwareMismatchToken: return "Device is already armed using a different token" case EFirmwareReleaseSwitchComm: return "Switch communication error during release" case EFirmwareActivateSwitchComm: return "Switch communication error during activate" case EFirmwareDeactivateSwitchComm: return "Switch communication error during deactivate" case EFirmwareActivateShortNotEnabled: return "Short is not enabled after activate" case EFirmwareDeactivateShortEnabled: return "Short is not disabled after deactivate" case EFirmwareUltrasonicCurrent1: return "Ultrasonic sensor 1 failed (current measurement)" case EFirmwareUltrasonicCurrent2: return "Ultrasonic sensor 2 failed (current measurement)" case EFirmwareUltrasonicCurrentBoth: return "Ultrasonic sensor 1 & 2 failed (current measurement)" case EFirmwareUltrasonicIo1: return "Ultrasonic sensor 1 failed (IO-path measurement)" case EFirmwareUltrasonicIo2: return "Ultrasonic sensor 2 failed (IO-path measurement)" case EFirmwareUltrasonicIoBoth: return "Ultrasonic sensor 1 & 2 failed (IO-path measurement)" case EFirmwareIoFailedI2c: return "I2C bus communication error" case EFirmwareIoFailedAdc: return "ADC peripheral error" // CAN-bus and protocol case ECanInval: return "CAN invalid argument" case ECanIo: return "CAN peripheral I/O error" case ECanTimeout: return "CAN timeout" case ECanAgain: return "CAN try again" case ECanNobufs: return "CAN buffers depleted" case ECanProto: return "CAN protocol error" case ECanCrc: return "CAN msg crc error" // Backend warnings case EWrnBackendDeviceWarning: return "Device warning" // Firmware/device warnings case EWrnFirmwareActivateShortPresent: return "Short was already present upon activation" case EWrnFirmwareDeactivateShortPresent: return "Short is still present after deactivation" case EWrnFirmwareBattery1Low: return "Battery 1 is low" case EWrnFirmwareBattery1Critical: return "Battery 1 is critical" case EWrnFirmwareBattery1Empty: return "Battery 1 is empty" case EWrnFirmwareBattery1Removed: return "Battery 1 is removed" case EWrnFirmwareBattery2Low: return "Battery 2 is low" case EWrnFirmwareBattery2Critical: return "Battery 2 is critical" case EWrnFirmwareBattery2Empty: return "Battery 2 is empty" case EWrnFirmwareBattery2Removed: return "Battery 2 is removed" case EWrnFirmwareUltrasonicCurrent1: return "Ultrasonic sensor 1 failed (current measurement)" case EWrnFirmwareUltrasonicCurrent2: return "Ultrasonic sensor 2 failed (current measurement)" case EWrnFirmwareUltrasonicCurrentBoth: return "Ultrasonic sensor 1 & 2 failed (current measurement)" case EWrnFirmwareUltrasonicIo1: return "Ultrasonic sensor 1 failed (IO-path measurement)" case EWrnFirmwareUltrasonicIo2: return "Ultrasonic sensor 2 failed (IO-path measurement)" case EWrnFirmwareUltrasonicIoBoth: return "Ultrasonic sensor 1 & 2 failed (IO-path measurement)" case EWrnFirmwareActivateDetectionNok: return "Detection is not ok after activate" case EWrnFirmwareNeedsReboot: return "Firmware needs reboot" default: return "Unknown" } } // IsError returns true when this error is a standard error and not Ok or a warning func (err ErrorCode) IsError() bool { return err != 0 && err < 2000000 } // IsWarning returns true when this error is actually a warning func (err ErrorCode) IsWarning() bool { return err >= 2000000 } // CompareError checks if the two errors are the same. func CompareError(err1 *Error, err2 *Error) bool { if err1 == err2 { return true } // It is possible that the errors are the same, but are pointing to different structs if err1 == nil || err2 == nil { // One struct is empty so they are not pointing to different structs return false } if err1.Code != err2.Code { return false } // There is no compare interface if !reflect.DeepEqual(err1.Data, err2.Data) { return false } return true }