quinta-feira, 10 de abril de 2014

Eletrônica com Genexus

Genexus incorpora recursos para manipular dispositivos eletrônicos externos? A resposta é não. Mais não fique frustrado, é possível. E foi justamente esse tema que apresentamos no Evento GeneXus Brasil de 2014, e o que me deixou bastante feliz foi o fato de muita gente se interessar por esse assunto. Eu particularmente acreditava que tivéssemos algumas poucas almas perdidas nesta palestra, ou mesmo um punhado de 'nerds' malucos por eletrônica, mas de fato a presença dos participantes surpreendeu, e também me motivou a escrever esse artigo.

Esse tema é bastante especializado então, me desculpem àqueles que não possuem muita intimidade com assuntos eletrônicos, confesso que eu mesmo não entendo muito dos detalhes envolvidos, tanto que tive que recorrer aos universitários (meu filho André), mas como como houve grande comoção e demanda dos presentes na apresentação sobre maiores informações, então afivele seu cinto se segurança e vamos lá.

Incorporando 'Coisas'

A grande questão envolvida aqui é como podemos nos comunicar com dispositivos eletrônicos que se conectam a portas seriais do computador? Genexamente falando não é possível, pois a ferramenta não oferece 'ainda' suporte direto ao hardware. Digo ainda porque em seguida a nossa apresentação tivemos a palestra do Nicolas Jodal que falou muito sobre o tema de sensores e a possível evolução do Genexus Evolution '4' neste sentido, mas ainda nada concreto.

Desta forma precisamos recorrer ao conceito fundamental da ferramenta para entendermos como isso é possível.  Assim sendo, precisamos primeiro compreender que Genexus é um ambiente de desenvolvimento que possui uma linguagem de programação própria, mas o produto gerado pelo Genexus é de fato um programa escrito em uma linguagem nativa (C#, Java, Ruby), desta forma podemos incorporar recursos escritos nas linguagens nativas para 'complementar' aquilo que foi produzido automaticamente, assim como está esquematizado na Figura 1 abaixo.

Figura 1

Desta forma na geração do nosso sistema podemos incluir um código próprio que complemente com recursos aquilo que está 'faltando'.

Mas atenção, gostaria de ressaltar que esta prática deve ser utilizada com cautela, Genexus na maioria dos casos gera um sistema excelente, e isso fere um pouco a filosofia Genexus, uma vez que devemos sempre nos distanciar da tecnologia e trabalhar num modelo de maior nível, justamente por causa dos benefícios proporcionados pelo aspecto multi-plataforma, mas também entendo que sob certas circunstâncias muito especificas, podemos recorrer a esta modalidade, para atender àqueles casos ditos especiais, como por exemplo abrir uma catraca eletrônica após a identificação de uma pessoa, ou obter o peso de uma balança, enfim, temos muitas situações em que essa prática é necessária.

Como Incorporar Objetos Externos?

Para realizar esta proeza é necessário que você produza uma classe (.Net ou Java) compatível com a versão do compilador utilizado para compilar o código produzido pelo Genexus. Atenção, isso não é feito no Genexus, mas em uma ferramenta externa qualquer.

Esta classe deve ser programada para realizar as ações desejadas, como no nosso caso que foi o de ler e escrever coisas na porta serial do computador.

Em seguida, de posse desta DLL ou Class Java, o processo de incorporação é simples bastando importar este objeto para o projeto Genexus, seguindo os seguintes passos:


Figura 2
  1. Copie a DLL ou Class Java na pasta BIN da sua aplicação. Esta pasta pode ser acessada por meio da operação Tools -> Explore Target Environment Directory (no Genexus)
  2. Em seguida execute a operação Tools -> Application Integration -> .Net Assembly Import (ou Java Class Import), conforme apresentado na Figura 2, ao lado.
  3. Informe o local e o nome da DLL na caixa de texto, sendo que o local é o diretório completo até a pasta BIN de sua aplicação.
  4. Figura 3
  5. Clique em avançar, até o passo 3, no qual você deve escolher nesta classe quais os métodos públicos (da classe) que serão importados para o Genexus. Em nossa DLL incluímos os métodos abaixo, conforme podemos observar na Figura 3 ao lado: openPort,closePort,portStatus,GetResponse,SendRequest
  6. Pressione o botão Import para finalizar o processo.
Esta ação criará um External Object na sua kb, que você poderá entender como sendo uma API (Application Programming Interface) para o seu 'hardware'.

Para os interessados em testar este exemplo, disponibilizei a DLL Comunicação Serial que pode ser baixada a partir deste link.  Incluímos inclusive o código C# que a gerou. 

Como Acessar a Porta Serial?

A porta USB em seu computador é na verdade uma porta serial, e pode ser utilizada para conectar dispositivos externos, que agora passam a ser controlados pela DLL através do Genexus. Desta forma podemos incluir microcontroladores (como o Arduino, por exemplo) e sensores.

Figura 4
Um detalhe importante neste processo é a Porta, que é um termo que passará ao seu vocabulário a partir de agora, e que representa o local onde estaremos escrevendo e recebendo informações. Para o computador a porta é montada (definida) na medida que você conecta o dispositivo externo. Por exemplo, ao conectar nosso hardware (Arduíno) com um cabo serial ao computador, a porta montada foi a COM9. Isso foi possível de ver por meio do painel Device Manager do Windows, conforme pode ser visto na Figura 5 abaixo.

Figura 5
Este detalhe pode influenciar o funcionamento da DLL que você poderá baixar para o teste, visto que está programada para que funcione nesta porta COM9. Se em seu computador a porta for diferente desta você deverá alterar o código e compilá-lo novamente com o Visual Studio, alterando o texto da string para a sua porta.

static SerialPort _serialPort = new SerialPort("COM9", 9600, Parity.None, 8, StopBits.One); 

Prometo que estarei trabalhando em uma versão mais inteligente neste código.

Referente ao Arduino, temos aqui um dilema, uma vez que você poderá utilizar outro tipo de dispositivo, e neste caso a situação ficaria específica para cada caso. Mas para que apenas complementemos o exemplo vou incluir aqui um pequeno programa de teste, que deve ser enviado para o microcontrolador.

void setup()
{
   Serial.begin(9600);
}

void loop()
{
  switch(Serial.read())
  {
   case 'X': Serial.println("Ola mamae!");
             break;
   case 'Y': Serial.println("Ola papai!");
             break;
  }
}

Observe que este código se assemelha bastante à linguagem C, portanto é bastante fácil programar este microcontrolador.  No exemplo o que temos é o seguinte, se na porta serial tiver o 'comando' X o controlador responde com a mensagem Ola Mamãe! e se Y a mensagem Ola Papai!

Como Programar no Genexus?

Muito bem, ao chegar neste ponto acredito que você esteja com muita curiosidade para saber aonde vai parar esta história. Confesso que eu também estava muito ansioso para ver o final da operação, e acabei me frustrando porque tudo pareceu tão simples de ser programado, a não ser pelo fato da porta 'travar' com grande frequência. Ou seja, se por alguma razão ocorrer algum travamento do código, a porta ficará também alocada para o processo, gerando a necessidade de, pasmem, reiniciar a máquina. Tive que fazer isso várias vezes até pegar o jeito da coisa.

Para evitar qualquer confusão utilizei o seguinte algoritmo para realizar a operação:

  1. Verificar o status da porta, por meio do método portStatus(), da API.
  2. Se estiver fechada abrir a porta, openPort()
  3. Realizar a operação de envio do comando, SendRequest()
  4. Realizar a leitura da porta para obter o resultado da operação, GetResponse()
  5. Fechar a porta com closePort().
Para testar crie um WebPanel e programe dois botoes, conforme o modelo a seguir.

Figura 6
Ao se pressionar os botões os eventos são executados, cada qual definindo o comando a ser enviado para a porta e uma operação de execução definida no código a seguir.


Event 'Mamae'
&comando = comando.Mamae
do 'Executar'
Endevent

Event 'Papai'
&comando = comando.Papai
do 'Executar'
Endevent

Sub 'Executar'
&continua = false
if not &Serial.portStatus()
&Serial.openPort()
&continua=true
endif

if &continua and not &Comando.IsEmpty()
&Serial.SendRequest(&Comando)
&Resposta = &Serial.GetResponse()
msg(&resposta)
endif

// fecha se abriu
if &Serial.portStatus()
&Serial.closePort()
endif
EndSub

As variáveis foram definidas como indicadas na Figura 7 abaixo.
Figura 7
Sendo que a variável comando foi definida como sendo domínio enumerado com os seguintes valores.
Figura 8

O resultado não poderia ser diferente, ou seja, apresentar o texto enviado pelo controlador conforme o pressionamento dos botões.

Figura 9

Observe que a DLL que importamos é facilmente acessada via Genexus por meio da programação de comandos simples, conforme foram definidos na Classe C#.

&Serial.portStatus()
&Serial.SendRequest(&Comando)

Ou seja, nada diferenciando da programação tradicional da ferramenta.

Conclusões

Por meio deste exemplo, não vou dizer simples, porque esta palavra é meio perigosa ao se conectar mundos tão distintos, é possível verificar que Genexus oferece suporte, de forma elegante por meio dos External Objects, para realizar coisas que vão além da sua capacidade projetada.

Utilizando os recursos de geração de sistemas Web e Smartdevices é possível conciliar esses mundos gerando aplicações muito interessantes.  Portanto, seja bem vindo a esta nova classe de aplicações.

Para finalizar nada mais resta senão agradecer ao meu filho André pelo fato de um dia ter escolhido estudar Engenharia Elétrica (ou Eletricista), pois vou dizer uma coisa, conectar sensores, leds, fiozinhos, plaquinhas, e demais coisas não é tão simples assim. Tem um tal de 'espúrio' que é um bicho difícil de domar. Só um especialista em assuntos 'nerdianos' é capaz de matar a coisa com tanta eficiência. Portanto, valeu, o papai te ama.




PS. Já estava esquecendo, preciso agradecer também ao Rodolfo Robalo e Alejandra Caggiano da Artech, que foram a fonte de inspiração para estudarmos este tema, em sua palestra Las Cronicas de SmartDevices: ..., do Genexus International Meeting de 2011/Uruguay.






terça-feira, 25 de março de 2014

RowsToTabs

Há um ano atras apresentamos aqui no Genexando uma forma de aproveitar o modelo de abas gerado pela aplicação do Pattern Work With em uma transação em outros objetos (Interface com Abas) . De fato esse recurso sempre foi necessário e o modelo que propusemos era 'meio facil' e útil. Interessante que na mesma época um novo UserControl surgiu no Genexus Market Place, que eu acredito que tem potencial suficiente para atender a grande maioria das interfaces que utilizam as tais abas (transações, webpanels, webcomponents), sem a complexidade do componente do Pattern.

Então, nada mais justo que apresentar esse controle, produzido pelo S2b-Group e distribuído gratuitamente para a comunidade. Fiz o teste no Genexus Evolution 2 e resultado foi excelente, muito simples de utilizar.

Como Funciona

Após baixar (RowsToTabs) e instalar o controle no Genexus, o mesmo é apresentado no toolbox com o mesmo nome podendo ser arrastado para o WebForm de uma transação ou WebPanel.

Melhor se jogar o controle dentro de uma tabela com várias linhas, o segredo está em colocar um nome em cada Row (linha) da tabela, que conterá os conteúdos a serem divididos nas abas:


Em seguida em cada linha incluir as informações que se deseja dividir em abas. No meu caso na primeira Row inclui um Grid, na segunda e terceira dois webcomponents.  Lembrando que cada Row deve ter um nome distinto.


Para programar o controle é necessário:

1. Criar uma variável Character(40) e marcando-a como Collection

2. No evento Start programar o conteúdo desta variável, sendo que cada Add()deve incluir uma das linhas que foram renomeadas anteriormente, e em seguida o nome que se deseja que apareça na aba do controle.

3. Na propriedade Tab Pages do controle incluir a variável collection que representa as abas (&TabPage).


O resultado

A interface apresenta um controle bem interessante de agrupamento de informações.


A configuração das cores pode ser feita no arquivo style.css que se encontra na pasta RowsToTabs na pasta web da aplicação.


O que falta

Não tenho criticas quanto ao controle, pois acredito que sua funcionalidade já supera as expectativas, mas creio que pra ficar melhor somente falta neste controle um tratamento de runtime, do tipo um evento que ao clicar em uma determinada aba se dispare um evento que possamos programar. Que possa, por exemplo, possibilitar que definamos o o conteúdo dos webcomponents.



Para saber mais:


  • http://marketplace.genexus.com/product.aspx?rowstotabs,pt
  • http://wiki.genexus.com/commwiki/servlet/hwiki?RowsToTabs+User+Control,


sexta-feira, 14 de março de 2014

Genexus Evolution 3

Enfim, sabemos que a Tilo de fato será chamada Genexus Evolution 3, e quais as suas principais 'evoluções'?

Para obter as respostas a esta pergunta recomendo a você participar do 11o Evento Genexus Brasil, dia 9/4 no Caesar Park Faria Lima em Sao Paulo.

Eu vou, rs...

domingo, 9 de março de 2014

Business Component ou Atualização Direta, eis a questão

Aqui no Blog sou um defensor do uso de Business Component (BC) ao invés da realização da manutenção de registros por meio de Procedures, pois são muitas as vantagens que esse recurso nos oferece, mas como nem tudo nesta vida é um mar de rosas, tomemos alguns cuidados em sua aplicação. Se você ainda não foi apresentado aos BC's, convém dar uma olhada nos artigos anteriores sobre este assunto:
  1. Genexando...: Business Component com Transação de Dois Níveis
  2. Genexando...: Cuidados Básicos com Business Component

Desempenho x Segurança

Esta é a principal questão a ser considerada neste recurso pois ao optarmos por utilizar BC's não temos que nos preocupar com regras de negócio na manutenção dos registros, uma vez que serão aplicadas as que foram programadas na própria transação.  Isso trará maior segurança na operação dos dados, pois os mesmos serão tratados pelo modelo da transação Genexus, que envolve diversos controles como a Integridade Referencial, Unicidade, Regras, tornando muito mais simples e eficiente a programação de novas interfaces.

Por exemplo, uma vez alterada a regra na transação o efeito será imediato, repercutindo em todas as demais interfaces do sistema que utilizam o BC, ou seja o impacto de manutenção do sistema seria mínimo. Talvez este efeito já seja justificativa suficiente para adotarmos BC's. Portanto é um recurso importante a ser considerado em seus projetos.

Como grande inconveniente dos BC's temos o desempenho, que pode degradar muito o projeto dependendo de onde o mesmo é aplicado.  Isso porque o efeito de um LOAD é o mesmo que abrir o registro na própria Transação com o disparo das regras standalone (Default, Noaccept, ...) que por ventura não foram incluídas dentro da cláusula [web]{...}, já discutida aqui no segundo artigo da lista apresentada anteriormente. Como resultado temos uma perda imensa de tempo para realizar coisas que talvez já estejam definidas.

Como se Beneficiar dos BC's

Para simplificar sua vida, proponho a seguir uma tabela com diversas situações que talvez possam te auxiliar na escolha do recurso ideal:

SituaçãoBCProcedures
O registro ao ser inserido deve passar por um filtro de regras que impeçam que o mesmo seja gravado de forma erradasimnão
O registro ao ser atualizado deve passar pelo mesmo filtro de regrassimnão
O registro ao ser apagado pode gerar problemas de Integridade Referencialsimnão
A interface criada protege as informações, de certa forma, permitindo que o usuário faça apenas ajustes em situações totalmente controladas, como por exemplo, permite-se a troca de certo status através de um controle combo cujos valores são sempre válidos.simnão
A interface é do tipo Formulário de entrada e saída, apresentando apenas um único registro a ser manipulado.simnão
A interface é do tipo GRID apresentando diversos registros da tabela, possibilitando que o usuário realize alterações de informações, porém com registros individuais. Por exemplo, cada linha possui um botão para salvar as alterações da linha.sim (*)sim
A interface é do tipo GRID apresentando diversos registros da tabela, possibilitando a manutenção dos dados em todas as linhas ou apenas das que foram selecionadas pelo usuário (através de um checkbox, por exemplo)nãosim

(*) mesmo nesta situação podemos ter perda de desempenho.

Teríamos muitas outras situações a serem tratadas, mas fiquemos com essas por enquanto, pois já são suficientes para chegarmos a uma boa conclusão que é:

Se você está manipulando um único registro opte sempre por BC, pois o resultado trará maior segurança e normalmente nesta situação o problema de desempenho está mais no operador do sistema do que no próprio sistema.  Por outro lado, se a operação envolve mais que um registro, cuidado, BC pode trazer lentidão ao processo, pois os controles e regras da transação seriam disparados em todos os registros.

Recentemente tive que reprogramar uma interface do tipo GRID, regredindo ao modelo da programação de Procedures, pois a lentidão impedia uma boa utilização.  Portanto, fica ai a dica, uma boa observação do resultado final pode te orientar, no futuro, sobre as melhores práticas a serem adotadas em cada caso em seu projeto.