Você está na página 1de 13

SMW Communication Kit SDK - Wiki - # 63

SMW Communication kit SDK Wiki


SDK
O SMW Communication Kit SDK um framework de comunicao multiplataforma para medidores da famlia SMW. O
desenvolvimento realizado em linguagem C, padro GNU99.

Objetivos
O objetivo do SMW Communication Kit SDK o de fornecer as ferramentas necessrias para auxiliar os desenvolvedores durante
o processo de integrao de novos acessrios de comunicao aos medidores da famlia SMW. As metas especficas deste projeto
incluem, mas no se limitam a:
Utilizar as funes de leitura e escrita de parmetros do projeto Modbus nas transaes com o medidor;
Utilizar os algoritmos de segurana (AES-256, CBC, ECDSA e SDH) do projeto Security para autenticao e criptografia;
Implementar o mecanismo de "aperto-de-mos" para o estabelecimento de sesso segura com o medidor;
Implementar a lista de atributos suportados por medidores da famlia SMW;
Realizar a escolha da funo Modbus correta de acordo com o atributo solicitado;
Verificar as respostas e retornar interface target o contedo das mensagens;
Encapsular as funcionalidades do SDK em uma nica static library.

Viso Arquitetural
O SDK uma biblioteca esttica independente de hardware que pode ser compilada para qualquer sistema que atenda a critrios
mnimos de RAM, ROM e capacidade de processamento. Ela encapsula as funcionalidades da biblioteca Modbus e de Security e
implementa as "queries" ou perguntas que podem ser realizadas para os medidores da famlia SMW. Existem quatro interfaces para
o sistema target:
Requerida
Memory.c - Realiza manipulaes em memria RAM. As principais funes so New(), Delete(), Set() e Compare().
Muitos sistemas podem utilizar o port existente, que utiliza as funes da biblioteca standard do ANSI C.
SerialPort.c - Para as funes de inicializao, leitura e escrita na porta serial. Tambm pode ser utilizada como wrapper
para outros meios (ex.: UDP/IP).
KeyLoader.c - Retorna as chaves de segurana utilizadas pelo SDK. O sistema target deve fornecer as chaves utilizadas
pelo SDK.
Fornecida
QueryManager.h - a principal interface fornecida pelo SDK que permite a abertura de sesso e comunicao com o
medidor.

01.12.2016

1/13

Abaixo um simples programa que utiliza o SDK para ler a tenso RMS do medidor e encerra logo aps:
staticvoidmyListener(uint8_tstate){
uint8_trcvBuffer[255]={0};
size_trcvLength=0;
/*CopythealreadyvalidatedresponsefromSDKbuffer.*/
Receive(rcvBuffer,sizeofrcvBuffer,&rcvLength);
/*Dumpthereceivedmessage.*/
printf("\r\nResponse(%zu):\r\n",rcvLength);
for(size_ti=0;i<rcvLength;i++)
printf("%02x",rcvBuffer[i]);
printf("\r\n");
}
intmain(intargc,char**argv){
/**
*Startasecuresessionwiththemeterandregistertheapplication
*listenertoreceiveresponsenotifications.
*/
Initialize("/dev/ttyUSB1",myListener);
/**
*RequesttheRMSvoltagetothemeter.myListener()willbeinvoked
*oncethereplyortimeoutarrives.
*/
Send(kInstantaneousRMSVoltage,NULL,0);
/*Closethesecuresession.*/
DeInitialize();
}

01.12.2016

2/13

Padres de Desenvolvimento de Software


O padro de projeto Observer utilizado para notificar quando uma resposta Modbus est disponvel para leitura. A aplicao deve
registrar um observador na chamada para inicializao do SDK:
Initialize("/dev/ttyUSB1",myListener);

O observador chamado sempre que uma resposta Modbus tiver sido recebida e estiver disponvel para o uso na aplicao. Esta
funcionalidade til especialmente no modo em que a resposta Modbus ocorre em uma thread independente a da requisio,
conhecido como modo non-blocking. No modo blocking a porta serial fica bloqueada at receber a resposta ou ocorrer timeout, no
sendo necessria a notificao.

Padres de Projeto de Framework


O SDK desenvolvido na forma de biblioteca esttica. Todas as rotinas, funes e variveis do sistema so resolvidas durante a
compilao e copiadas pelo compilador e linker para a aplicao final executvel.
Alm disso, tambm implementada a validao de dados das requisies e respostas: no envio do comando selecionada a
melhor funo Modbus de acordo com o cdigo do atributo, e, na resposta ocorre a verificao por CRC-16.
Todas as funes realizam verificaes internas de consistncia e tem retorno 0 para sucesso ou > 0 para indicar um erro.

Criando o port
A realizao do port do SDK para uma nova plataforma consiste na implementao das interfaces requeridas mencionadas na Viso
Arquitetural:
Memory.c
Encapsula as funes de gerenciamento de memria utilizadas no sistema target. Uma implementao tpica do Memory.c
utilizando a biblioteca padro C pode ser desta forma:
#include"Memory.h"
void*New(constvoid*type,...){
/*Obtainthesizeoftheobject.*/
constsize_tsize=*(constsize_t*)type;
/*Allocatesmemoryfortheobject.*/
void*instance=malloc(size);
/*Objectinstance.*/
returninstance;
}
voidDelete(void**instance){
/*Releaseinstance,ifexists.*/
if(*instance){
free(*instance);
*instance=NULL;
}
}
void*Copy(void*to,constvoid*from,size_tsize){
memcpy(to,from,size);

01.12.2016

3/13

returnto;
}
void*Set(void*block,int8_tvalue,size_tsize){
memset(block,value,size);
return0;
}
int32_tCompare(constvoid*str1,constvoid*str2,size_tn){
returnmemcmp(str1,str2,n);
}

SerialPort.c
Implementa as funes de leitura e escrita na porta serial. Abaixo um exemplo para a plataforma Windows em modo blocking:
#include"SerialPortWindows.h"
/*Windowsserialporthandler.*/
void*_fd=INVALID_HANDLE_VALUE;
staticSerialListener_notify;/*<Callbacktonotifyaboutincomingreplies.*/
int8_tSerialPortInit(constcharportName[],SerialListenerlistener){
/*Opentheserialport.*/
DWORDaccessDirection=GENERIC_READ|GENERIC_WRITE;
_fd=CreateFile(portName,accessDirection,0,0,OPEN_EXISTING,0,0);
if(_fd==INVALID_HANDLE_VALUE)
return-1;
/*Obtainportstate.*/
DCBdcbSerialParams={0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if(!GetCommState(_fd,&dcbSerialParams))
return-1;
/*Definegeneralcommunicationparameters.*/
dcbSerialParams.BaudRate=115200;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=2;
dcbSerialParams.Parity=0;
if(!SetCommState(_fd,&dcbSerialParams))
return-1;
/*Configuretime-outparameters.*/
COMMTIMEOUTStimeouts={0};
timeouts.ReadIntervalTimeout=-1;
timeouts.ReadTotalTimeoutConstant=0;
timeouts.ReadTotalTimeoutMultiplier=1000;
timeouts.WriteTotalTimeoutConstant=0;
timeouts.WriteTotalTimeoutMultiplier=0;
if(!SetCommTimeouts(_fd,&timeouts))
return-1;
/*Configuretheserialobserver.*/

01.12.2016

4/13

if(!listener)
return-1;
_notify=listener;
/*Returnsuccess.*/
return0;
}
int8_tSerialPortDeInit(void){
CloseHandle(_fd);
/*Returncode.*/
return(_fd==INVALID_HANDLE_VALUE)?
-1:0;
}
int8_tSerialPortRead(uint8_t*buffer,uint8_tlength,uint8_t*readLength){
DWORDnBytesRead=0;
uint8_ttemporaryBuffer=0;
uint8_ti=1;
/*Checkthebufferispreviouslyallocated.*/
if(buffer==NULL)
return-1;
/*Checkthenumberofbytesreadpointerispreviouslyallocated.*/
if(readLength==NULL)
return-1;
do{
if(!ReadFile(_fd,&temporaryBuffer,1,&nBytesRead,NULL))
break;
buffer[i-1]=temporaryBuffer;
i++;
}while(nBytesRead>0&&i<length);
/*Numberofbytesread.*/
*readLength=i-2;
/*Returnsuccess.*/
return0;
}
int8_tSerialPortWrite(uint8_t*buffer,uint8_tlength){
DWORDnBytesWritten=0;
/*Writequery.*/
if(!WriteFile(_fd,buffer,length,&nBytesWritten,NULL))
return-1;
_notify();
/*Returnsuccess.*/
return0;
}
int8_tSerialPortSetTimeOut(uint32_tportTimeOut){
/*Holdtime-outparameters.*/
COMMTIMEOUTStimeouts={0};

01.12.2016

5/13

/*Retrievecurrenttime-outparameters.*/
if(!GetCommTimeouts(_fd,&timeouts))
return-1;
/*Definethenewtime-outvalue.*/
timeouts.ReadTotalTimeoutMultiplier=portTimeOut;
/*Setthenewtime-out.*/
if(!SetCommTimeouts(_fd,&timeouts))
return-1;
/*Returnsuccess.*/
return0;
}
int8_tSerialPortIsBlocking(){
return1;
}

E no arquivo .h:
/**
*@fileSerialPortWindows.h
*@authorRichardH.Baeumle<richardhb@weg.net>
*@version1.0
*@briefImplementstheModbusserialporthandlerforWindowssystems.
*
*Thisfilecontainthedefinitionofthenecessaryfunctionstoinitialize,
*readandwritedataonaserialport.
*
*Copyright2015WEGAutomacaoLtda.AllRightsReserved.
*/
#ifndefSERIAL_PORT_WINDOWS_H
#defineSERIAL_PORT_WINDOWS_H
#ifdef__cplusplus
extern"C"{
#endif
/*StandardC.*/
#include<stdint.h>/*<Standardintegerdatatypes.*/
#include<stdio.h>/*<Printerroranddebugmessages.*/
#include<string.h>/*<Erroroutput.*/
/*Windows.*/
#include<windows.h>/*<DefinitionsusedbytheterminalI/Ointerfaces.*/
/*SDK.*/
#include"SerialPort.h"/*<Definitionofportinterfacestobeimplemented.*/
#ifdef__cplusplus
}
#endif
#endif/*SERIAL_PORT_WINDOWS_H*/

KeyLoader.c

01.12.2016

6/13

Permite que o SDK recupere as chaves e assinaturas necessrias durante a autenticao com o medidor. Uma implementao
bsica pode ser desta forma:
#include"KeyLoader.h"
externvoidGetPrivateKey(uint8_tbuffer[],size_tbufferLength,
size_t*keyLength){
/*System'sprivatekey.*/
constuint8_tprivateKey[]={
0x69,0xdf,0xce,0x0f,0x78,0xc6,0xbe,0xdb,
0x8f,0xbb,0x44,0xb9,0x86,0x1c,0xea,0x68,
0x55,0xbc,0xac,0xa9,0x32,0x54,0x9b,0x4d,
0x6a,0xe5,0x61,0xfc,0x64,0x2b,0x75,0x68
};
*keyLength=sizeofprivateKey;
/*CopytoSDKbuffer.*/
Copy(buffer,privateKey,(*keyLength<bufferLength)?
*keyLength:bufferLength);
}
externvoidGetPublicKey(uint8_tbuffer[],size_tbufferLength,
size_t*keyLength){
/*System'spublickey.*/
constuint8_tpublicKey[]={
0x04,0xd9,0x4f,0x0c,0x5b,0x91,0xae,0xeb,
0xf0,0xd1,0x22,0x86,0x2b,0xf0,0x49,0x32,
0x71,0xe1,0x5d,0x1e,0x13,0x53,0xf2,0x82,
0x70,0xcc,0xaa,0x7f,0x51,0xe2,0x39,0x01,
0x4a,0xc1,0xa3,0xf9,0xe0,0x5f,0x3b,0x4f,
0x1c,0x0b,0xd3,0xb8,0x09,0x6b,0xeb,0xd2,
0xc4,0xf0,0x87,0x57,0x27,0x36,0x51,0xc2,
0x01,0xcc,0x20,0x9c,0x26,0x2d,0x44,0x50,
0x66,0x00/*<lastbyteispaddingtofitwordsize.*/
};
*keyLength=sizeofpublicKey;
/*CopytoSDKbuffer.*/
Copy(buffer,publicKey,(*keyLength<bufferLength)?
*keyLength:bufferLength);
}
externvoidGetCaKey(uint8_tbuffer[],size_tbufferLength,
size_t*keyLength){
/*CA'spublickey.*/
constuint8_tcaKey[]={
0x04,0xc7,0x88,0x61,0x33,0x57,0x77,0x58,
0xac,0xcf,0x3b,0x8a,0xba,0x9d,0xc6,0x99,
0xf0,0x3f,0x68,0x8d,0x7e,0x34,0x03,0xef,
0x80,0x45,0x45,0x8e,0xe5,0xf0,0x78,0xc4,
0x37,0x47,0x8c,0xc4,0xef,0x48,0xdb,0x2f,
0xb2,0xa7,0x6d,0x83,0xf4,0x09,0x14,0x34,
0xf3,0xd5,0xfc,0xf5,0xb6,0x99,0x28,0xac,
0x31,0xc6,0x22,0x44,0xc3,0x62,0x24,0x87,
0x06
};
*keyLength=sizeofcaKey;
/*CopytoSDKbuffer.*/
Copy(buffer,caKey,(*keyLength<bufferLength)?
*keyLength:bufferLength);

01.12.2016

7/13

}
externvoidGetSignature(uint8_tbuffer[],size_tbufferLength,
size_t*signatureLength){
constuint8_tsignature[]={
0x30,0x46,0x02,0x21,0x00,0x16,0x09,0x7d,
0x01,0x50,0x53,0x68,0xb0,0x83,0xaa,0x47,
0xa0,0xec,0x29,0x4c,0x32,0x68,0x76,0x75,
0x98,0xa2,0x96,0x43,0xcd,0x1b,0x88,0x71,
0x46,0xe2,0x55,0xbd,0x89,0x02,0x21,0x00,
0x85,0x14,0x22,0xd5,0xc7,0x11,0x68,0xd0,
0x3a,0x19,0x74,0xdb,0x02,0xe1,0xee,0x31,
0x09,0xd3,0x29,0x6b,0xe0,0xd8,0x15,0x8f,
0x8e,0x71,0x22,0xa5,0xd7,0x87,0x7b,0x13
};
*signatureLength=sizeofsignature;
/*CopytoSDKbuffer.*/
Copy(buffer,signature,(*signatureLength<bufferLength)?
*signatureLength:bufferLength);
}

CLI
O smw-com-cli uma ferramenta de apoio disponvel para as plataformas Linux e Windows, que permite verificar a comunicao
com medidores da famlia SMW. Um dos principais objetivos do CLI mostrar como o SDK pode ser utilizado para realizar a leitura
e escrita de parmetros do medidor atravs de uma sesso segura e totalmente transparente para o desenvolvedor.

01.12.2016

8/13

Compilao
Esta biblioteca possui Makefile para diversos targets. A sada para qualquer target sempre gerada no diretrio Build.
Instrues para compilao:
Linux
[richard@arch-linuxtrunk]$make
ou
[richard@arch-linuxtrunk]$makeDISTRO=arch

Itron Cross-compilation

[richard@arch-linuxtrunk]$makeDISTRO=itron

Nota: Necessita do Buildroot com ucLibc. Deve ser configurado com gcc-4.8.3 e uclibc-0.9.33.2.
Windows
C:\Development\Workspace\shared\ModbusClient\trunk>make

Utilizar UDP Wrapper


possvel compilar o SDK para utilizar um socket UDP ao invs de transmitir pela serial. Utilize a seguinte sintaxe:
C:\Development\Workspace\shared\ModbusClient\trunk>makeWRAPPER=udp

Modos de Exibio
O CLI permite a exibio dos resultados em modo hexadecimal (corresponde ao payload da resposta Modbus do medidor), ou em
modo pretty (fcil compreenso).
Modo PRETTY
Para habilitar o modo pretty, digite a seguinte linha de comando:
[smw200i]$prettymode

E para desabilitar:
[smw200i]$noprettymode

Mtodo GET

01.12.2016

9/13

Este mtodo pode ser utilizado para recuperar valores de atributos do medidor. Uma lista de atributos e a resposta esperada so
detalhados nos tpicos adiante. A descrio das respostas para o modo decimal. Para facilitar a compreenso, o usurio pode
ativar o Modo PRETTY.
Identificador do Dispositivo
Retorna informaes do fabricante, famlia e modelo do medidor, bem como verso do firmware.
Comando:
[smw200i]$getid

Resposta:
010100000300035745470108534d5733303000000204302e303000
||_________|||______________________|
|fabricante|modelo
||tamanhodocampomodelo
|tamanhodocampofabricante

Interpretao da resposta:
Para obter os valores, deve-se converter os intervalos de informaes para string. No exemplo, o fabricante de 3 caracteres e
corresponde a "WEG" em ASCII. O modelo "SMW300".
Mais informaes sobre a resposta da funo ID podem ser encontradas aqui.
Relgio
O valor lido contm a data e a hora atuais do medidor.
O formato da resposta ddmmyyhhMMss.
Comando:
[smw200i]$getclock

Resposta:
0000040a0c151418
||||||minuto
|||||segundo
||||hora
|||ano
||ms
|dia

Interpretao da resposta:
Para obter os valores, basta visualizar o byte correspondente na forma decimal.
Tenso RMS Instantnea
O valor lido em milivolts (mV).
O medidor sempre retorna o valor correspondente de trs fases. Caso seja um medidor bifsico ou monofsico, as fases no
presentes retornam valor zero.
Comando:

01.12.2016

10/13

[smw200i]$getvoltage

Resposta:
0000000000034eac00000000000000000000000000000000
|_______________________|_______________________|_______________________|
tensoL1tensoL2tensoL3

Interpretao da resposta:
Para obter o valor de tenso, deve-se inverter a ordem do sub-array correspondente a fase desejada e convert-lo para um nmero
do tipo uint64_t.
Rel de corte e religamento
Permite abrir ou fechar o contato do rel.
Permite ler o estado atual do rel.
Ler o estado do rel

Comando:
[smw200i]$getbreaker

Resposta:
0000000000000000
|
|00=aberto,01=fechado

Interpretao da resposta:
Para saber se est aberto ou fechado, deve-se ler o valor do ltimo byte.

Mtodo SET
Este mtodo pode ser utilizado para configurar atributos do medidor. Para facilitar a compreenso, o usurio pode ativar o Modo
PRETTY.
Abrir o contato do rel

Comando:
[smw200i]$setbreakeropened

Resposta:
970004
||
||04=sucesso
|respostadocomandodeabertura

01.12.2016

11/13

Interpretao da resposta:
Sempre que o comando for executado corretamente o retorno ser o da resposta acima. Qualquer outra resposta significa que a
ao no foi executada.
Fechar o contato do rel

Comando:
[smw200i]$setbreakerclosed

Resposta:
960004
||
||04=sucesso
|respostadocomandodefechamento

Interpretao da resposta:
Sempre que o comando for executado corretamente o retorno ser o da resposta acima. Qualquer outra resposta significa que a
ao no foi executada.

Tabela de comandos
Mtodo

Atributo

Descrio

Ajuda.

exit

Encerrar a aplicao.

[no] pretty mode

Alterna entre modo pretty/hexa.

upgrade <filepath>

Atualizar o firmware do medidor.

set

timeout

Configurar o tempo de resposta da porta


serial.

get

current

Corrente RMS instantnea.

get

voltage

Tenso RMS instantnea.

get | set

clock

Data e hora.

get

id

Identificador do dispositivo.

get | set

breaker [opened | closed]

Estado do rel de corte/religa.

get

phase angle

ngulo de tenso entre fases.

get

frequency

Frequncia da rede.

get

<active | reactive | apparent> power

Potncia ativa, reativa ou aparente.

get

battery status

Estado da carga da bateria.

get

temperature

Temperatura interna do medidor.

get

events

Alarmes e erros.

get

<active | reactive> energy <import |


export> [total]

Energia ativa/reativa gerada/consumida


por tarifa/total.

get

ids

Identificadores (srie, fabricante, unidade


consumidora, ...).

get

version

Identificador e verso de firmware.

get

power factor

Valor instantneo do fator de potncia


medido (total e por fase).

01.12.2016

12/13

get

thd

Valor instantneo do THD medido (total e


por fase)

get

tariff zone

Posto horrio ativo

Arquivos
screenshot.png

43,9 KB

28.10.2015

Richard Heller Baeumle

interfaces.png

41,5 KB

29.10.2015

Richard Heller Baeumle

screenshot.png

53,5 KB

10.11.2015

Richard Heller Baeumle

cli_ethernet_udp.png

43,2 KB

21.01.2016

Richard Heller Baeumle

01.12.2016

13/13

Você também pode gostar