/** * @file GoSensorInfo.c * * @internal * Copyright (C) 2016-2021 by LMI Technologies Inc. * Licensed under the MIT License. * Redistributed files must retain the above copyright notice. */ #include #include kBeginClassEx(Go, GoSensorInfo) kEndClassEx() GoFx(kStatus) GoSensorInfo_Construct(GoSensorInfo* info, kAlloc allocator) { kAlloc alloc = kAlloc_Fallback(allocator); kStatus status; kCheck(kAlloc_GetObject(alloc, kTypeOf(GoSensorInfo), info)); if (!kSuccess(status = GoSensorInfo_Init(*info, kTypeOf(GoSensorInfo), alloc))) { kAlloc_FreeRef(alloc, info); } return status; } GoFx(kStatus) GoSensorInfo_Init(GoSensorInfo info, kType type, kAlloc alloc) { kObjR(GoSensorInfo, info); kCheck(kObject_Init(info, type, alloc)); obj->id = 0; kZero(obj->firmwareVersion); obj->partNumber[0] = 0; obj->buddyId = 0; obj->address = kIpAddress_AnyV4(); obj->mainId = 0; obj->buddyableStatus = GO_BUDDY_STATE_ERROR; obj->role = GO_ROLE_MAIN; obj->state = GO_STATE_OFFLINE; obj->modelNumber[0] = 0; obj->modelDisplayName[0] = 0; return kOK; } GoFx(kStatus) GoSensorInfo_Read(GoSensorInfo info, kSerializer serializer) { kObj(GoSensorInfo, info); k32s temp; kByte tempArray[4]; kSize i; kCheck(kSerializer_Read32u(serializer, &obj->id)); kCheck(kSerializer_ReadByteArray(serializer, tempArray, kCountOf(tempArray))); for (i = 0; i < 16; i++) { if (i < 4) { obj->address.address[i] = tempArray[i]; } else { obj->address.address[i] = 0; } } //hack for now // modelName is deprecated, underlying var is renamed to partNumber for clarity. kCheck(kSerializer_ReadCharArray(serializer, obj->partNumber, kCountOf(obj->partNumber))); kCheck(kSerializer_ReadByteArray(serializer, tempArray, kCountOf(tempArray))); obj->firmwareVersion = kVersion_Create(tempArray[0], tempArray[1], tempArray[2], tempArray[3]); kCheck(kSerializer_Read32s(serializer, &temp)); switch(temp) { case -1: obj->state = GO_STATE_INCOMPLETE; break; case 0: obj->state = GO_STATE_READY; break; case 1: obj->state = GO_STATE_RUNNING; break; default: obj->state = GO_STATE_CONNECTED; break; } kCheck(kSerializer_Read32s(serializer, &obj->role)); kCheck(kSerializer_Read32s(serializer, &obj->buddyId)); // Even for very old sensors, we can still provide fallback modelNumber and display name. kCheck(GoSensorInfo_FillModelNumber(info, obj->partNumber, obj->modelNumber, kCountOf(obj->modelNumber))); kCheck(GoSensorInfo_FillModelDisplayName(info, obj->partNumber, obj->modelDisplayName, kCountOf(obj->modelDisplayName))); return kOK; } GoFx(kStatus) GoSensorInfo_ReadV2(GoSensorInfo info, kSerializer serializer, k16u sensorInfoSize, kBool isLocalInfo) { kObj(GoSensorInfo, info); k32s temp; k32u bytesRead = 0; kByte tempArray[4]; kSize i; kCheck(kSerializer_Read32u(serializer, &obj->id)); kCheck(kSerializer_ReadByteArray(serializer, tempArray, kCountOf(tempArray))); for (i = 0; i < 16; i++) { if (i < 4) { obj->address.address[i] = tempArray[i]; } else { obj->address.address[i] = 0; } } //hack for now // modelName is deprecated, underlying var is renamed to partNumber for clarity. kCheck(kSerializer_ReadCharArray(serializer, obj->partNumber, kCountOf(obj->partNumber))); kCheck(kSerializer_ReadByteArray(serializer, tempArray, kCountOf(tempArray))); obj->firmwareVersion = kVersion_Create(tempArray[0], tempArray[1], tempArray[2], tempArray[3]); kCheck(kSerializer_Read32s(serializer, &temp)); switch (temp) { case -1: obj->state = GO_STATE_INCOMPLETE; break; case 0: obj->state = GO_STATE_READY; break; case 1: obj->state = GO_STATE_RUNNING; break; default: obj->state = GO_STATE_CONNECTED; break; } kCheck(kSerializer_Read32s(serializer, &obj->role)); bytesRead = 52; //SensorInfoV2 is variable size, so need to track the number of bytes read in case a future sensor version is sending more data than what this version expects if (!isLocalInfo) { kCheck(kSerializer_Read32u(serializer, &obj->mainId)); kCheck(kSerializer_Read32s(serializer, &obj->buddyableStatus)); bytesRead += 8; } // During 5.3 Beta, before 5.3.10.31 if (sensorInfoSize - bytesRead == 0) { // Provide fallback values for modelNumber and modelDisplayName. kCheck(GoSensorInfo_FillModelNumber(info, obj->partNumber, obj->modelNumber, kCountOf(obj->modelNumber))); kCheck(GoSensorInfo_FillModelDisplayName(info, obj->partNumber, obj->modelDisplayName, kCountOf(obj->modelDisplayName))); } // During 5.3 Beta for 5.3.10.31 - 5.3.17.23. else if (sensorInfoSize - bytesRead == kCountOf(obj->modelDisplayName)) { // Read modelDisplayName, and provide fallback values for modelNumber. kCheck(GoSensorInfo_FillModelNumber(info, obj->partNumber, obj->modelNumber, kCountOf(obj->modelNumber))); kCheck(kSerializer_ReadCharArray(serializer, obj->modelDisplayName, kCountOf(obj->modelDisplayName))); bytesRead += kCountOf(obj->modelDisplayName); } // During 5.3 Beta for 5.3.17.23 and onwards.. to 5.3 Release else if (sensorInfoSize - bytesRead >= kCountOf(obj->modelDisplayName) + kCountOf(obj->modelNumber)) { // Read modelNumber and modelDisplayName. kCheck(kSerializer_ReadCharArray(serializer, obj->modelNumber, kCountOf(obj->modelNumber))); bytesRead += kCountOf(obj->modelNumber); kCheck(kSerializer_ReadCharArray(serializer, obj->modelDisplayName, kCountOf(obj->modelDisplayName))); bytesRead += kCountOf(obj->modelDisplayName); } kCheck(kSerializer_AdvanceRead(serializer, sensorInfoSize - bytesRead)); return kOK; } GoFx(k32u) GoSensorInfo_Id(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->id; } GoFx(kVersion) GoSensorInfo_Firmware(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->firmwareVersion; } // deprecated GoFx(kStatus) GoSensorInfo_Model(GoSensorInfo info, kChar* model, kSize capacity) { kObj(GoSensorInfo, info); // modelName is deprecated, provide the original behavior which was to return partNumber. return GoSensorInfo_PartNumber(info, model, capacity); } GoFx(kStatus) GoSensorInfo_PartNumber(GoSensorInfo info, kChar* partNumber, kSize capacity) { kObj(GoSensorInfo, info); // NOTE: the partnumber returned in the remote info is actually the "Derived LMI PartNumber", // which hides branding customizations, and may not fully match the true part number // that is available in GoSensor_PartNumber(). return kStrCopy(partNumber, capacity, obj->partNumber); } GoFx(kStatus) GoSensorInfo_ModelNumber(GoSensorInfo info, kChar* modelNumber, kSize capacity) { kObj(GoSensorInfo, info); return kStrCopy(modelNumber, capacity, obj->modelNumber); } GoFx(kStatus) GoSensorInfo_ModelDisplayName(GoSensorInfo info, kChar* modelDisplayName, kSize capacity) { kObj(GoSensorInfo, info); return kStrCopy(modelDisplayName, capacity, obj->modelDisplayName); } GoFx(GoRole) GoSensorInfo_Role(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->role; } GoFx(kBool) GoSensorInfo_HasBuddy(GoSensorInfo info) { kObj(GoSensorInfo, info); return (obj->buddyId != 0); } GoFx(k32u) GoSensorInfo_BuddyId(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->buddyId; } GoFx(GoState) GoSensorInfo_State(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->state; } GoFx(GoBuddyState) GoSensorInfo_BuddyableStatus(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->buddyableStatus; } GoFx(k32s) GoSensorInfo_buddyableStatus(GoSensorInfo info) { return GoSensorInfo_BuddyableStatus(info); } GoFx(k32u) GoSensorInfo_MainId(GoSensorInfo info) { kObj(GoSensorInfo, info); return obj->mainId; } GoFx(kStatus) GoSensorInfo_FillModelNumber(GoSensorInfo info, kChar *partNumber, kChar *fallBackModelNumber, kSize capacity) { kObj(GoSensorInfo, info); const char* pos = kNULL; kString tempString = kNULL; k32s tempCleanNum = kNULL; kArrayList tokens = kNULL; kStatus exception; kTry { kTest(kString_Construct(&tempString, partNumber, kObject_Alloc(info))); kTest(kString_Split(tempString, "-", &tokens, kObject_Alloc(info))); if(kArrayList_Count(tokens) == 0) { // This is the same fallback as in GsDevice_ParseModelNumber(). kTest(kStrCopy(fallBackModelNumber, capacity, "2300")); } else { // We take the first token in the part number after the two-digit class (31, 33), // then convert to a number to get rid of A,B,C suffixes. // ie. 33250A-3B-R-52-S // ^^^ = "250" // // 312330C-2M-R-01-T // ^^^^ = "2330" // kTest(k32s_Parse(&tempCleanNum, kString_Chars(kArrayList_AsT(tokens, 0, kString)) + 2)); kTest(k32s_Format(tempCleanNum, fallBackModelNumber, capacity)); } } kCatchEx(&exception) { kLogf("%s: cannot fill model number into capacity[%u] from '%s'", __FUNCTION__, capacity, partNumber); kEndCatchEx(exception); } kFinallyEx { kDestroyRef(&tempString); kDisposeRef(&tokens); kEndFinallyEx(); } return kOK; } GoFx(kStatus) GoSensorInfo_FillModelDisplayName(GoSensorInfo info, kChar * partNumber, kChar *fallBackModelDisplayName, kSize capacity) { kObj(GoSensorInfo, info); return GoSensorInfo_FillModelNumber(info, partNumber, fallBackModelDisplayName, capacity); }