From 72604ec957bd831a97ca2c402a0dd3ab381cb92e Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Thu, 6 Apr 2017 01:34:40 +0300 Subject: Add FW & config deployment library (WIP, Argon not supported yet) --- SimpleMotionV2.pri | 4 +- smdeploymenttool.c | 634 +++++++++++++++++++++++++++++++++++++++++++++++++++++ smdeploymenttool.h | 89 ++++++++ 3 files changed, 725 insertions(+), 2 deletions(-) create mode 100644 smdeploymenttool.c create mode 100644 smdeploymenttool.h diff --git a/SimpleMotionV2.pri b/SimpleMotionV2.pri index b5619bc..7254e17 100644 --- a/SimpleMotionV2.pri +++ b/SimpleMotionV2.pri @@ -6,9 +6,9 @@ DEPENDPATH += $$PWD DEFINES += SIMPLEMOTIONV2_LIBRARY SOURCES += $$PWD/sm_consts.c $$PWD/simplemotion.c $$PWD/busdevice.c $$PWD/pcserialport.c \ - $$PWD/bufferedmotion.c + $$PWD/bufferedmotion.c $$PWD/smdeploymenttool.c HEADERS += $$PWD/simplemotion_private.h\ $$PWD/pcserialport.h $$PWD/busdevice.h $$PWD/simplemotion.h $$PWD/sm485.h $$PWD/simplemotion_defs.h \ - $$PWD/bufferedmotion.h + $$PWD/bufferedmotion.h $$PWD/smdeploymenttool.h diff --git a/smdeploymenttool.c b/smdeploymenttool.c new file mode 100644 index 0000000..f1f1931 --- /dev/null +++ b/smdeploymenttool.c @@ -0,0 +1,634 @@ +#include "smdeploymenttool.h" +#include +#include +#include +#include + +#ifdef __unix__ +#include +void sleep_ms(int millisecs) +{ + msleep(millisecs); +} +#else +#include +void sleep_ms(int millisecs) +{ + Sleep(millisecs); +} +#endif + +int globalErrorDetailCode=0; + +int smGetDeploymentToolErrroDetail() +{ + return globalErrorDetailCode; +} + +//return -1 if EOF +unsigned int readFileLine( FILE *f, int charlimit, char *output, smbool *eof) +{ + int len=0; + char c; + do + { + c=fgetc(f); + + if(feof(f)) + *eof=smtrue; + else + *eof=smfalse; + + //eol or eof + if( *eof==smtrue || c=='\n' || c=='\r' || len>=charlimit-1 ) + { + output[len]=0;//terminate str + return len; + } + + output[len]=c; + len++; + } while(1); + return len; +} + +smbool parseParameter(FILE *f, int idx, smint32 *paramaddr, smint32 *value, smbool *readonly) +{ + const int maxLineLen=100; + char line[maxLineLen]; + char scanline[maxLineLen]; + //search correct row + fseek(f,0,SEEK_SET); + smbool gotaddr=smfalse,gotvalue=smfalse, gotreadonly=smfalse, readRDonly; + int readAddr, readValue; + unsigned int readbytes; + smbool eof; + + do//loop trhu all lines of file + { + readbytes=readFileLine(f,maxLineLen,line,&eof);//read line + + //try read address + sprintf(scanline,"%d\\addr=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%d",&readAddr)==1)//parse number after the start of line + gotaddr=smtrue;//number parse success + + //try read value + sprintf(scanline,"%d\\value=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%d",&readValue)==1)//parse number after the start of line + gotvalue=smtrue;//number parse success + + //try read readonly status + sprintf(scanline,"%d\\readonly=true",idx);//check if readonly=true + if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match + { + readRDonly=smtrue; + gotreadonly=smtrue; + } + sprintf(scanline,"%d\\readonly=false",idx);//check if readonly=false + if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match + { + readRDonly=smfalse; + gotreadonly=smtrue; + } + } + while( (gotvalue==smfalse || gotaddr==smfalse || gotreadonly==smfalse) && eof==smfalse ); + + if(gotvalue==smtrue&&gotaddr==smtrue) + { + *paramaddr=readAddr; + *value=readValue; + *readonly=readRDonly; + return smtrue; + } + + return smfalse;//not found +} + +/** + * @brief smConfigureParameters Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param filename .DRC file name + * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). + * @return Enum LoadConfigurationStatus + * + * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. + */ +LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smaddress, const char *filename, unsigned int mode , int *skippedCount, int *errorCount) +{ + //test connection + smint32 devicetype; + SM_STATUS stat; + FILE *f; + int ignoredCount=0; + int setErrors=0; + smint32 CB1Value; + int changed=0; + + *skippedCount=-1; + *errorCount=-1; + + //test connection + stat=smRead1Parameter(smhandle,smaddress,SMP_DEVICE_TYPE,&devicetype); + if(stat!=SM_OK) + return CFGCommunicationError; + + //smSetParameter( smhandle, smaddress, SMP_RETURN_PARAM_LEN, SMPRET_CMD_STATUS );//get command status as feedback from each executed SM command + + if(mode&CONFIGMODE_DISABLE_DURING_CONFIG) + { + smRead1Parameter( smhandle, smaddress, SMP_CONTROL_BITS1, &CB1Value ); + smSetParameter( smhandle, smaddress, SMP_CONTROL_BITS1, 0);//disable drive + } + + if(getCumulativeStatus( smhandle )!=SM_OK ) + return CFGCommunicationError; + + f=fopen(filename,"rb"); + if(f==NULL) + return CFGUnableToOpenFile; + + smDebug(smhandle,Low,"Setting parameters\n"); + + int i=1; + smbool readOk; + do + { + smint32 readAddr, readValue; + smbool isReadOnly; + readOk=parseParameter(f,i,&readAddr,&readValue,&isReadOnly); + + if(readOk==smtrue && isReadOnly==smfalse) + { + smint32 currentValue; + //set parameter to device + if(smRead1Parameter( smhandle, smaddress, readAddr, ¤tValue )==SM_OK) + { + if(currentValue!=readValue ) //set only if different + { + resetCumulativeStatus( smhandle ); + smint32 dummy; + smint32 cmdSetAddressStatus; + smint32 cmdSetValueStatus; + + //use low level SM commands so we can get execution status of each subpacet: + smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, SMP_RETURN_PARAM_LEN ); + smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_24B, SMPRET_CMD_STATUS ); + smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, readAddr ); + smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_32B, readValue ); + smExecuteCommandQueue( smhandle, smaddress ); + smGetQueuedSMCommandReturnValue( smhandle, &dummy ); + smGetQueuedSMCommandReturnValue( smhandle, &dummy ); + smGetQueuedSMCommandReturnValue( smhandle, &cmdSetAddressStatus ); + smGetQueuedSMCommandReturnValue( smhandle, &cmdSetValueStatus ); + + //check if above code succeed + if( getCumulativeStatus(smhandle)!=SM_OK || cmdSetAddressStatus!=SMP_CMD_STATUS_ACK || cmdSetValueStatus!=SMP_CMD_STATUS_ACK ) + { + SM_STATUS stat=getCumulativeStatus(smhandle); + setErrors++; + smDebug(smhandle,Low,"Failed to write parameter value %d to address %d (status: %d %d %d)\n",readValue,readAddr,(int)stat,cmdSetAddressStatus,cmdSetValueStatus); + } + + changed++; + } + } + else//device doesn't have such parameter. perhaps wrong model or fw version. + { + ignoredCount++; + smDebug(smhandle,Low,"Ignoring parameter parameter value %d to address %d\n",readValue,readAddr); + } + } + + i++; + } while(readOk==smtrue); + + *skippedCount=ignoredCount; + *errorCount=setErrors; + + resetCumulativeStatus( smhandle ); + + //save to flash if some value was changed + if(changed>0) + smSetParameter( smhandle, smaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_SAVECFG ); + + if(mode&CONFIGMODE_CLEAR_FAULTS_AFTER_CONFIG ) + { + smDebug(smhandle,Low,"Restting faults\n"); + smSetParameter( smhandle, smaddress, SMP_FAULTS, 0 );//reset faults + } + + //re-enable drive + if(mode&CONFIGMODE_DISABLE_DURING_CONFIG) + { + smDebug(smhandle,Low,"Restoring CONTROL_BITS1 to value 0x%x\n",CB1Value); + smSetParameter( smhandle, smaddress, SMP_CONTROL_BITS1, CB1Value );//restore controbits1 (enable if it was enabled before) + } + + smint32 statusbits; + smRead1Parameter( smhandle, smaddress, SMP_STATUS, &statusbits ); + + //restart drive if necessary or if forced + if( (statusbits&STAT_PERMANENT_STOP) || (mode&CONFIGMODE_ALWAYS_RESTART_TARGET) ) + { + smDebug(smhandle,Low,"Restarting device\n"); + smSetParameter( smhandle, smaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_RESTART ); + sleep_ms(2000);//wait power-on + } + + if(getCumulativeStatus(smhandle)!=SM_OK) + return CFGCommunicationError; + + return CFGComplete; +} + +/** + * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. + * @param UID result will be written to this pointer + * @return smtrue if success, smfalse if failed (if communication otherwise works, then probably UID feature not present in this firmware version) + */ +smbool smGetDeviceFirmwareUniqueID( smbus smhandle, int deviceaddress, smuint32 *UID )//FIXME gives questionable value if device is in DFU mode. Check FW side. +{ + smint32 fwBinaryChecksum; + resetCumulativeStatus(smhandle); + smSetParameter( smhandle, deviceaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_GET_SPECIAL_DATA); + smRead1Parameter( smhandle, deviceaddress, SMP_DEBUGPARAM1, &fwBinaryChecksum ); + *UID=(smuint32) fwBinaryChecksum; + + if(getCumulativeStatus(smhandle)==SM_OK) + return smtrue; + else + return smfalse; +} + +FirmwareUploadStatus verifyFirmwareData(smuint8 *data, smuint32 numbytes, int connectedDeviceTypeId, + smuint32 *primaryMCUDataOffset, smuint32 *primaryMCUDataLenth, + smuint32 *secondaryMCUDataOffset,smuint32 *secondaryMCUDataLength ) +{ + //see http://granitedevices.com/wiki/Argon_firmware_file_format + + smuint32 filetype; + filetype=((smuint32*)data)[0]; + if(filetype!=0x57464447) //check header string "GDFW" + return FWInvalidFile; + + smuint16 filever, deviceid; + smuint32 primaryMCUSize, secondaryMCUSize; + + filever=((smuint16*)data)[2]; + deviceid=((smuint16*)data)[3]; + primaryMCUSize=((smuint32*)data)[2]; + secondaryMCUSize=((smuint32*)data)[3]; + if(secondaryMCUSize==0xffffffff) + secondaryMCUSize=0;//it is not present + + if(filever!=300) + return FWIncompatibleFW; + + if(deviceid/1000!=connectedDeviceTypeId/1000)//compare only device and model family. AABBCC so AAB is compared value, ARGON=004 IONI=011 + return FWIncompatibleFW; + + //get checksum and check it + smuint32 cksum,cksumcalc=0; + smuint32 i; + smuint32 cksumOffset=4+2+2+4+4+primaryMCUSize+secondaryMCUSize; + if(cksumOffset>numbytes-4) + return FWInvalidFile; + cksum=((smuint32*)((smuint32)data+cksumOffset))[0]; + + for(i=0;i< numbytes-4;i++) + { + cksumcalc+=data[i]; + } + + if(cksum!=cksumcalc) + return FWIncompatibleFW; + + //let caller know where the firmware data is located in buffer + *primaryMCUDataOffset=4+2+2+4+4; + *primaryMCUDataLenth=primaryMCUSize; + *secondaryMCUDataOffset=*primaryMCUDataOffset+*primaryMCUDataLenth; + *secondaryMCUDataLength=secondaryMCUSize; + + return FWComplete; +} + +smbool loadBinaryFile( const char *filename, smuint8 **data, int *numbytes ) +{ + FILE *f; + f=fopen(filename,"rb"); + if(f==NULL) + return smfalse; + + *numbytes=0; + + //get length + fseek(f,0,SEEK_END); + int length=ftell(f); + fseek(f,0,SEEK_SET); + + //allocate buffer + *data=malloc(length); + if(*data==NULL) + return smfalse; + + //read + *numbytes=fread(*data,1,length,f); + if(*numbytes!=length)//failed to read it all + { + free(*data); + *numbytes=0; + return smfalse; + } + + return smtrue;//successl +} + + + +//flashing STM32 (host side mcu) +smbool flashFirmwarePrimaryMCU( smbus smhandle, int deviceaddress, const smuint8 *data, smint32 size, int *progress ) +{ + smint32 ret; + static smint32 deviceType, fwVersion; + static int uploadIndex; + int c; + const int BL_CHUNK_LEN=32; + static enum {Init,Upload,Finish} state=Init; + + if(state==Init) + { + resetCumulativeStatus( smhandle ); + smRead2Parameters( smhandle, deviceaddress, SMP_FIRMWARE_VERSION, &fwVersion, SMP_DEVICE_TYPE,&deviceType ); + + if(getCumulativeStatus(smhandle)!=SM_OK) + { + state=Init; + return smfalse; + } + +/* kommentoitu pois koska ei haluta erasoida parskuja koska parametri SMO ei saisi nollautua mielellään + + if(deviceType!=4000)//argon does not support BL function 11 + smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,11);//BL func on ioni 11 = do mass erase on STM32, also confifuration + else//does not reset on ioni and drives that support preserving settings. but resets on argon +*/ + smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,1);//BL func 1 = do mass erase on STM32. On Non-Argon devices it doesn't reset confifuration + + sleep_ms(2000);//wait some time. 500ms too little 800ms barely enough + + //flash + smSetParameter(smhandle,deviceaddress,SMP_RETURN_PARAM_LEN, SMPRET_CMD_STATUS); + + if(getCumulativeStatus(smhandle)!=SM_OK) + { + state=Init; + return smfalse; + } + + state=Upload; + uploadIndex=0; + *progress=5; + } + else if(state==Upload) + { + size/=2;//bytes to 16 bit words + + //upload data in 32=BL_CHUNK_LEN word chunks + for(;uploadIndex=size) + upword=0xeeee; + else + upword=((smuint16*)data)[uploadIndex]; + smAppendSMCommandToQueue( smhandle, SMPCMD_24B, upword ); + uploadIndex++; + } + + smAppendSMCommandToQueue( smhandle, SMPCMD_SETPARAMADDR, SMP_BOOTLOADER_FUNCTION ); + smAppendSMCommandToQueue( smhandle, SMPCMD_24B, 2);//BL func 2 = do write on STM32 + smExecuteCommandQueue( smhandle, deviceaddress ); + + //read return packets + for(c=0;c=94)//95 will indicate that progress is complete. dont let it indicate that yet. + *progress=94; + + if(uploadIndex%256==0) + { + //printf("upload %d\n",uploadIndex); + return smtrue;//in progress. return often to make upload non-blocking + } + } + if(uploadIndex>=size)//finished + { + state=Finish; + } + } + else if(state==Finish) + { + //verify STM32 flash if supported by BL version + if(fwVersion>=1210) + { + smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,3);//BL func 3 = verify STM32 FW integrity + smint32 faults; + smRead1Parameter(smhandle,deviceaddress,SMP_FAULTS,&faults); + + if(getCumulativeStatus(smhandle)!=SM_OK) + { + state=Init; + *progress=0; + return smfalse; + } + + if(faults&FLT_FLASHING_COMMSIDE_FAIL) + { + //printf("verify failed\n"); + *progress=0; + state=Init; + return smfalse; + } + else + { + //printf("verify success\n"); + } + } + + *progress=95;//my job is complete + state=Init; + } + + return smtrue; +} + + +typedef enum { StatIdle=0, StatEnterDFU, StatFindDFUDevice, StatLoadFile, StatUpload, StatLaunch } UploadState;//state machine status + +//free buffer and return given status code +FirmwareUploadStatus abortFWUpload( FirmwareUploadStatus stat, smuint8 *fwData, UploadState *state, int errorDetailCode ) +{ + globalErrorDetailCode=errorDetailCode; + *state=StatIdle; + free(fwData); + return stat; +} + +/** + * @brief smFirmwareUpload Sets drive in firmware upgrade mode if necessary and uploads a new firmware. Call this many until it returns value 100 (complete) or a negative value (error). + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. + * @param filename .gdf file name + * @return Enum FirmwareUploadStatus that indicates errors or Complete status. Typecast to integer to get progress value 0-100. + */ +FirmwareUploadStatus smFirmwareUpload( const smbus smhandle, const int smaddress, const char *firmware_filename ) +{ + static smuint8 *fwData=NULL; + static int fwDataLength; + static smuint32 primaryMCUDataOffset, primaryMCUDataLenth; + static smuint32 secondaryMCUDataOffset,secondaryMCUDataLength; + static UploadState state=StatIdle;//state machine status + static smint32 deviceType=0; + static int DFUAddress; + static int progress=0; + + SM_STATUS stat; + + //state machine + if(state==StatIdle) + { + + //check if device is in DFU mode already + smint32 busMode; + stat=smRead2Parameters(smhandle,smaddress,SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); + if(stat==SM_OK && busMode==SMP_BUS_MODE_DFU) + { + state=StatLoadFile; + } + else if(stat==SM_OK && busMode!=0)//device not in bus mode + { + if(deviceType==4000)//argon does not support restarting in DFU mode by software + { + return abortFWUpload(FWConnectionError,fwData,&state,200); + } + + //restart device into DFU mode + state=StatEnterDFU; + + stat=smSetParameter(smhandle,smaddress,SMP_SYSTEM_CONTROL,64);//reset device to DFU command + if(stat!=SM_OK) + return abortFWUpload(FWConnectionError,fwData,&state,300); + } + else + state=StatFindDFUDevice;//search DFU device in brute force, fallback for older BL versions that don't preserve same smaddress than non-DFU mode + //return abortFWUpload(FWConnectionError,fwData,&state,301); + + progress=1; + DFUAddress=smaddress; + } + + else if(state==StatEnterDFU) + { + sleep_ms(2500);//wait device to reboot in DFU mode. probably shorter delay would do. + + //check if device is in DFU mode already + smint32 busMode; + stat=smRead2Parameters(smhandle,smaddress, SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); + if(stat==SM_OK && busMode==0)//busmode 0 is DFU mode + { + state=StatLoadFile; + } + else + state=StatFindDFUDevice;//search DFU device in brute force, fallback for older BL versions that don't preserve same smaddress than non-DFU mode + + progress=2; + } + + else if(state==StatFindDFUDevice) + { + int i; + for(i=245;i<=255;i++) + { + smint32 busMode; + stat=smRead2Parameters(smhandle,i, SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); + if(stat==SM_OK && busMode==0)//busmode 0 is DFU mode + { + state=StatLoadFile; + DFUAddress=i; + break;//DFU found, break out of for loop + } + } + + if(i==256)//DFU device not found + return abortFWUpload(CFGConnectingDFUModeFailed,fwData,&state,400);//setting DFU mode failed + + progress=3; + } + + else if(state==StatLoadFile) + { + if(loadBinaryFile(firmware_filename,&fwData,&fwDataLength)!=smtrue) + return FWFileNotReadable; + + FirmwareUploadStatus stat=verifyFirmwareData(fwData, fwDataLength, deviceType, + &primaryMCUDataOffset, &primaryMCUDataLenth, + &secondaryMCUDataOffset, &secondaryMCUDataLength); + if(stat!=FWComplete)//error in verify + { + return abortFWUpload(stat,fwData,&state,100); + } + + //all good, upload firmware + state=StatUpload; + + progress=4; + } + + else if(state==StatUpload) + { + smbool ret=flashFirmwarePrimaryMCU(smhandle,DFUAddress,fwData+primaryMCUDataOffset,primaryMCUDataLenth,&progress); + if(ret==smfalse)//failed + { + return abortFWUpload(FWConnectionError,fwData,&state,1000); + } + else + { + if(progress>=95) + state=StatLaunch; + } + } + + else if(state==StatLaunch) + { + smSetParameter(smhandle,DFUAddress,SMP_BOOTLOADER_FUNCTION,4);//BL func 4 = launch. + sleep_ms(2000); + progress=100; + state=StatIdle; + } + + return (FirmwareUploadStatus)progress; +} + + + + diff --git a/smdeploymenttool.h b/smdeploymenttool.h new file mode 100644 index 0000000..8838664 --- /dev/null +++ b/smdeploymenttool.h @@ -0,0 +1,89 @@ +#ifndef SMDEPLOYMENTTOOL_H +#define SMDEPLOYMENTTOOL_H + +#ifdef WIN32 +//dll specs +#ifdef BUILD_DLL + #define LIB __declspec(dllexport) +#else +// #define LIB __declspec(dllimport) +#define LIB +#endif +#else +#define LIB +#endif + + +#include "simplemotion.h" + + +#ifdef __cplusplus +extern "C"{ +#endif + + +typedef enum +{ + FWComplete=100, + FWInvalidFile=-1, + FWConnectionError=-2, + FWIncompatibleFW=-3, + FWConnectionLoss=-4, + FWUnsupportedTargetDevice=-5, + FWFileNotReadable=-6 +} FirmwareUploadStatus; + +/** + * @brief smFirmwareUpload Sets drive in firmware upgrade mode if necessary and uploads a new firmware. Call this many until it returns value 100 (complete) or a negative value (error). + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param filename .gdf file name + * @return Enum FirmwareUploadStatus that indicates errors or Complete status. Typecast to integer to get progress value 0-100. + */ +LIB FirmwareUploadStatus smFirmwareUpload(const smbus smhandle, const int smaddress, const char *firmware_filename ); + +typedef enum +{ + CFGComplete=100, + CFGInvalidFile=-1, + CFGCommunicationError=-2, + CFGConnectingDFUModeFailed=-3, + CFGIncompatibleFW=-4, + CFGUnsupportedTargetDevice=-5, + CFGUnableToOpenFile=-6 + +} LoadConfigurationStatus; + +//TODO implement: #define CONFIGMODE_REQUIRE_SAME_FW 1 //will return IncompatibleFW if firmware checksum does not match the one in .drc files. if this error is returned, perform smFirmwareUpload and perform smLoadConfiguration again. Requires DRC file version 111 or later (if not met, returns InvalidFile). +#define CONFIGMODE_ALWAYS_RESTART_TARGET 2 //will perform device restart after setup even when it's not required +#define CONFIGMODE_DISABLE_DURING_CONFIG 4 //will set device in disabled state during configuration +#define CONFIGMODE_CLEAR_FAULTS_AFTER_CONFIG 8 //will perform clear faults command after configuration + +/** + * @brief smConfigureParameters Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param filename .DRC file name + * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). + * @return Enum LoadConfigurationStatus + * + * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. + */ +LIB LoadConfigurationStatus smLoadConfiguration( const smbus smhandle, const int smaddress, const char *filename, unsigned int mode, int *skippedCount, int *errorCount ); + + +/** + * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. + * @param UID result will be written to this pointer + * @return smtrue if success, smfalse if failed (if communication otherwise works, then probably UID feature not present in this firmware version) + */ +smbool smGetDeviceFirmwareUniqueID( smbus smhandle, int deviceaddress, smuint32 *UID ); + + + +#ifdef __cplusplus +} +#endif +#endif // SMDEPLOYMENTTOOL_H -- cgit v1.2.3 From a780e4b1123dbc416dd06af9ee2d7f99f281a9c7 Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Thu, 6 Apr 2017 02:22:19 +0300 Subject: Add proper parameter value conversion --- smdeploymenttool.c | 64 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/smdeploymenttool.c b/smdeploymenttool.c index f1f1931..2551128 100644 --- a/smdeploymenttool.c +++ b/smdeploymenttool.c @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef __unix__ #include @@ -52,15 +53,23 @@ unsigned int readFileLine( FILE *f, int charlimit, char *output, smbool *eof) return len; } -smbool parseParameter(FILE *f, int idx, smint32 *paramaddr, smint32 *value, smbool *readonly) +typedef struct +{ + int address; + double value; + smbool readOnly; + double scale; + double offset; +} Parameter; + +smbool parseParameter(FILE *f, int idx, Parameter *param ) { const int maxLineLen=100; char line[maxLineLen]; char scanline[maxLineLen]; //search correct row fseek(f,0,SEEK_SET); - smbool gotaddr=smfalse,gotvalue=smfalse, gotreadonly=smfalse, readRDonly; - int readAddr, readValue; + smbool gotaddr=smfalse,gotvalue=smfalse, gotreadonly=smfalse, gotscale=smfalse,gotoffset=smfalse; unsigned int readbytes; smbool eof; @@ -71,36 +80,45 @@ smbool parseParameter(FILE *f, int idx, smint32 *paramaddr, smint32 *value, smbo //try read address sprintf(scanline,"%d\\addr=",idx); if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line - if(sscanf(line+strlen(scanline),"%d",&readAddr)==1)//parse number after the start of line + if(sscanf(line+strlen(scanline),"%d",¶m->address)==1)//parse number after the start of line gotaddr=smtrue;//number parse success //try read value sprintf(scanline,"%d\\value=",idx); if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line - if(sscanf(line+strlen(scanline),"%d",&readValue)==1)//parse number after the start of line + if(sscanf(line+strlen(scanline),"%lf",¶m->value)==1)//parse number after the start of line gotvalue=smtrue;//number parse success + //try read offset + sprintf(scanline,"%d\\offset=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%lf",¶m->offset)==1)//parse number after the start of line + gotoffset=smtrue;//number parse success + + //try read scale + sprintf(scanline,"%d\\scaling=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%lf",¶m->scale)==1)//parse number after the start of line + gotscale=smtrue;//number parse success + //try read readonly status sprintf(scanline,"%d\\readonly=true",idx);//check if readonly=true if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match { - readRDonly=smtrue; + param->readOnly=smtrue; gotreadonly=smtrue; } sprintf(scanline,"%d\\readonly=false",idx);//check if readonly=false if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match { - readRDonly=smfalse; + param->readOnly=smfalse; gotreadonly=smtrue; } } - while( (gotvalue==smfalse || gotaddr==smfalse || gotreadonly==smfalse) && eof==smfalse ); + while( (gotvalue==smfalse || gotaddr==smfalse || gotreadonly==smfalse || gotscale==smfalse || gotoffset==smfalse) && eof==smfalse ); - if(gotvalue==smtrue&&gotaddr==smtrue) + if(gotvalue==smtrue&&gotaddr==smtrue&&gotoffset==smtrue&&gotscale==smtrue&&gotreadonly==smtrue) { - *paramaddr=readAddr; - *value=readValue; - *readonly=readRDonly; return smtrue; } @@ -157,17 +175,19 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad smbool readOk; do { - smint32 readAddr, readValue; - smbool isReadOnly; - readOk=parseParameter(f,i,&readAddr,&readValue,&isReadOnly); + Parameter param; + readOk=parseParameter(f,i,¶m); - if(readOk==smtrue && isReadOnly==smfalse) + if(readOk==smtrue && param.readOnly==smfalse) { smint32 currentValue; + + int configFileValue=round(param.value*param.scale-param.offset); + //set parameter to device - if(smRead1Parameter( smhandle, smaddress, readAddr, ¤tValue )==SM_OK) + if(smRead1Parameter( smhandle, smaddress, param.address, ¤tValue )==SM_OK) { - if(currentValue!=readValue ) //set only if different + if(currentValue!=configFileValue ) //set only if different { resetCumulativeStatus( smhandle ); smint32 dummy; @@ -177,8 +197,8 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad //use low level SM commands so we can get execution status of each subpacet: smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, SMP_RETURN_PARAM_LEN ); smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_24B, SMPRET_CMD_STATUS ); - smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, readAddr ); - smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_32B, readValue ); + smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, param.address ); + smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_32B, configFileValue ); smExecuteCommandQueue( smhandle, smaddress ); smGetQueuedSMCommandReturnValue( smhandle, &dummy ); smGetQueuedSMCommandReturnValue( smhandle, &dummy ); @@ -190,7 +210,7 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad { SM_STATUS stat=getCumulativeStatus(smhandle); setErrors++; - smDebug(smhandle,Low,"Failed to write parameter value %d to address %d (status: %d %d %d)\n",readValue,readAddr,(int)stat,cmdSetAddressStatus,cmdSetValueStatus); + smDebug(smhandle,Low,"Failed to write parameter value %d to address %d (status: %d %d %d)\n",configFileValue,param.address,(int)stat,cmdSetAddressStatus,cmdSetValueStatus); } changed++; @@ -199,7 +219,7 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad else//device doesn't have such parameter. perhaps wrong model or fw version. { ignoredCount++; - smDebug(smhandle,Low,"Ignoring parameter parameter value %d to address %d\n",readValue,readAddr); + smDebug(smhandle,Low,"Ignoring parameter parameter value %d to address %d\n",configFileValue,param.address); } } -- cgit v1.2.3 From 1d6f69d1f056777401bcdfcde0844c9b9af1cbac Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Thu, 6 Apr 2017 17:06:50 +0300 Subject: Update readme.md & rename library files --- README.md | 36 ++- SimpleMotionV2.pri | 4 +- devicedeployment.c | 654 +++++++++++++++++++++++++++++++++++++++++++++++++++++ devicedeployment.h | 100 ++++++++ smdeploymenttool.c | 654 ----------------------------------------------------- smdeploymenttool.h | 89 -------- 6 files changed, 790 insertions(+), 747 deletions(-) create mode 100644 devicedeployment.c create mode 100644 devicedeployment.h delete mode 100644 smdeploymenttool.c delete mode 100644 smdeploymenttool.h diff --git a/README.md b/README.md index 88b0006..1b2e53a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,39 @@ SimpleMotionV2 ============== -SimpleMotion V2 library +This is a SimpleMotion V2 library, which is an API to control motor controller from any programmable platform, such as PC, PLC or MCU. -For more information, see: +For main documentation, see: http://granitedevices.com/wiki/SimpleMotion_V2 + + +Files & usage +============= + +There are files that are needed for basic SimpleMotion usage, and files that are optional and needed only for certain features. Following may be useful info when porting library to different platforms (such as embedded MCU) to avoid unnecessary work on some files. + +Compulsory +---------- + +- simplemotion.c/.h +- sm485.h +- sm_consts.c +- simplemotion_defs.h +- simplemotion_private.h +- busdevice.c/.h + +Platform specific +----------------- +Following files probably need modification if ported to another platform + +- pcserialport.c/.h - Contains a driver for communication device interface. This driver controls serial/COM port on Unix & Windows. Also busdevice.c/.h need to be modified accordingly if this driver is removed or modified. + +A typical platform port would involve writing a communication driver that implements same functions as pcserialport.c and adding their relevant calls to busdevice.c/.h. + +Feature specific +---------------- + +- bufferedmotion.c/.h - Library used for buffered motion stream applications +- devicedeployment.c/.h - Library used for installing firmware and loading settings into target devices. Can be used to configure devices automatically in-system. + +For practical usage examples, refer to https://github.com/GraniteDevices/SimpleMotionV2Examples \ No newline at end of file diff --git a/SimpleMotionV2.pri b/SimpleMotionV2.pri index 7254e17..9d2caf5 100644 --- a/SimpleMotionV2.pri +++ b/SimpleMotionV2.pri @@ -6,9 +6,9 @@ DEPENDPATH += $$PWD DEFINES += SIMPLEMOTIONV2_LIBRARY SOURCES += $$PWD/sm_consts.c $$PWD/simplemotion.c $$PWD/busdevice.c $$PWD/pcserialport.c \ - $$PWD/bufferedmotion.c $$PWD/smdeploymenttool.c + $$PWD/bufferedmotion.c $$PWD/devicedeployment.c HEADERS += $$PWD/simplemotion_private.h\ $$PWD/pcserialport.h $$PWD/busdevice.h $$PWD/simplemotion.h $$PWD/sm485.h $$PWD/simplemotion_defs.h \ - $$PWD/bufferedmotion.h $$PWD/smdeploymenttool.h + $$PWD/bufferedmotion.h $$PWD/devicedeployment.h diff --git a/devicedeployment.c b/devicedeployment.c new file mode 100644 index 0000000..bdb718d --- /dev/null +++ b/devicedeployment.c @@ -0,0 +1,654 @@ +#include "devicedeployment.h" +#include +#include +#include +#include +#include + +#ifdef __unix__ +#include +void sleep_ms(int millisecs) +{ + msleep(millisecs); +} +#else +#include +void sleep_ms(int millisecs) +{ + Sleep(millisecs); +} +#endif + +int globalErrorDetailCode=0; + +int smGetDeploymentToolErrroDetail() +{ + return globalErrorDetailCode; +} + +//return -1 if EOF +unsigned int readFileLine( FILE *f, int charlimit, char *output, smbool *eof) +{ + int len=0; + char c; + do + { + c=fgetc(f); + + if(feof(f)) + *eof=smtrue; + else + *eof=smfalse; + + //eol or eof + if( *eof==smtrue || c=='\n' || c=='\r' || len>=charlimit-1 ) + { + output[len]=0;//terminate str + return len; + } + + output[len]=c; + len++; + } while(1); + return len; +} + +typedef struct +{ + int address; + double value; + smbool readOnly; + double scale; + double offset; +} Parameter; + +smbool parseParameter(FILE *f, int idx, Parameter *param ) +{ + const int maxLineLen=100; + char line[maxLineLen]; + char scanline[maxLineLen]; + //search correct row + fseek(f,0,SEEK_SET); + smbool gotaddr=smfalse,gotvalue=smfalse, gotreadonly=smfalse, gotscale=smfalse,gotoffset=smfalse; + unsigned int readbytes; + smbool eof; + + do//loop trhu all lines of file + { + readbytes=readFileLine(f,maxLineLen,line,&eof);//read line + + //try read address + sprintf(scanline,"%d\\addr=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%d",¶m->address)==1)//parse number after the start of line + gotaddr=smtrue;//number parse success + + //try read value + sprintf(scanline,"%d\\value=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%lf",¶m->value)==1)//parse number after the start of line + gotvalue=smtrue;//number parse success + + //try read offset + sprintf(scanline,"%d\\offset=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%lf",¶m->offset)==1)//parse number after the start of line + gotoffset=smtrue;//number parse success + + //try read scale + sprintf(scanline,"%d\\scaling=",idx); + if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line + if(sscanf(line+strlen(scanline),"%lf",¶m->scale)==1)//parse number after the start of line + gotscale=smtrue;//number parse success + + //try read readonly status + sprintf(scanline,"%d\\readonly=true",idx);//check if readonly=true + if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match + { + param->readOnly=smtrue; + gotreadonly=smtrue; + } + sprintf(scanline,"%d\\readonly=false",idx);//check if readonly=false + if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match + { + param->readOnly=smfalse; + gotreadonly=smtrue; + } + } + while( (gotvalue==smfalse || gotaddr==smfalse || gotreadonly==smfalse || gotscale==smfalse || gotoffset==smfalse) && eof==smfalse ); + + if(gotvalue==smtrue&&gotaddr==smtrue&&gotoffset==smtrue&&gotscale==smtrue&&gotreadonly==smtrue) + { + return smtrue; + } + + return smfalse;//not found +} + +/** + * @brief smConfigureParameters Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param filename .DRC file name + * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). + * @return Enum LoadConfigurationStatus + * + * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. + */ +LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smaddress, const char *filename, unsigned int mode , int *skippedCount, int *errorCount) +{ + //test connection + smint32 devicetype; + SM_STATUS stat; + FILE *f; + int ignoredCount=0; + int setErrors=0; + smint32 CB1Value; + int changed=0; + + *skippedCount=-1; + *errorCount=-1; + + //test connection + stat=smRead1Parameter(smhandle,smaddress,SMP_DEVICE_TYPE,&devicetype); + if(stat!=SM_OK) + return CFGCommunicationError; + + //smSetParameter( smhandle, smaddress, SMP_RETURN_PARAM_LEN, SMPRET_CMD_STATUS );//get command status as feedback from each executed SM command + + if(mode&CONFIGMODE_DISABLE_DURING_CONFIG) + { + smRead1Parameter( smhandle, smaddress, SMP_CONTROL_BITS1, &CB1Value ); + smSetParameter( smhandle, smaddress, SMP_CONTROL_BITS1, 0);//disable drive + } + + if(getCumulativeStatus( smhandle )!=SM_OK ) + return CFGCommunicationError; + + f=fopen(filename,"rb"); + if(f==NULL) + return CFGUnableToOpenFile; + + smDebug(smhandle,Low,"Setting parameters\n"); + + int i=1; + smbool readOk; + do + { + Parameter param; + readOk=parseParameter(f,i,¶m); + + if(readOk==smtrue && param.readOnly==smfalse) + { + smint32 currentValue; + + int configFileValue=round(param.value*param.scale-param.offset); + + //set parameter to device + if(smRead1Parameter( smhandle, smaddress, param.address, ¤tValue )==SM_OK) + { + if(currentValue!=configFileValue ) //set only if different + { + resetCumulativeStatus( smhandle ); + smint32 dummy; + smint32 cmdSetAddressStatus; + smint32 cmdSetValueStatus; + + //use low level SM commands so we can get execution status of each subpacet: + smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, SMP_RETURN_PARAM_LEN ); + smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_24B, SMPRET_CMD_STATUS ); + smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, param.address ); + smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_32B, configFileValue ); + smExecuteCommandQueue( smhandle, smaddress ); + smGetQueuedSMCommandReturnValue( smhandle, &dummy ); + smGetQueuedSMCommandReturnValue( smhandle, &dummy ); + smGetQueuedSMCommandReturnValue( smhandle, &cmdSetAddressStatus ); + smGetQueuedSMCommandReturnValue( smhandle, &cmdSetValueStatus ); + + //check if above code succeed + if( getCumulativeStatus(smhandle)!=SM_OK || cmdSetAddressStatus!=SMP_CMD_STATUS_ACK || cmdSetValueStatus!=SMP_CMD_STATUS_ACK ) + { + SM_STATUS stat=getCumulativeStatus(smhandle); + setErrors++; + smDebug(smhandle,Low,"Failed to write parameter value %d to address %d (status: %d %d %d)\n",configFileValue,param.address,(int)stat,cmdSetAddressStatus,cmdSetValueStatus); + } + + changed++; + } + } + else//device doesn't have such parameter. perhaps wrong model or fw version. + { + ignoredCount++; + smDebug(smhandle,Low,"Ignoring parameter parameter value %d to address %d\n",configFileValue,param.address); + } + } + + i++; + } while(readOk==smtrue); + + *skippedCount=ignoredCount; + *errorCount=setErrors; + + resetCumulativeStatus( smhandle ); + + //save to flash if some value was changed + if(changed>0) + smSetParameter( smhandle, smaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_SAVECFG ); + + if(mode&CONFIGMODE_CLEAR_FAULTS_AFTER_CONFIG ) + { + smDebug(smhandle,Low,"Restting faults\n"); + smSetParameter( smhandle, smaddress, SMP_FAULTS, 0 );//reset faults + } + + //re-enable drive + if(mode&CONFIGMODE_DISABLE_DURING_CONFIG) + { + smDebug(smhandle,Low,"Restoring CONTROL_BITS1 to value 0x%x\n",CB1Value); + smSetParameter( smhandle, smaddress, SMP_CONTROL_BITS1, CB1Value );//restore controbits1 (enable if it was enabled before) + } + + smint32 statusbits; + smRead1Parameter( smhandle, smaddress, SMP_STATUS, &statusbits ); + + //restart drive if necessary or if forced + if( (statusbits&STAT_PERMANENT_STOP) || (mode&CONFIGMODE_ALWAYS_RESTART_TARGET) ) + { + smDebug(smhandle,Low,"Restarting device\n"); + smSetParameter( smhandle, smaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_RESTART ); + sleep_ms(2000);//wait power-on + } + + if(getCumulativeStatus(smhandle)!=SM_OK) + return CFGCommunicationError; + + return CFGComplete; +} + +/** + * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. + * @param UID result will be written to this pointer + * @return smtrue if success, smfalse if failed (if communication otherwise works, then probably UID feature not present in this firmware version) + */ +smbool smGetDeviceFirmwareUniqueID( smbus smhandle, int deviceaddress, smuint32 *UID )//FIXME gives questionable value if device is in DFU mode. Check FW side. +{ + smint32 fwBinaryChecksum; + resetCumulativeStatus(smhandle); + smSetParameter( smhandle, deviceaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_GET_SPECIAL_DATA); + smRead1Parameter( smhandle, deviceaddress, SMP_DEBUGPARAM1, &fwBinaryChecksum ); + *UID=(smuint32) fwBinaryChecksum; + + if(getCumulativeStatus(smhandle)==SM_OK) + return smtrue; + else + return smfalse; +} + +FirmwareUploadStatus verifyFirmwareData(smuint8 *data, smuint32 numbytes, int connectedDeviceTypeId, + smuint32 *primaryMCUDataOffset, smuint32 *primaryMCUDataLenth, + smuint32 *secondaryMCUDataOffset,smuint32 *secondaryMCUDataLength ) +{ + //see http://granitedevices.com/wiki/Argon_firmware_file_format + + smuint32 filetype; + filetype=((smuint32*)data)[0]; + if(filetype!=0x57464447) //check header string "GDFW" + return FWInvalidFile; + + smuint16 filever, deviceid; + smuint32 primaryMCUSize, secondaryMCUSize; + + filever=((smuint16*)data)[2]; + deviceid=((smuint16*)data)[3]; + primaryMCUSize=((smuint32*)data)[2]; + secondaryMCUSize=((smuint32*)data)[3]; + if(secondaryMCUSize==0xffffffff) + secondaryMCUSize=0;//it is not present + + if(filever!=300) + return FWIncompatibleFW; + + if(deviceid/1000!=connectedDeviceTypeId/1000)//compare only device and model family. AABBCC so AAB is compared value, ARGON=004 IONI=011 + return FWIncompatibleFW; + + //get checksum and check it + smuint32 cksum,cksumcalc=0; + smuint32 i; + smuint32 cksumOffset=4+2+2+4+4+primaryMCUSize+secondaryMCUSize; + if(cksumOffset>numbytes-4) + return FWInvalidFile; + cksum=((smuint32*)((smuint32)data+cksumOffset))[0]; + + for(i=0;i< numbytes-4;i++) + { + cksumcalc+=data[i]; + } + + if(cksum!=cksumcalc) + return FWIncompatibleFW; + + //let caller know where the firmware data is located in buffer + *primaryMCUDataOffset=4+2+2+4+4; + *primaryMCUDataLenth=primaryMCUSize; + *secondaryMCUDataOffset=*primaryMCUDataOffset+*primaryMCUDataLenth; + *secondaryMCUDataLength=secondaryMCUSize; + + return FWComplete; +} + +smbool loadBinaryFile( const char *filename, smuint8 **data, int *numbytes ) +{ + FILE *f; + f=fopen(filename,"rb"); + if(f==NULL) + return smfalse; + + *numbytes=0; + + //get length + fseek(f,0,SEEK_END); + int length=ftell(f); + fseek(f,0,SEEK_SET); + + //allocate buffer + *data=malloc(length); + if(*data==NULL) + return smfalse; + + //read + *numbytes=fread(*data,1,length,f); + if(*numbytes!=length)//failed to read it all + { + free(*data); + *numbytes=0; + return smfalse; + } + + return smtrue;//successl +} + + + +//flashing STM32 (host side mcu) +smbool flashFirmwarePrimaryMCU( smbus smhandle, int deviceaddress, const smuint8 *data, smint32 size, int *progress ) +{ + smint32 ret; + static smint32 deviceType, fwVersion; + static int uploadIndex; + int c; + const int BL_CHUNK_LEN=32; + static enum {Init,Upload,Finish} state=Init; + + if(state==Init) + { + resetCumulativeStatus( smhandle ); + smRead2Parameters( smhandle, deviceaddress, SMP_FIRMWARE_VERSION, &fwVersion, SMP_DEVICE_TYPE,&deviceType ); + + if(getCumulativeStatus(smhandle)!=SM_OK) + { + state=Init; + return smfalse; + } + +/* kommentoitu pois koska ei haluta erasoida parskuja koska parametri SMO ei saisi nollautua mielellään + + if(deviceType!=4000)//argon does not support BL function 11 + smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,11);//BL func on ioni 11 = do mass erase on STM32, also confifuration + else//does not reset on ioni and drives that support preserving settings. but resets on argon +*/ + smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,1);//BL func 1 = do mass erase on STM32. On Non-Argon devices it doesn't reset confifuration + + sleep_ms(2000);//wait some time. 500ms too little 800ms barely enough + + //flash + smSetParameter(smhandle,deviceaddress,SMP_RETURN_PARAM_LEN, SMPRET_CMD_STATUS); + + if(getCumulativeStatus(smhandle)!=SM_OK) + { + state=Init; + return smfalse; + } + + state=Upload; + uploadIndex=0; + *progress=5; + } + else if(state==Upload) + { + size/=2;//bytes to 16 bit words + + //upload data in 32=BL_CHUNK_LEN word chunks + for(;uploadIndex=size) + upword=0xeeee; + else + upword=((smuint16*)data)[uploadIndex]; + smAppendSMCommandToQueue( smhandle, SMPCMD_24B, upword ); + uploadIndex++; + } + + smAppendSMCommandToQueue( smhandle, SMPCMD_SETPARAMADDR, SMP_BOOTLOADER_FUNCTION ); + smAppendSMCommandToQueue( smhandle, SMPCMD_24B, 2);//BL func 2 = do write on STM32 + smExecuteCommandQueue( smhandle, deviceaddress ); + + //read return packets + for(c=0;c=94)//95 will indicate that progress is complete. dont let it indicate that yet. + *progress=94; + + if(uploadIndex%256==0) + { + //printf("upload %d\n",uploadIndex); + return smtrue;//in progress. return often to make upload non-blocking + } + } + if(uploadIndex>=size)//finished + { + state=Finish; + } + } + else if(state==Finish) + { + //verify STM32 flash if supported by BL version + if(fwVersion>=1210) + { + smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,3);//BL func 3 = verify STM32 FW integrity + smint32 faults; + smRead1Parameter(smhandle,deviceaddress,SMP_FAULTS,&faults); + + if(getCumulativeStatus(smhandle)!=SM_OK) + { + state=Init; + *progress=0; + return smfalse; + } + + if(faults&FLT_FLASHING_COMMSIDE_FAIL) + { + //printf("verify failed\n"); + *progress=0; + state=Init; + return smfalse; + } + else + { + //printf("verify success\n"); + } + } + + *progress=95;//my job is complete + state=Init; + } + + return smtrue; +} + + +typedef enum { StatIdle=0, StatEnterDFU, StatFindDFUDevice, StatLoadFile, StatUpload, StatLaunch } UploadState;//state machine status + +//free buffer and return given status code +FirmwareUploadStatus abortFWUpload( FirmwareUploadStatus stat, smuint8 *fwData, UploadState *state, int errorDetailCode ) +{ + globalErrorDetailCode=errorDetailCode; + *state=StatIdle; + free(fwData); + return stat; +} + +/** + * @brief smFirmwareUpload Sets drive in firmware upgrade mode if necessary and uploads a new firmware. Call this many until it returns value 100 (complete) or a negative value (error). + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. + * @param filename .gdf file name + * @return Enum FirmwareUploadStatus that indicates errors or Complete status. Typecast to integer to get progress value 0-100. + */ +FirmwareUploadStatus smFirmwareUpload( const smbus smhandle, const int smaddress, const char *firmware_filename ) +{ + static smuint8 *fwData=NULL; + static int fwDataLength; + static smuint32 primaryMCUDataOffset, primaryMCUDataLenth; + static smuint32 secondaryMCUDataOffset,secondaryMCUDataLength; + static UploadState state=StatIdle;//state machine status + static smint32 deviceType=0; + static int DFUAddress; + static int progress=0; + + SM_STATUS stat; + + //state machine + if(state==StatIdle) + { + + //check if device is in DFU mode already + smint32 busMode; + stat=smRead2Parameters(smhandle,smaddress,SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); + if(stat==SM_OK && busMode==SMP_BUS_MODE_DFU) + { + state=StatLoadFile; + } + else if(stat==SM_OK && busMode!=0)//device not in bus mode + { + if(deviceType==4000)//argon does not support restarting in DFU mode by software + { + return abortFWUpload(FWConnectionError,fwData,&state,200); + } + + //restart device into DFU mode + state=StatEnterDFU; + + stat=smSetParameter(smhandle,smaddress,SMP_SYSTEM_CONTROL,64);//reset device to DFU command + if(stat!=SM_OK) + return abortFWUpload(FWConnectionError,fwData,&state,300); + } + else + state=StatFindDFUDevice;//search DFU device in brute force, fallback for older BL versions that don't preserve same smaddress than non-DFU mode + //return abortFWUpload(FWConnectionError,fwData,&state,301); + + progress=1; + DFUAddress=smaddress; + } + + else if(state==StatEnterDFU) + { + sleep_ms(2500);//wait device to reboot in DFU mode. probably shorter delay would do. + + //check if device is in DFU mode already + smint32 busMode; + stat=smRead2Parameters(smhandle,smaddress, SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); + if(stat==SM_OK && busMode==0)//busmode 0 is DFU mode + { + state=StatLoadFile; + } + else + state=StatFindDFUDevice;//search DFU device in brute force, fallback for older BL versions that don't preserve same smaddress than non-DFU mode + + progress=2; + } + + else if(state==StatFindDFUDevice) + { + int i; + for(i=245;i<=255;i++) + { + smint32 busMode; + stat=smRead2Parameters(smhandle,i, SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); + if(stat==SM_OK && busMode==0)//busmode 0 is DFU mode + { + state=StatLoadFile; + DFUAddress=i; + break;//DFU found, break out of for loop + } + } + + if(i==256)//DFU device not found + return abortFWUpload(CFGConnectingDFUModeFailed,fwData,&state,400);//setting DFU mode failed + + progress=3; + } + + else if(state==StatLoadFile) + { + if(loadBinaryFile(firmware_filename,&fwData,&fwDataLength)!=smtrue) + return FWFileNotReadable; + + FirmwareUploadStatus stat=verifyFirmwareData(fwData, fwDataLength, deviceType, + &primaryMCUDataOffset, &primaryMCUDataLenth, + &secondaryMCUDataOffset, &secondaryMCUDataLength); + if(stat!=FWComplete)//error in verify + { + return abortFWUpload(stat,fwData,&state,100); + } + + //all good, upload firmware + state=StatUpload; + + progress=4; + } + + else if(state==StatUpload) + { + smbool ret=flashFirmwarePrimaryMCU(smhandle,DFUAddress,fwData+primaryMCUDataOffset,primaryMCUDataLenth,&progress); + if(ret==smfalse)//failed + { + return abortFWUpload(FWConnectionError,fwData,&state,1000); + } + else + { + if(progress>=95) + state=StatLaunch; + } + } + + else if(state==StatLaunch) + { + smSetParameter(smhandle,DFUAddress,SMP_BOOTLOADER_FUNCTION,4);//BL func 4 = launch. + sleep_ms(2000); + progress=100; + state=StatIdle; + } + + return (FirmwareUploadStatus)progress; +} + + + + diff --git a/devicedeployment.h b/devicedeployment.h new file mode 100644 index 0000000..f6fa08e --- /dev/null +++ b/devicedeployment.h @@ -0,0 +1,100 @@ +/* Device deployment library based on SimpleMotionV2 lib. Features: + * + * - install .gdf format firmware to drive + * - load .drc settings file to drive + * - read installed firmware binary checksum from device - this may be used to verify that exact correct FW build is installed in the drive + * + * TODO: + * - Support Argon. Currently tested only on IONI/ATOMI series drives. Currently FW upgrade on Argon will fail, but settings load may work. + * - Add some way of reading binary checksum from .gdf file or settings file. Now user must read it from device and store that number somewhere manually. + */ + +#ifndef SMDEPLOYMENTTOOL_H +#define SMDEPLOYMENTTOOL_H + +#ifdef WIN32 +//dll specs +#ifdef BUILD_DLL + #define LIB __declspec(dllexport) +#else +// #define LIB __declspec(dllimport) +#define LIB +#endif +#else +#define LIB +#endif + + +#include "simplemotion.h" + + +#ifdef __cplusplus +extern "C"{ +#endif + + +typedef enum +{ + FWComplete=100, + FWInvalidFile=-1, + FWConnectionError=-2, + FWIncompatibleFW=-3, + FWConnectionLoss=-4, + FWUnsupportedTargetDevice=-5, + FWFileNotReadable=-6 +} FirmwareUploadStatus; + +/** + * @brief smFirmwareUpload Sets drive in firmware upgrade mode if necessary and uploads a new firmware. Call this many until it returns value 100 (complete) or a negative value (error). + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param filename .gdf file name + * @return Enum FirmwareUploadStatus that indicates errors or Complete status. Typecast to integer to get progress value 0-100. + */ +LIB FirmwareUploadStatus smFirmwareUpload(const smbus smhandle, const int smaddress, const char *firmware_filename ); + +typedef enum +{ + CFGComplete=100, + CFGInvalidFile=-1, + CFGCommunicationError=-2, + CFGConnectingDFUModeFailed=-3, + CFGIncompatibleFW=-4, + CFGUnsupportedTargetDevice=-5, + CFGUnableToOpenFile=-6 + +} LoadConfigurationStatus; + +//TODO implement: #define CONFIGMODE_REQUIRE_SAME_FW 1 //will return IncompatibleFW if firmware checksum does not match the one in .drc files. if this error is returned, perform smFirmwareUpload and perform smLoadConfiguration again. Requires DRC file version 111 or later (if not met, returns InvalidFile). +#define CONFIGMODE_ALWAYS_RESTART_TARGET 2 //will perform device restart after setup even when it's not required +#define CONFIGMODE_DISABLE_DURING_CONFIG 4 //will set device in disabled state during configuration +#define CONFIGMODE_CLEAR_FAULTS_AFTER_CONFIG 8 //will perform clear faults command after configuration + +/** + * @brief smConfigureParameters Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param filename .DRC file name + * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). + * @return Enum LoadConfigurationStatus + * + * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. + */ +LIB LoadConfigurationStatus smLoadConfiguration( const smbus smhandle, const int smaddress, const char *filename, unsigned int mode, int *skippedCount, int *errorCount ); + + +/** + * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. + * @param UID result will be written to this pointer + * @return smtrue if success, smfalse if failed (if communication otherwise works, then probably UID feature not present in this firmware version) + */ +smbool smGetDeviceFirmwareUniqueID( smbus smhandle, int deviceaddress, smuint32 *UID ); + + + +#ifdef __cplusplus +} +#endif +#endif // SMDEPLOYMENTTOOL_H diff --git a/smdeploymenttool.c b/smdeploymenttool.c deleted file mode 100644 index 2551128..0000000 --- a/smdeploymenttool.c +++ /dev/null @@ -1,654 +0,0 @@ -#include "smdeploymenttool.h" -#include -#include -#include -#include -#include - -#ifdef __unix__ -#include -void sleep_ms(int millisecs) -{ - msleep(millisecs); -} -#else -#include -void sleep_ms(int millisecs) -{ - Sleep(millisecs); -} -#endif - -int globalErrorDetailCode=0; - -int smGetDeploymentToolErrroDetail() -{ - return globalErrorDetailCode; -} - -//return -1 if EOF -unsigned int readFileLine( FILE *f, int charlimit, char *output, smbool *eof) -{ - int len=0; - char c; - do - { - c=fgetc(f); - - if(feof(f)) - *eof=smtrue; - else - *eof=smfalse; - - //eol or eof - if( *eof==smtrue || c=='\n' || c=='\r' || len>=charlimit-1 ) - { - output[len]=0;//terminate str - return len; - } - - output[len]=c; - len++; - } while(1); - return len; -} - -typedef struct -{ - int address; - double value; - smbool readOnly; - double scale; - double offset; -} Parameter; - -smbool parseParameter(FILE *f, int idx, Parameter *param ) -{ - const int maxLineLen=100; - char line[maxLineLen]; - char scanline[maxLineLen]; - //search correct row - fseek(f,0,SEEK_SET); - smbool gotaddr=smfalse,gotvalue=smfalse, gotreadonly=smfalse, gotscale=smfalse,gotoffset=smfalse; - unsigned int readbytes; - smbool eof; - - do//loop trhu all lines of file - { - readbytes=readFileLine(f,maxLineLen,line,&eof);//read line - - //try read address - sprintf(scanline,"%d\\addr=",idx); - if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line - if(sscanf(line+strlen(scanline),"%d",¶m->address)==1)//parse number after the start of line - gotaddr=smtrue;//number parse success - - //try read value - sprintf(scanline,"%d\\value=",idx); - if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line - if(sscanf(line+strlen(scanline),"%lf",¶m->value)==1)//parse number after the start of line - gotvalue=smtrue;//number parse success - - //try read offset - sprintf(scanline,"%d\\offset=",idx); - if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line - if(sscanf(line+strlen(scanline),"%lf",¶m->offset)==1)//parse number after the start of line - gotoffset=smtrue;//number parse success - - //try read scale - sprintf(scanline,"%d\\scaling=",idx); - if(!strncmp(line,scanline,strlen(scanline)) && readbytes > strlen(scanline))//string starts with correct line - if(sscanf(line+strlen(scanline),"%lf",¶m->scale)==1)//parse number after the start of line - gotscale=smtrue;//number parse success - - //try read readonly status - sprintf(scanline,"%d\\readonly=true",idx);//check if readonly=true - if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match - { - param->readOnly=smtrue; - gotreadonly=smtrue; - } - sprintf(scanline,"%d\\readonly=false",idx);//check if readonly=false - if(!strncmp(line,scanline,strlen(scanline)) && readbytes >= strlen(scanline))//line match - { - param->readOnly=smfalse; - gotreadonly=smtrue; - } - } - while( (gotvalue==smfalse || gotaddr==smfalse || gotreadonly==smfalse || gotscale==smfalse || gotoffset==smfalse) && eof==smfalse ); - - if(gotvalue==smtrue&&gotaddr==smtrue&&gotoffset==smtrue&&gotscale==smtrue&&gotreadonly==smtrue) - { - return smtrue; - } - - return smfalse;//not found -} - -/** - * @brief smConfigureParameters Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. - * @param smhandle SM bus handle, must be opened before call - * @param smaddress Target SM device address - * @param filename .DRC file name - * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). - * @return Enum LoadConfigurationStatus - * - * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. - */ -LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smaddress, const char *filename, unsigned int mode , int *skippedCount, int *errorCount) -{ - //test connection - smint32 devicetype; - SM_STATUS stat; - FILE *f; - int ignoredCount=0; - int setErrors=0; - smint32 CB1Value; - int changed=0; - - *skippedCount=-1; - *errorCount=-1; - - //test connection - stat=smRead1Parameter(smhandle,smaddress,SMP_DEVICE_TYPE,&devicetype); - if(stat!=SM_OK) - return CFGCommunicationError; - - //smSetParameter( smhandle, smaddress, SMP_RETURN_PARAM_LEN, SMPRET_CMD_STATUS );//get command status as feedback from each executed SM command - - if(mode&CONFIGMODE_DISABLE_DURING_CONFIG) - { - smRead1Parameter( smhandle, smaddress, SMP_CONTROL_BITS1, &CB1Value ); - smSetParameter( smhandle, smaddress, SMP_CONTROL_BITS1, 0);//disable drive - } - - if(getCumulativeStatus( smhandle )!=SM_OK ) - return CFGCommunicationError; - - f=fopen(filename,"rb"); - if(f==NULL) - return CFGUnableToOpenFile; - - smDebug(smhandle,Low,"Setting parameters\n"); - - int i=1; - smbool readOk; - do - { - Parameter param; - readOk=parseParameter(f,i,¶m); - - if(readOk==smtrue && param.readOnly==smfalse) - { - smint32 currentValue; - - int configFileValue=round(param.value*param.scale-param.offset); - - //set parameter to device - if(smRead1Parameter( smhandle, smaddress, param.address, ¤tValue )==SM_OK) - { - if(currentValue!=configFileValue ) //set only if different - { - resetCumulativeStatus( smhandle ); - smint32 dummy; - smint32 cmdSetAddressStatus; - smint32 cmdSetValueStatus; - - //use low level SM commands so we can get execution status of each subpacet: - smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, SMP_RETURN_PARAM_LEN ); - smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_24B, SMPRET_CMD_STATUS ); - smAppendSMCommandToQueue( smhandle, SM_SET_WRITE_ADDRESS, param.address ); - smAppendSMCommandToQueue( smhandle, SM_WRITE_VALUE_32B, configFileValue ); - smExecuteCommandQueue( smhandle, smaddress ); - smGetQueuedSMCommandReturnValue( smhandle, &dummy ); - smGetQueuedSMCommandReturnValue( smhandle, &dummy ); - smGetQueuedSMCommandReturnValue( smhandle, &cmdSetAddressStatus ); - smGetQueuedSMCommandReturnValue( smhandle, &cmdSetValueStatus ); - - //check if above code succeed - if( getCumulativeStatus(smhandle)!=SM_OK || cmdSetAddressStatus!=SMP_CMD_STATUS_ACK || cmdSetValueStatus!=SMP_CMD_STATUS_ACK ) - { - SM_STATUS stat=getCumulativeStatus(smhandle); - setErrors++; - smDebug(smhandle,Low,"Failed to write parameter value %d to address %d (status: %d %d %d)\n",configFileValue,param.address,(int)stat,cmdSetAddressStatus,cmdSetValueStatus); - } - - changed++; - } - } - else//device doesn't have such parameter. perhaps wrong model or fw version. - { - ignoredCount++; - smDebug(smhandle,Low,"Ignoring parameter parameter value %d to address %d\n",configFileValue,param.address); - } - } - - i++; - } while(readOk==smtrue); - - *skippedCount=ignoredCount; - *errorCount=setErrors; - - resetCumulativeStatus( smhandle ); - - //save to flash if some value was changed - if(changed>0) - smSetParameter( smhandle, smaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_SAVECFG ); - - if(mode&CONFIGMODE_CLEAR_FAULTS_AFTER_CONFIG ) - { - smDebug(smhandle,Low,"Restting faults\n"); - smSetParameter( smhandle, smaddress, SMP_FAULTS, 0 );//reset faults - } - - //re-enable drive - if(mode&CONFIGMODE_DISABLE_DURING_CONFIG) - { - smDebug(smhandle,Low,"Restoring CONTROL_BITS1 to value 0x%x\n",CB1Value); - smSetParameter( smhandle, smaddress, SMP_CONTROL_BITS1, CB1Value );//restore controbits1 (enable if it was enabled before) - } - - smint32 statusbits; - smRead1Parameter( smhandle, smaddress, SMP_STATUS, &statusbits ); - - //restart drive if necessary or if forced - if( (statusbits&STAT_PERMANENT_STOP) || (mode&CONFIGMODE_ALWAYS_RESTART_TARGET) ) - { - smDebug(smhandle,Low,"Restarting device\n"); - smSetParameter( smhandle, smaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_RESTART ); - sleep_ms(2000);//wait power-on - } - - if(getCumulativeStatus(smhandle)!=SM_OK) - return CFGCommunicationError; - - return CFGComplete; -} - -/** - * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed - * @param smhandle SM bus handle, must be opened before call - * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. - * @param UID result will be written to this pointer - * @return smtrue if success, smfalse if failed (if communication otherwise works, then probably UID feature not present in this firmware version) - */ -smbool smGetDeviceFirmwareUniqueID( smbus smhandle, int deviceaddress, smuint32 *UID )//FIXME gives questionable value if device is in DFU mode. Check FW side. -{ - smint32 fwBinaryChecksum; - resetCumulativeStatus(smhandle); - smSetParameter( smhandle, deviceaddress, SMP_SYSTEM_CONTROL, SMP_SYSTEM_CONTROL_GET_SPECIAL_DATA); - smRead1Parameter( smhandle, deviceaddress, SMP_DEBUGPARAM1, &fwBinaryChecksum ); - *UID=(smuint32) fwBinaryChecksum; - - if(getCumulativeStatus(smhandle)==SM_OK) - return smtrue; - else - return smfalse; -} - -FirmwareUploadStatus verifyFirmwareData(smuint8 *data, smuint32 numbytes, int connectedDeviceTypeId, - smuint32 *primaryMCUDataOffset, smuint32 *primaryMCUDataLenth, - smuint32 *secondaryMCUDataOffset,smuint32 *secondaryMCUDataLength ) -{ - //see http://granitedevices.com/wiki/Argon_firmware_file_format - - smuint32 filetype; - filetype=((smuint32*)data)[0]; - if(filetype!=0x57464447) //check header string "GDFW" - return FWInvalidFile; - - smuint16 filever, deviceid; - smuint32 primaryMCUSize, secondaryMCUSize; - - filever=((smuint16*)data)[2]; - deviceid=((smuint16*)data)[3]; - primaryMCUSize=((smuint32*)data)[2]; - secondaryMCUSize=((smuint32*)data)[3]; - if(secondaryMCUSize==0xffffffff) - secondaryMCUSize=0;//it is not present - - if(filever!=300) - return FWIncompatibleFW; - - if(deviceid/1000!=connectedDeviceTypeId/1000)//compare only device and model family. AABBCC so AAB is compared value, ARGON=004 IONI=011 - return FWIncompatibleFW; - - //get checksum and check it - smuint32 cksum,cksumcalc=0; - smuint32 i; - smuint32 cksumOffset=4+2+2+4+4+primaryMCUSize+secondaryMCUSize; - if(cksumOffset>numbytes-4) - return FWInvalidFile; - cksum=((smuint32*)((smuint32)data+cksumOffset))[0]; - - for(i=0;i< numbytes-4;i++) - { - cksumcalc+=data[i]; - } - - if(cksum!=cksumcalc) - return FWIncompatibleFW; - - //let caller know where the firmware data is located in buffer - *primaryMCUDataOffset=4+2+2+4+4; - *primaryMCUDataLenth=primaryMCUSize; - *secondaryMCUDataOffset=*primaryMCUDataOffset+*primaryMCUDataLenth; - *secondaryMCUDataLength=secondaryMCUSize; - - return FWComplete; -} - -smbool loadBinaryFile( const char *filename, smuint8 **data, int *numbytes ) -{ - FILE *f; - f=fopen(filename,"rb"); - if(f==NULL) - return smfalse; - - *numbytes=0; - - //get length - fseek(f,0,SEEK_END); - int length=ftell(f); - fseek(f,0,SEEK_SET); - - //allocate buffer - *data=malloc(length); - if(*data==NULL) - return smfalse; - - //read - *numbytes=fread(*data,1,length,f); - if(*numbytes!=length)//failed to read it all - { - free(*data); - *numbytes=0; - return smfalse; - } - - return smtrue;//successl -} - - - -//flashing STM32 (host side mcu) -smbool flashFirmwarePrimaryMCU( smbus smhandle, int deviceaddress, const smuint8 *data, smint32 size, int *progress ) -{ - smint32 ret; - static smint32 deviceType, fwVersion; - static int uploadIndex; - int c; - const int BL_CHUNK_LEN=32; - static enum {Init,Upload,Finish} state=Init; - - if(state==Init) - { - resetCumulativeStatus( smhandle ); - smRead2Parameters( smhandle, deviceaddress, SMP_FIRMWARE_VERSION, &fwVersion, SMP_DEVICE_TYPE,&deviceType ); - - if(getCumulativeStatus(smhandle)!=SM_OK) - { - state=Init; - return smfalse; - } - -/* kommentoitu pois koska ei haluta erasoida parskuja koska parametri SMO ei saisi nollautua mielellään - - if(deviceType!=4000)//argon does not support BL function 11 - smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,11);//BL func on ioni 11 = do mass erase on STM32, also confifuration - else//does not reset on ioni and drives that support preserving settings. but resets on argon -*/ - smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,1);//BL func 1 = do mass erase on STM32. On Non-Argon devices it doesn't reset confifuration - - sleep_ms(2000);//wait some time. 500ms too little 800ms barely enough - - //flash - smSetParameter(smhandle,deviceaddress,SMP_RETURN_PARAM_LEN, SMPRET_CMD_STATUS); - - if(getCumulativeStatus(smhandle)!=SM_OK) - { - state=Init; - return smfalse; - } - - state=Upload; - uploadIndex=0; - *progress=5; - } - else if(state==Upload) - { - size/=2;//bytes to 16 bit words - - //upload data in 32=BL_CHUNK_LEN word chunks - for(;uploadIndex=size) - upword=0xeeee; - else - upword=((smuint16*)data)[uploadIndex]; - smAppendSMCommandToQueue( smhandle, SMPCMD_24B, upword ); - uploadIndex++; - } - - smAppendSMCommandToQueue( smhandle, SMPCMD_SETPARAMADDR, SMP_BOOTLOADER_FUNCTION ); - smAppendSMCommandToQueue( smhandle, SMPCMD_24B, 2);//BL func 2 = do write on STM32 - smExecuteCommandQueue( smhandle, deviceaddress ); - - //read return packets - for(c=0;c=94)//95 will indicate that progress is complete. dont let it indicate that yet. - *progress=94; - - if(uploadIndex%256==0) - { - //printf("upload %d\n",uploadIndex); - return smtrue;//in progress. return often to make upload non-blocking - } - } - if(uploadIndex>=size)//finished - { - state=Finish; - } - } - else if(state==Finish) - { - //verify STM32 flash if supported by BL version - if(fwVersion>=1210) - { - smSetParameter(smhandle,deviceaddress,SMP_BOOTLOADER_FUNCTION,3);//BL func 3 = verify STM32 FW integrity - smint32 faults; - smRead1Parameter(smhandle,deviceaddress,SMP_FAULTS,&faults); - - if(getCumulativeStatus(smhandle)!=SM_OK) - { - state=Init; - *progress=0; - return smfalse; - } - - if(faults&FLT_FLASHING_COMMSIDE_FAIL) - { - //printf("verify failed\n"); - *progress=0; - state=Init; - return smfalse; - } - else - { - //printf("verify success\n"); - } - } - - *progress=95;//my job is complete - state=Init; - } - - return smtrue; -} - - -typedef enum { StatIdle=0, StatEnterDFU, StatFindDFUDevice, StatLoadFile, StatUpload, StatLaunch } UploadState;//state machine status - -//free buffer and return given status code -FirmwareUploadStatus abortFWUpload( FirmwareUploadStatus stat, smuint8 *fwData, UploadState *state, int errorDetailCode ) -{ - globalErrorDetailCode=errorDetailCode; - *state=StatIdle; - free(fwData); - return stat; -} - -/** - * @brief smFirmwareUpload Sets drive in firmware upgrade mode if necessary and uploads a new firmware. Call this many until it returns value 100 (complete) or a negative value (error). - * @param smhandle SM bus handle, must be opened before call - * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. - * @param filename .gdf file name - * @return Enum FirmwareUploadStatus that indicates errors or Complete status. Typecast to integer to get progress value 0-100. - */ -FirmwareUploadStatus smFirmwareUpload( const smbus smhandle, const int smaddress, const char *firmware_filename ) -{ - static smuint8 *fwData=NULL; - static int fwDataLength; - static smuint32 primaryMCUDataOffset, primaryMCUDataLenth; - static smuint32 secondaryMCUDataOffset,secondaryMCUDataLength; - static UploadState state=StatIdle;//state machine status - static smint32 deviceType=0; - static int DFUAddress; - static int progress=0; - - SM_STATUS stat; - - //state machine - if(state==StatIdle) - { - - //check if device is in DFU mode already - smint32 busMode; - stat=smRead2Parameters(smhandle,smaddress,SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); - if(stat==SM_OK && busMode==SMP_BUS_MODE_DFU) - { - state=StatLoadFile; - } - else if(stat==SM_OK && busMode!=0)//device not in bus mode - { - if(deviceType==4000)//argon does not support restarting in DFU mode by software - { - return abortFWUpload(FWConnectionError,fwData,&state,200); - } - - //restart device into DFU mode - state=StatEnterDFU; - - stat=smSetParameter(smhandle,smaddress,SMP_SYSTEM_CONTROL,64);//reset device to DFU command - if(stat!=SM_OK) - return abortFWUpload(FWConnectionError,fwData,&state,300); - } - else - state=StatFindDFUDevice;//search DFU device in brute force, fallback for older BL versions that don't preserve same smaddress than non-DFU mode - //return abortFWUpload(FWConnectionError,fwData,&state,301); - - progress=1; - DFUAddress=smaddress; - } - - else if(state==StatEnterDFU) - { - sleep_ms(2500);//wait device to reboot in DFU mode. probably shorter delay would do. - - //check if device is in DFU mode already - smint32 busMode; - stat=smRead2Parameters(smhandle,smaddress, SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); - if(stat==SM_OK && busMode==0)//busmode 0 is DFU mode - { - state=StatLoadFile; - } - else - state=StatFindDFUDevice;//search DFU device in brute force, fallback for older BL versions that don't preserve same smaddress than non-DFU mode - - progress=2; - } - - else if(state==StatFindDFUDevice) - { - int i; - for(i=245;i<=255;i++) - { - smint32 busMode; - stat=smRead2Parameters(smhandle,i, SMP_BUS_MODE,&busMode, SMP_DEVICE_TYPE, &deviceType); - if(stat==SM_OK && busMode==0)//busmode 0 is DFU mode - { - state=StatLoadFile; - DFUAddress=i; - break;//DFU found, break out of for loop - } - } - - if(i==256)//DFU device not found - return abortFWUpload(CFGConnectingDFUModeFailed,fwData,&state,400);//setting DFU mode failed - - progress=3; - } - - else if(state==StatLoadFile) - { - if(loadBinaryFile(firmware_filename,&fwData,&fwDataLength)!=smtrue) - return FWFileNotReadable; - - FirmwareUploadStatus stat=verifyFirmwareData(fwData, fwDataLength, deviceType, - &primaryMCUDataOffset, &primaryMCUDataLenth, - &secondaryMCUDataOffset, &secondaryMCUDataLength); - if(stat!=FWComplete)//error in verify - { - return abortFWUpload(stat,fwData,&state,100); - } - - //all good, upload firmware - state=StatUpload; - - progress=4; - } - - else if(state==StatUpload) - { - smbool ret=flashFirmwarePrimaryMCU(smhandle,DFUAddress,fwData+primaryMCUDataOffset,primaryMCUDataLenth,&progress); - if(ret==smfalse)//failed - { - return abortFWUpload(FWConnectionError,fwData,&state,1000); - } - else - { - if(progress>=95) - state=StatLaunch; - } - } - - else if(state==StatLaunch) - { - smSetParameter(smhandle,DFUAddress,SMP_BOOTLOADER_FUNCTION,4);//BL func 4 = launch. - sleep_ms(2000); - progress=100; - state=StatIdle; - } - - return (FirmwareUploadStatus)progress; -} - - - - diff --git a/smdeploymenttool.h b/smdeploymenttool.h deleted file mode 100644 index 8838664..0000000 --- a/smdeploymenttool.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef SMDEPLOYMENTTOOL_H -#define SMDEPLOYMENTTOOL_H - -#ifdef WIN32 -//dll specs -#ifdef BUILD_DLL - #define LIB __declspec(dllexport) -#else -// #define LIB __declspec(dllimport) -#define LIB -#endif -#else -#define LIB -#endif - - -#include "simplemotion.h" - - -#ifdef __cplusplus -extern "C"{ -#endif - - -typedef enum -{ - FWComplete=100, - FWInvalidFile=-1, - FWConnectionError=-2, - FWIncompatibleFW=-3, - FWConnectionLoss=-4, - FWUnsupportedTargetDevice=-5, - FWFileNotReadable=-6 -} FirmwareUploadStatus; - -/** - * @brief smFirmwareUpload Sets drive in firmware upgrade mode if necessary and uploads a new firmware. Call this many until it returns value 100 (complete) or a negative value (error). - * @param smhandle SM bus handle, must be opened before call - * @param smaddress Target SM device address - * @param filename .gdf file name - * @return Enum FirmwareUploadStatus that indicates errors or Complete status. Typecast to integer to get progress value 0-100. - */ -LIB FirmwareUploadStatus smFirmwareUpload(const smbus smhandle, const int smaddress, const char *firmware_filename ); - -typedef enum -{ - CFGComplete=100, - CFGInvalidFile=-1, - CFGCommunicationError=-2, - CFGConnectingDFUModeFailed=-3, - CFGIncompatibleFW=-4, - CFGUnsupportedTargetDevice=-5, - CFGUnableToOpenFile=-6 - -} LoadConfigurationStatus; - -//TODO implement: #define CONFIGMODE_REQUIRE_SAME_FW 1 //will return IncompatibleFW if firmware checksum does not match the one in .drc files. if this error is returned, perform smFirmwareUpload and perform smLoadConfiguration again. Requires DRC file version 111 or later (if not met, returns InvalidFile). -#define CONFIGMODE_ALWAYS_RESTART_TARGET 2 //will perform device restart after setup even when it's not required -#define CONFIGMODE_DISABLE_DURING_CONFIG 4 //will set device in disabled state during configuration -#define CONFIGMODE_CLEAR_FAULTS_AFTER_CONFIG 8 //will perform clear faults command after configuration - -/** - * @brief smConfigureParameters Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. - * @param smhandle SM bus handle, must be opened before call - * @param smaddress Target SM device address - * @param filename .DRC file name - * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). - * @return Enum LoadConfigurationStatus - * - * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. - */ -LIB LoadConfigurationStatus smLoadConfiguration( const smbus smhandle, const int smaddress, const char *filename, unsigned int mode, int *skippedCount, int *errorCount ); - - -/** - * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed - * @param smhandle SM bus handle, must be opened before call - * @param smaddress Target SM device address. Can be device in DFU mode or main operating mode. For Argon, one device in a bus must be started into DFU mode by DIP switches and smaddress must be set to 255. - * @param UID result will be written to this pointer - * @return smtrue if success, smfalse if failed (if communication otherwise works, then probably UID feature not present in this firmware version) - */ -smbool smGetDeviceFirmwareUniqueID( smbus smhandle, int deviceaddress, smuint32 *UID ); - - - -#ifdef __cplusplus -} -#endif -#endif // SMDEPLOYMENTTOOL_H -- cgit v1.2.3 From 52bf3a6b791a381cf08a3ac167fac7375459aab9 Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Thu, 6 Apr 2017 17:19:06 +0300 Subject: Add missing fclose calls --- devicedeployment.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/devicedeployment.c b/devicedeployment.c index bdb718d..54f07e0 100644 --- a/devicedeployment.c +++ b/devicedeployment.c @@ -226,6 +226,8 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad i++; } while(readOk==smtrue); + fclose(f); + *skippedCount=ignoredCount; *errorCount=setErrors; @@ -355,7 +357,10 @@ smbool loadBinaryFile( const char *filename, smuint8 **data, int *numbytes ) //allocate buffer *data=malloc(length); if(*data==NULL) + { + fclose(f); return smfalse; + } //read *numbytes=fread(*data,1,length,f); @@ -363,9 +368,11 @@ smbool loadBinaryFile( const char *filename, smuint8 **data, int *numbytes ) { free(*data); *numbytes=0; + fclose(f); return smfalse; } + fclose(f); return smtrue;//successl } -- cgit v1.2.3 From 7dc56301dd8388cdf60e0c3270ec99b403c6063f Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Fri, 7 Apr 2017 15:33:40 +0300 Subject: Switch using stdint.h types --- simplemotion.c | 2 +- simplemotion.h | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/simplemotion.c b/simplemotion.c index 9a0b3fb..d78e511 100644 --- a/simplemotion.c +++ b/simplemotion.c @@ -158,7 +158,7 @@ SM_STATUS smSetTimeout( smuint16 millsecs ) return SM_ERR_PARAMETER; } -unsigned long smGetVersion() +smuint32 smGetVersion() { return SM_VERSION; } diff --git a/simplemotion.h b/simplemotion.h index 725d3dc..dcf499d 100644 --- a/simplemotion.h +++ b/simplemotion.h @@ -17,6 +17,7 @@ #endif #include +#include #include "simplemotion_defs.h" @@ -38,13 +39,13 @@ extern "C"{ /////////////////////////////////////////////////////////////////////////////////////// //declare SM lib types typedef long smbus; -typedef unsigned long smuint32; -typedef unsigned short smuint16; -typedef unsigned char smuint8; -typedef long smint32; -typedef short smint16; -typedef char smint8; -typedef char smbool; +typedef uint32_t smuint32; +typedef uint16_t smuint16; +typedef uint8_t smuint8; +typedef int32_t smint32; +typedef int16_t smint16; +typedef int8_t smint8; +typedef int8_t smbool; #define smtrue 1 #define smfalse 0 typedef int SM_STATUS; -- cgit v1.2.3 From 6ed02275c76150f78ce1d4f2571b99d903855cbd Mon Sep 17 00:00:00 2001 From: Oskari Timperi Date: Wed, 12 Apr 2017 12:32:18 +0300 Subject: Fix devicedeployment.c on 64-bit OS X --- devicedeployment.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/devicedeployment.c b/devicedeployment.c index 54f07e0..222992a 100644 --- a/devicedeployment.c +++ b/devicedeployment.c @@ -5,11 +5,11 @@ #include #include -#ifdef __unix__ +#if defined(__unix__) || defined(__APPLE__) #include void sleep_ms(int millisecs) { - msleep(millisecs); + usleep(millisecs*1000); } #else #include @@ -321,7 +321,7 @@ FirmwareUploadStatus verifyFirmwareData(smuint8 *data, smuint32 numbytes, int co smuint32 cksumOffset=4+2+2+4+4+primaryMCUSize+secondaryMCUSize; if(cksumOffset>numbytes-4) return FWInvalidFile; - cksum=((smuint32*)((smuint32)data+cksumOffset))[0]; + cksum=((smuint32*)(data+cksumOffset))[0]; for(i=0;i< numbytes-4;i++) { -- cgit v1.2.3 From 706a71c01664ad990c60f6187eb1886693a93153 Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Mon, 17 Apr 2017 22:44:31 +0300 Subject: Fix FW uploader crashing on 64 bit OS X --- devicedeployment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicedeployment.c b/devicedeployment.c index 54f07e0..a5078b3 100644 --- a/devicedeployment.c +++ b/devicedeployment.c @@ -321,7 +321,7 @@ FirmwareUploadStatus verifyFirmwareData(smuint8 *data, smuint32 numbytes, int co smuint32 cksumOffset=4+2+2+4+4+primaryMCUSize+secondaryMCUSize; if(cksumOffset>numbytes-4) return FWInvalidFile; - cksum=((smuint32*)((smuint32)data+cksumOffset))[0]; + cksum=((smuint32*)(data+cksumOffset))[0]; for(i=0;i< numbytes-4;i++) { -- cgit v1.2.3 From c2a59b64b486ced4dd91d4dba1005205322d6bc6 Mon Sep 17 00:00:00 2001 From: Tero Kontkanen Date: Mon, 29 May 2017 22:14:53 +0300 Subject: -Added smLoadConfigurationFromBuffer to be operated from RAM buffer instead of file -Fix bug of smLoadConfiguration returning CFGCommunicationError repeatedly after the first connection error --- devicedeployment.c | 60 ++++++++++++++++++++++++++++++++++++++---------------- devicedeployment.h | 13 ++++++++++++ 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/devicedeployment.c b/devicedeployment.c index 222992a..18e9748 100644 --- a/devicedeployment.c +++ b/devicedeployment.c @@ -21,24 +21,32 @@ void sleep_ms(int millisecs) int globalErrorDetailCode=0; +smbool loadBinaryFile( const char *filename, smuint8 **data, int *numbytes ); + int smGetDeploymentToolErrroDetail() { return globalErrorDetailCode; } //return -1 if EOF -unsigned int readFileLine( FILE *f, int charlimit, char *output, smbool *eof) +//readPosition should be initialized to 0 and not touched by caller after that. this func will increment it after each call. +unsigned int readFileLine( const smuint8 *data, const int dataLen, int *readPosition, int charlimit, char *output, smbool *eof) { int len=0; char c; do { - c=fgetc(f); - - if(feof(f)) + if(*readPosition>=dataLen)//end of data buffer + { *eof=smtrue; + c=0; + } else + { *eof=smfalse; + c=data[*readPosition+len]; + (*readPosition)++; + } //eol or eof if( *eof==smtrue || c=='\n' || c=='\r' || len>=charlimit-1 ) @@ -62,20 +70,19 @@ typedef struct double offset; } Parameter; -smbool parseParameter(FILE *f, int idx, Parameter *param ) +smbool parseParameter( const smuint8 *drcData, const int drcDataLen, int idx, Parameter *param ) { const int maxLineLen=100; char line[maxLineLen]; char scanline[maxLineLen]; - //search correct row - fseek(f,0,SEEK_SET); smbool gotaddr=smfalse,gotvalue=smfalse, gotreadonly=smfalse, gotscale=smfalse,gotoffset=smfalse; unsigned int readbytes; + int readPosition=0; smbool eof; do//loop trhu all lines of file { - readbytes=readFileLine(f,maxLineLen,line,&eof);//read line + readbytes=readFileLine(drcData,drcDataLen,&readPosition,maxLineLen,line,&eof);//read line //try read address sprintf(scanline,"%d\\addr=",idx); @@ -136,20 +143,45 @@ smbool parseParameter(FILE *f, int idx, Parameter *param ) * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. */ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smaddress, const char *filename, unsigned int mode , int *skippedCount, int *errorCount) +{ + LoadConfigurationStatus ret; + smuint8 *drcData=NULL; + int drcDataLength; + + if(loadBinaryFile(filename,&drcData,&drcDataLength)!=smtrue) + return CFGUnableToOpenFile; + + ret = smLoadConfigurationFromBuffer( smhandle, smaddress, drcData, drcDataLength, mode, skippedCount, errorCount ); + free(drcData); + + return ret; +} + +/** + * @brief smConfigureParametersFromBuffer Same as smConfigureParameters but reads data from user specified memory address instead of file. Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param drcData Pointer to to a memory where .drc file is loaded + * @param drcDataLen Number of bytes available in the drcData buffer + * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). + * @return Enum LoadConfigurationStatus + * + * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. + */ +LIB LoadConfigurationStatus smLoadConfigurationFromBuffer( const smbus smhandle, const int smaddress, const smuint8 *drcData, const int drcDataLength, unsigned int mode, int *skippedCount, int *errorCount ) { //test connection smint32 devicetype; SM_STATUS stat; - FILE *f; int ignoredCount=0; int setErrors=0; smint32 CB1Value; int changed=0; - *skippedCount=-1; *errorCount=-1; //test connection + resetCumulativeStatus(smhandle); stat=smRead1Parameter(smhandle,smaddress,SMP_DEVICE_TYPE,&devicetype); if(stat!=SM_OK) return CFGCommunicationError; @@ -165,10 +197,6 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad if(getCumulativeStatus( smhandle )!=SM_OK ) return CFGCommunicationError; - f=fopen(filename,"rb"); - if(f==NULL) - return CFGUnableToOpenFile; - smDebug(smhandle,Low,"Setting parameters\n"); int i=1; @@ -176,7 +204,7 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad do { Parameter param; - readOk=parseParameter(f,i,¶m); + readOk=parseParameter(drcData,drcDataLength,i,¶m); if(readOk==smtrue && param.readOnly==smfalse) { @@ -226,8 +254,6 @@ LoadConfigurationStatus smLoadConfiguration(const smbus smhandle, const int smad i++; } while(readOk==smtrue); - fclose(f); - *skippedCount=ignoredCount; *errorCount=setErrors; diff --git a/devicedeployment.h b/devicedeployment.h index f6fa08e..f86c7dc 100644 --- a/devicedeployment.h +++ b/devicedeployment.h @@ -82,6 +82,19 @@ typedef enum */ LIB LoadConfigurationStatus smLoadConfiguration( const smbus smhandle, const int smaddress, const char *filename, unsigned int mode, int *skippedCount, int *errorCount ); +/** + * @brief smConfigureParametersFromBuffer Same as smConfigureParameters but reads data from user specified memory address instead of file. Configures all target device parameters from file and performs device restart if necessary. This can take few seconds to complete. This may take 2-5 seconds to call. + * @param smhandle SM bus handle, must be opened before call + * @param smaddress Target SM device address + * @param drcData Pointer to to a memory where .drc file is loaded + * @param drcDataLen Number of bytes available in the drcData buffer + * @param mode Combined from CONFIGMODE_ define bits (can logic OR mutliple values). + * @return Enum LoadConfigurationStatus + * + * Requires DRC file version 111 or later to use CONFIGMODE_REQUIRE_SAME_FW. + */ +LIB LoadConfigurationStatus smLoadConfigurationFromBuffer(const smbus smhandle, const int smaddress, const smuint8 *drcData, const int drcDataLength, unsigned int mode, int *skippedCount, int *errorCount ); + /** * @brief smGetDeviceFirmwareUniqueID Reads installed firmware binary checksum that can be used to verify whether a wanted FW version is installed -- cgit v1.2.3