bool ClimateControlBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(climatecontrol_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case activeCoolingMode_key+descriptions_key_offset: aPropValue->setBoolValue(climateDeviceKind==climatedevice_fancoilunit); // FCUs can cool actively return true; // Settings properties case heatingSystemCapability_key+settings_key_offset: aPropValue->setUint8Value(heatingSystemCapability); return true; case heatingSystemType_key+settings_key_offset: aPropValue->setUint8Value(heatingSystemType); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties case heatingSystemCapability_key+settings_key_offset: setPVar(heatingSystemCapability, (VdcHeatingSystemCapability)aPropValue->uint8Value()); return true; case heatingSystemType_key+settings_key_offset: setPVar(heatingSystemType, (VdcHeatingSystemType)aPropValue->uint8Value()); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }
// access to all fields bool ChannelBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(channel_Key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case name_key+descriptions_key_offset: aPropValue->setStringValue(getName()); return true; case channelIndex_key+descriptions_key_offset: aPropValue->setUint8Value(channelIndex); return true; case min_key+descriptions_key_offset: aPropValue->setDoubleValue(getMin()); return true; case max_key+descriptions_key_offset: aPropValue->setDoubleValue(getMax()); return true; case resolution_key+descriptions_key_offset: aPropValue->setDoubleValue(getResolution()); return true; // Settings properties // - none for now // States properties case value_key+states_key_offset: // get value of channel, possibly calculating it if needed (color conversions) aPropValue->setDoubleValue(getChannelValueCalculated()); return true; case age_key+states_key_offset: if (channelLastSync==Never) aPropValue->setNull(); // no value known else aPropValue->setDoubleValue((double)(MainLoop::now()-channelLastSync)/Second); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties // - none for now // States properties case value_key+states_key_offset: setChannelValue(aPropValue->doubleValue(), 0, true); // always apply, no transition time return true; } } } // single class level properties only, don't call inherited return false; }
ErrorPtr P44JsonApiRequest::sendResult(ApiValuePtr aResult) { LOG(LOG_DEBUG, "cfg <- vdcd (JSON) result sent: result=%s", aResult ? aResult->description().c_str() : "<none>"); JsonApiValuePtr result = boost::dynamic_pointer_cast<JsonApiValue>(aResult); if (result) { P44VdcHost::sendCfgApiResponse(jsonComm, result->jsonObject(), ErrorPtr()); } else { // always return SOMETHING P44VdcHost::sendCfgApiResponse(jsonComm, JsonObject::newNull(), ErrorPtr()); } return ErrorPtr(); }
// access to all fields bool EnoceanDevice::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(enoceanDevice_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { case profileVariants_key: aPropValue->setType(apivalue_object); // make object (incoming object is NULL) return getProfileVariants(aPropValue); case profile_key: aPropValue->setInt32Value(getEEProfile()); return true; case packetage_key: // Note lastPacketTime is set to now at startup, so additionally check lastRSSI if (lastPacketTime==Never || lastRSSI<=-999) aPropValue->setNull(); else aPropValue->setDoubleValue((double)(MainLoop::now()-lastPacketTime)/Second); return true; case rssi_key: if (lastRSSI<=-999) aPropValue->setNull(); else aPropValue->setInt32Value(lastRSSI); return true; case repeaterCount_key: if (lastRSSI<=-999) aPropValue->setNull(); else aPropValue->setUint8Value(lastRepeaterCount); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { case profile_key: setProfileVariant(aPropValue->int32Value()); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }
bool EnoceanDevice::getProfileVariants(ApiValuePtr aApiObjectValue) { // check if current profile is one of the interchangeable ones const ProfileVariantEntry *currentVariant = profileVariantsTable(); while (currentVariant && currentVariant->profileGroup!=0) { // look for current EEP in the list of variants if (getEEProfile()==currentVariant->eep) { // create string from all other variants (same profileGroup), if any bool anyVariants = false; const ProfileVariantEntry *variant = profileVariantsTable(); while (variant->profileGroup!=0) { if (variant->profileGroup==currentVariant->profileGroup) { if (variant->eep!=getEEProfile()) anyVariants = true; // another variant than just myself aApiObjectValue->add(string_format("%d",variant->eep), aApiObjectValue->newString(variant->description)); } variant++; } // there are variants return anyVariants; } currentVariant++; } return false; // no variants }
void VdcJsonApiConnection::jsonResponseHandler(VdcApiResponseCB aResponseHandler, int32_t aResponseId, ErrorPtr &aError, JsonObjectPtr aResultOrErrorData) { if (aResponseHandler) { // create request object just to hold the response ID string respId = string_format("%d", aResponseId); ApiValuePtr resultOrErrorData = JsonApiValue::newValueFromJson(aResultOrErrorData); VdcApiRequestPtr request = VdcJsonApiRequestPtr(new VdcJsonApiRequest(VdcJsonApiConnectionPtr(this), respId.c_str())); if (Error::isOK(aError)) { LOG(LOG_INFO,"vdSM -> vDC (JSON) result received: id='%s', result=%s\n", request->requestId().c_str(), resultOrErrorData ? resultOrErrorData->description().c_str() : "<none>"); } else { LOG(LOG_INFO,"vdSM -> vDC (JSON) error received: id='%s', error=%s, errordata=%s\n", request->requestId().c_str(), aError->description().c_str(), resultOrErrorData ? resultOrErrorData->description().c_str() : "<none>"); } aResponseHandler(VdcApiConnectionPtr(this), request, aError, resultOrErrorData); } }
void VdcJsonApiConnection::jsonRequestHandler(const char *aMethod, const char *aJsonRpcId, JsonObjectPtr aParams) { ErrorPtr respErr; if (apiRequestHandler) { // create params API value ApiValuePtr params = JsonApiValue::newValueFromJson(aParams); VdcApiRequestPtr request; // create request object in case this request expects an answer if (aJsonRpcId) { // Method request = VdcJsonApiRequestPtr(new VdcJsonApiRequest(VdcJsonApiConnectionPtr(this), aJsonRpcId)); LOG(LOG_INFO,"vdSM -> vDC (JSON) method call '%s' received: requestid='%s', params=%s\n", aMethod, request->requestId().c_str(), params ? params->description().c_str() : "<none>"); } else { // Notification LOG(LOG_INFO,"vdSM -> vDC (JSON) notification '%s' received: params=%s\n", aMethod, params ? params->description().c_str() : "<none>"); } // call handler apiRequestHandler(VdcJsonApiConnectionPtr(this), request, aMethod, params); } }
bool SensorBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(sensor_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case sensorType_key+descriptions_key_offset: aPropValue->setUint16Value(sensorType); return true; case sensorUsage_key+descriptions_key_offset: aPropValue->setUint16Value(sensorUsage); return true; case min_key+descriptions_key_offset: aPropValue->setDoubleValue(min); return true; case max_key+descriptions_key_offset: aPropValue->setDoubleValue(max); return true; case resolution_key+descriptions_key_offset: aPropValue->setDoubleValue(resolution); return true; case updateInterval_key+descriptions_key_offset: aPropValue->setDoubleValue((double)updateInterval/Second); return true; case aliveSignInterval_key+descriptions_key_offset: aPropValue->setDoubleValue((double)aliveSignInterval/Second); return true; // Settings properties case group_key+settings_key_offset: aPropValue->setUint16Value(sensorGroup); return true; case minPushInterval_key+settings_key_offset: aPropValue->setDoubleValue((double)minPushInterval/Second); return true; case changesOnlyInterval_key+settings_key_offset: aPropValue->setDoubleValue((double)changesOnlyInterval/Second); return true; // States properties case value_key+states_key_offset: // value if (lastUpdate==Never) aPropValue->setNull(); else aPropValue->setDoubleValue(currentValue); return true; case age_key+states_key_offset: // age if (lastUpdate==Never) aPropValue->setNull(); else aPropValue->setDoubleValue((double)(MainLoop::now()-lastUpdate)/Second); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties case group_key+settings_key_offset: setPVar(sensorGroup, (DsGroup)aPropValue->int32Value()); return true; case minPushInterval_key+settings_key_offset: setPVar(minPushInterval, (MLMicroSeconds)(aPropValue->doubleValue()*Second)); return true; case changesOnlyInterval_key+settings_key_offset: setPVar(changesOnlyInterval, (MLMicroSeconds)(aPropValue->doubleValue()*Second)); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }
ErrorPtr PropertyContainer::accessProperty(PropertyAccessMode aMode, ApiValuePtr aQueryObject, ApiValuePtr aResultObject, int aDomain, PropertyDescriptorPtr aParentDescriptor) { ErrorPtr err; #if DEBUGFOCUSLOGGING FOCUSLOG("\naccessProperty: entered with query = %s\n", aQueryObject->description().c_str()); if (aParentDescriptor) { FOCUSLOG("- parentDescriptor '%s' (%s), fieldKey=%u, objectKey=%u\n", aParentDescriptor->name(), aParentDescriptor->isStructured() ? "structured" : "scalar", aParentDescriptor->fieldKey(), aParentDescriptor->objectKey()); } #endif // for reading, NULL query is like query { "":NULL } if (aQueryObject->isNull() && aMode==access_read) { aQueryObject->setType(apivalue_object); aQueryObject->add("", aQueryObject->newValue(apivalue_null)); } // aApiObject must be of type apivalue_object if (!aQueryObject->isType(apivalue_object)) return ErrorPtr(new VdcApiError(415, "Query or Value written must be object")); if (aMode==access_read) { if (!aResultObject) return ErrorPtr(new VdcApiError(415, "accessing property for read must provide result object")); aResultObject->setType(apivalue_object); // must be object } // Iterate trough elements of query object aQueryObject->resetKeyIteration(); string queryName; ApiValuePtr queryValue; string errorMsg; while (aQueryObject->nextKeyValue(queryName, queryValue)) { FOCUSLOG("- starting to process query element named '%s' : %s\n", queryName.c_str(), queryValue->description().c_str()); if (aMode==access_read && queryName=="#") { // asking for number of elements at this level -> generate and return int value queryValue = queryValue->newValue(apivalue_int64); // integer queryValue->setInt32Value(numProps(aDomain, aParentDescriptor)); aResultObject->add(queryName, queryValue); } else { // accessing an element or series of elements at this level bool wildcard = isMatchAll(queryName); // - find all descriptor(s) for this queryName PropertyDescriptorPtr propDesc; int propIndex = 0; bool foundone = false; do { propDesc = getDescriptorByName(queryName, propIndex, aDomain, aParentDescriptor); if (propDesc) { foundone = true; // found at least one descriptor for this query element FOCUSLOG(" - processing descriptor '%s' (%s), fieldKey=%u, objectKey=%u\n", propDesc->name(), propDesc->isStructured() ? "structured" : "scalar", propDesc->fieldKey(), propDesc->objectKey()); // actually access by descriptor if (propDesc->isStructured()) { ApiValuePtr subQuery; // property is a container. Now check the value if (queryValue->isType(apivalue_object)) { subQuery = queryValue; // query specifies next level, just use it } else if (queryName!="*" && (!wildcard || propDesc->isWildcardAddressable())) { // don't recurse deeper when query name is "*" or property is not wildcard-adressable // special case is "*" as leaf in query - only recurse if it is not present // - autocreate subquery subQuery = queryValue->newValue(apivalue_object); subQuery->add("", queryValue->newValue(apivalue_null)); } if (subQuery) { // addressed property is a container by itself -> recurse // - get the PropertyContainer int containerDomain = aDomain; // default to same, but getContainer may modify it PropertyDescriptorPtr containerPropDesc = propDesc; PropertyContainerPtr container = getContainer(containerPropDesc, containerDomain); if (container) { FOCUSLOG(" - container for '%s' is 0x%p\n", propDesc->name(), container.get()); FOCUSLOG(" >>>> RECURSING into accessProperty()\n"); if (aMode==access_read) { // read needs a result object ApiValuePtr resultValue = queryValue->newValue(apivalue_object); err = container->accessProperty(aMode, subQuery, resultValue, containerDomain, containerPropDesc); if (Error::isOK(err)) { // add to result with actual name (from descriptor) FOCUSLOG("\n <<<< RETURNED from accessProperty() recursion\n"); FOCUSLOG(" - accessProperty of container for '%s' returns %s\n", propDesc->name(), resultValue->description().c_str()); aResultObject->add(propDesc->name(), resultValue); } } else { // for write, just pass the query value err = container->accessProperty(aMode, subQuery, ApiValuePtr(), containerDomain, containerPropDesc); FOCUSLOG(" <<<< RETURNED from accessProperty() recursion\n", propDesc->name(), container.get()); } if ((aMode!=access_read) && Error::isOK(err)) { // give this container a chance to post-process write access err = writtenProperty(aMode, propDesc, aDomain, container); } // 404 errors are collected, but dont abort the query if (Error::isError(err, VdcApiError::domain(), 404)) { if (!errorMsg.empty()) errorMsg += "; "; errorMsg += string_format("Error(s) accessing subproperties of '%s' : { %s }", queryName.c_str(), err->description().c_str()); err.reset(); // forget the error on this level } } } } else { // addressed (and known by descriptor!) property is a simple value field -> access it if (aMode==access_read) { // read access: create a new apiValue and have it filled ApiValuePtr fieldValue = queryValue->newValue(propDesc->type()); // create a value of correct type to get filled bool accessOk = accessField(aMode, fieldValue, propDesc); // read // for read, not getting an OK from accessField means: property does not exist (even if known per descriptor), // so it will not be added to the result if (accessOk) { // add to result with actual name (from descriptor) aResultObject->add(propDesc->name(), fieldValue); } FOCUSLOG(" - accessField for '%s' returns %s\n", propDesc->name(), fieldValue->description().c_str()); } else { // write access: just pass the value if (!accessField(aMode, queryValue, propDesc)) { // write err = ErrorPtr(new VdcApiError(403,string_format("Write access to '%s' denied", propDesc->name()))); } } } } else { // no descriptor found for this query element // Note: this means that property is not KNOWN, which IS not the same as getting false from accessField // (latter means that property IS known, but has no value in the context it was queried) // HOWEVER, for the vdc API it was decided that for reading, these cases should NOT be // distinguished for getProperty. If a property does not exist for either reason, the return tree just does // no contain that property. // Also note that not having a property is not the same as not having a property VALUE: // latter case will explicitly return a NULL value if (!wildcard && !foundone && aMode!=access_read) { // query did address a specific property but it is unknown -> report as error (for read AND write!) // - collect error message, but do not abort query processing if (!errorMsg.empty()) errorMsg += "; "; errorMsg += string_format("Unknown property '%s' -> ignored", queryName.c_str()); } } } while (Error::isOK(err) && propIndex!=PROPINDEX_NONE); } // now generate error if we have collected a non-empty error message if (!errorMsg.empty()) { err = ErrorPtr(new VdcApiError(404,errorMsg)); } #if DEBUGLOGGING if (aMode==access_read) { FOCUSLOG("- query element named '%s' now has result object: %s\n", queryName.c_str(), aResultObject->description().c_str()); } #endif } return err; }
ErrorPtr DaliDeviceContainer::handleMethod(VdcApiRequestPtr aRequest, const string &aMethod, ApiValuePtr aParams) { ErrorPtr respErr; if (aMethod=="x-p44-groupDevices") { // create a composite device out of existing single-channel ones ApiValuePtr components; long long collectionID = -1; DeviceVector groupedDevices; respErr = checkParam(aParams, "members", components); if (Error::isOK(respErr)) { if (components->isType(apivalue_object)) { components->resetKeyIteration(); string dimmerType; ApiValuePtr o; while (components->nextKeyValue(dimmerType, o)) { DsUid memberUID; memberUID.setAsBinary(o->binaryValue()); bool deviceFound = false; // search for this device for (DeviceVector::iterator pos = devices.begin(); pos!=devices.end(); ++pos) { // only non-grouped DALI devices can be grouped DaliDevicePtr dev = boost::dynamic_pointer_cast<DaliDevice>(*pos); if (dev && dev->getDsUid() == memberUID) { deviceFound = true; // found this device, create DB entry for it db.executef( "INSERT OR REPLACE INTO compositeDevices (dimmerUID, dimmerType, collectionID) VALUES ('%s','%s',%lld)", memberUID.getString().c_str(), dimmerType.c_str(), collectionID ); if (collectionID<0) { // use rowid of just inserted item as collectionID collectionID = db.last_insert_rowid(); // - update already inserted first record db.executef( "UPDATE compositeDevices SET collectionID=%lld WHERE ROWID=%lld", collectionID, collectionID ); } // remember groupedDevices.push_back(dev); // done break; } } if (!deviceFound) { respErr = ErrorPtr(new WebError(404, "some devices of the group could not be found")); break; } } if (Error::isOK(respErr) && groupedDevices.size()>0) { // all components inserted into DB // - remove grouped single devices for (DeviceVector::iterator pos = groupedDevices.begin(); pos!=groupedDevices.end(); ++pos) { (*pos)->hasVanished(false); // vanish, but keep settings } // - re-collect devices to find grouped composite now, but only in a second starting from main loop, not from here CompletedCB cb = boost::bind(&DaliDeviceContainer::groupCollected, this, aRequest); MainLoop::currentMainLoop().executeOnce(boost::bind(&DaliDeviceContainer::collectDevices, this, cb, false, false), 1*Second); } } } } else { respErr = inherited::handleMethod(aRequest, aMethod, aParams); } return respErr; }
// access to all fields bool ChannelBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(channel_Key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case name_key+descriptions_key_offset: aPropValue->setStringValue(getName()); return true; case channelIndex_key+descriptions_key_offset: if (aPropertyDescriptor->getApiVersion()>=3) return false; // property does not exist any more in v3 and later aPropValue->setUint8Value(channelIndex); return true; case dsIndex_key+descriptions_key_offset: aPropValue->setUint8Value(channelIndex); return true; case channelType_key+descriptions_key_offset: aPropValue->setUint8Value(getChannelType()); return true; case siunit_key+descriptions_key_offset: aPropValue->setStringValue(valueUnitName(getChannelUnit(), false)); return true; case unitsymbol_key+descriptions_key_offset: aPropValue->setStringValue(valueUnitName(getChannelUnit(), true)); return true; case min_key+descriptions_key_offset: aPropValue->setDoubleValue(getMin()); return true; case max_key+descriptions_key_offset: aPropValue->setDoubleValue(getMax()); return true; case resolution_key+descriptions_key_offset: aPropValue->setDoubleValue(getResolution()); return true; // Settings properties // - none for now // States properties case value_key+states_key_offset: // get value of channel, possibly calculating it if needed (color conversions) aPropValue->setDoubleValue(getChannelValueCalculated()); return true; case age_key+states_key_offset: if (channelLastSync==Never) aPropValue->setNull(); // no value known else aPropValue->setDoubleValue((double)(MainLoop::now()-channelLastSync)/Second); // time of last sync (does not necessarily relate to currently visible "value", as this might be a to-be-applied new value already) return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties // - none for now // States properties case value_key+states_key_offset: setChannelValue(aPropValue->doubleValue(), output.transitionTime, true); // always apply, default transition time (normally 0, unless set in outputState) return true; } } } // single class level properties only, don't call inherited return false; }
ApiValuePtr JsonApiValue::newValue(ApiValueType aObjectType) { ApiValuePtr newVal = ApiValuePtr(new JsonApiValue); newVal->setType(aObjectType); return newVal; }
ErrorPtr VdcJsonApiConnection::sendRequest(const string &aMethod, ApiValuePtr aParams, VdcApiResponseCB aResponseHandler) { JsonApiValuePtr params = boost::dynamic_pointer_cast<JsonApiValue>(aParams); ErrorPtr err; if (aResponseHandler) { // method call expecting response err = jsonRpcComm->sendRequest(aMethod.c_str(), params->jsonObject(), boost::bind(&VdcJsonApiConnection::jsonResponseHandler, this, aResponseHandler, _1, _2, _3)); LOG(LOG_INFO,"vdSM <- vDC (JSON) method call sent: requestid='%d', method='%s', params=%s\n", jsonRpcComm->lastRequestId(), aMethod.c_str(), aParams ? aParams->description().c_str() : "<none>"); } else { // notification err = jsonRpcComm->sendRequest(aMethod.c_str(), params->jsonObject(), NULL); LOG(LOG_INFO,"vdSM <- vDC (JSON) notification sent: method='%s', params=%s\n", aMethod.c_str(), aParams ? aParams->description().c_str() : "<none>"); } return err; }
ErrorPtr VdcJsonApiRequest::sendResult(ApiValuePtr aResult) { LOG(LOG_INFO,"vdSM <- vDC (JSON) result sent: requestid='%s', result=%s\n", requestId().c_str(), aResult ? aResult->description().c_str() : "<none>"); JsonApiValuePtr result = boost::dynamic_pointer_cast<JsonApiValue>(aResult); return jsonConnection->jsonRpcComm->sendResult(requestId().c_str(), result ? result->jsonObject() : NULL); }
// access to vdc API methods and notifications via web requests ErrorPtr P44VdcHost::processVdcRequest(JsonCommPtr aJsonComm, JsonObjectPtr aRequest) { ErrorPtr err; string cmd; bool isMethod = false; // get method/notification and params JsonObjectPtr m = aRequest->get("method"); if (m) { // is a method call, expects answer isMethod = true; } else { // not method, may be notification m = aRequest->get("notification"); } if (!m) { err = Error::err<P44VdcError>(400, "invalid request, must specify 'method' or 'notification'"); } else { // get method/notification name cmd = m->stringValue(); // get params // Note: the "method" or "notification" param will also be in the params, but should not cause any problem ApiValuePtr params = JsonApiValue::newValueFromJson(aRequest); P44JsonApiRequestPtr request = P44JsonApiRequestPtr(new P44JsonApiRequest(aJsonComm)); if (Error::isOK(err)) { // operation method if (isMethod) { // create request // check for old-style name/index and generate basic query (1 or 2 levels) ApiValuePtr query = params->newObject(); ApiValuePtr name = params->get("name"); if (name) { ApiValuePtr index = params->get("index"); ApiValuePtr subquery = params->newNull(); if (index) { // subquery subquery->setType(apivalue_object); subquery->add(index->stringValue(), subquery->newNull()); } string nm = trimWhiteSpace(name->stringValue()); // to allow a single space for deep recursing wildcard query->add(nm, subquery); params->add("query", query); } // have method handled err = handleMethodForParams(request, cmd, params); // Note: if method returns NULL, it has sent or will send results itself. // Otherwise, even if Error is ErrorOK we must send a generic response } else { // handle notification err = handleNotificationForParams(request->connection(), cmd, params); // Notifications are always immediately confirmed, so make sure there's an explicit ErrorOK if (!err) { err = ErrorPtr(new Error(Error::OK)); } } } } // returning NULL means caller should not do anything more // returning an Error object (even ErrorOK) means caller should return status return err; }
bool OutputBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(output_groups_key)) { if (aMode==access_read) { // read group membership if (isMember((DsGroup)aPropertyDescriptor->fieldKey())) { aPropValue->setBoolValue(true); return true; } return false; } else { // write group setGroupMembership((DsGroup)aPropertyDescriptor->fieldKey(), aPropValue->boolValue()); return true; } } else if (aPropertyDescriptor->hasObjectKey(output_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case outputFunction_key+descriptions_key_offset: aPropValue->setUint8Value(outputFunction); return true; case outputUsage_key+descriptions_key_offset: aPropValue->setUint16Value(outputUsage); return true; case variableRamp_key+descriptions_key_offset: aPropValue->setBoolValue(variableRamp); return true; case maxPower_key+descriptions_key_offset: aPropValue->setDoubleValue(maxPower); return true; // Settings properties case mode_key+settings_key_offset: aPropValue->setUint8Value(actualOutputMode()); // return actual mode, never outputmode_default return true; case pushChanges_key+settings_key_offset: aPropValue->setBoolValue(pushChanges); return true; // State properties case localPriority_key+states_key_offset: aPropValue->setBoolValue(localPriority); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties case mode_key+settings_key_offset: setOutputMode((DsOutputMode)aPropValue->int32Value()); return true; case pushChanges_key+settings_key_offset: setPVar(pushChanges, aPropValue->boolValue()); return true; // State properties case localPriority_key+states_key_offset: setPVar(localPriority, aPropValue->boolValue()); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }