Pesquisa personalizada

2010/03/08

Circuito: O Hardware do Gym4Us 1.0

O hardware do Gym4Us 1.0 é bastante simples e carece de otimizações. Não o simplifiquei por questões de tempo e dinheiro - queria economizar ambos. A versão que estou apresentando é a primeira que fiz e até o momento em que escrevo este artigo, é também a única. Sendo assim, enquanto montava o circuito, também tinha em mente minimizar problemas e por isso modularizei todo o circuito de modo que pudesse testar cada módulo individualmente. Se algum módulo apresentasse problemas, poderia substituí-lo. A idéia era isolar qualquer problema que ocorrece de modo a não impactar em todo o circuito. Esta ideia de simplificar e modulalizar tudo, se aplica desde o design do circuito, até a montagem.

Como verão, o circuito pode ser tremendamente melhorada e isso para praticamente todos os aspectos, incluindo: gestão de consumo de energia, tamanho total do circuito, conexões externas, design de caixa para acondionamento do circuito, preço dos componentes, re-design dos módulos etc. Já tenho vários planos para as próximas versões e isso inclui:

  • Uso de um módulo Bluetooth comercial
    No circuito que montei acabei utilizando um módulo Bluetooth de um GPS Bluetooth velho
  • Uso do módulo receptor Polar RMCM01
    Infelizmente, como não consegui montar um receptor adequado, fui obrigado a enrolar uma próximo do transmissor da cinta. Pelo fato do RMCM01 ser pequeno e relativamente barato, creio ser preferível usá-lo do que tentar criar um receptor equivalente. O maior problema que tive para construir um receptor para as cintas de 5KHz é que, onde moro, aqui em Brasília-DF, não há amplificadores operacionais com as características necessárias para a amplificação e filtragem do sinal.
  • Substituição do PIC16F628A
    Eu acabei por usar o PIC16F628A, pois tenho uma centena destes sem uso aqui em meu laboratório. No entanto, é desejável substituí-lo por algum outro microcontrolador de baixo consumo e de poucos requisitos para o circuito de apoio. Talvez algum PIC18 ou mais provavelmente, algum ARM7. Quando já estava testando a firmware para o PIC16F628A, me dei conta que ele necessitava de 5V para que funcionasse adequadamente com um clock de 20MHz. Da forma como idealizei o circuito, para que a amostragem do sinal ocorra, é necessário um clock de 20MHz para este PIC em particular. Dessa forma, acabei, sem me dar conta, o requisito de alimentação para o circuito, já que teria que suprir 5V para o PIC.
  • Usar algum gerenciador de carga de bateria e alimentação
    Estou utilizando a bateria e o circuito gereciador do GPS Bluetooth que desmontei. O ideal é usar alguma solução que seja aplicável a qualquer um que for montar o circuito.
  • Eliminar o circuito de Step-Up e regulagem para 5V
    Como expliquei antes, por causa do PIC16F628A estar funcionando a 20MHz, é necessário alimentá-lo com 5V. Quando ele for substituído por algum microcontrolador de 3,3V, ou inferior, creio que ficará mais fácil e econômica a alimentação do circuito. Ainda assim, pode ser que seja necessário manter o circuito de Step-Up ou algum equivalente, e ainda manter alguma regulagem de voltagem para o microcontrolador, mas provavelmente isto será mais fácil do que fazendo da forma como está atualmente. De qualquer forma, mesmo que continuasse necessário produzir os 5V, isto poderia ser realizado com algum IC comercial e de preferência que fizesse o Step-Up e a regulagem tudo num único circuito. Há vários ICs com esse propósito que podem ser utilizados. Na solução que eu fiz para o Gym4Us 1.0, acabei por criar três circuitos que juntos forma o step-up e a regulagem que provê os 5V. Obviamente isto pode e deve ser simplificado!
  • Adicionar suporte a cartão de memória
    A ideia é gravar o percurso usando um GPS e juntamente gravar o monitoramento do coração. Tenho visto que o NST não é tão estável quanto gostaria e por isso é interessante manter o tracklog e o HRM gravado por hardware para recuperação em caso de pane do NST.
  • ECG
    Criar um hardware para realizar o ECG e enviar esses dados no mesmo pacote do NST. Outras aplicações poderão mostrar diretamente o ECG, sua forma de onda, batimento por minuto e até prever arritimias, bem como, outras anormalidades. Isto também substituirá, com precisão, a cinta de monitoramento cardíaco de 5KHz.
  • Sensor de temperatura
  • Sensor de umidade
  • Sensor de nível de CO2
  • Conta giros para a bike
  • Sensor de cadência para a bike
  • Display
    Dependendo do uso que se destinatar, um display pode ser interessante. Hoje há muitos displays gráficos de celulares que são baratos e eficientes.
  • Utilização de energia solar para carga de bateria
  • Transmissão dos dados também por outros meios, como:
    • RS-232
    • Infravermelho
    • Ultra-som
    • Zigbee
    • Wifi

Uma das vantagens no frame de dados que é enviado ao NST, é que, ao que observei, ele é redimensionável. Dessa forma é possível aumentar seu tamanho e enviar outros dados que somente aqueles usados pelo NST.

O circuito do Gym4Us 1.0 é composto dos seguintes módulos:

  • Circuito de Recepção e Amplificação de Sinal emitido pela cinta transmissora;
  • Módulo de Microcontrole para amostragem de sinal, detecção de sinal, cálculo de batimento do coração e empacotamento dos dados no formato do Nokia Sports Tracker para transmissão via Bluetooth;
  • Módulo Bluetooth para transmissão dos dados para o celular;
  • Módulo de Energia
    Com base numa bateria recarregável, um gerenciador de recarga e circuito para step-up e regulagem, temos a energia necessária para o módulo bluetooth, o microcontrolador e o módulo de recepção do sinal emitido pela cinta transmissora. No circuito que fiz, acabei por criar um módulo de step-up e regulagem para 5V. Dessa forma, o módulo de energia final, ficou dividido em:
    • Partes obtidas do GPS Bluetooth que utilizei
      • Bateria recarregável de íons de lítio;
      • Módulo de gerenciamento e recarga da bateria de íons de lítio;
      • Módulo de alimentação para o módulo Bluetooth (3,3V);
    • Circuitos que criei para a alimentação do Gym4Us 1.0 - composto de um step-up e regulador de voltagem
      • Módulo oscilador
        Baseado num 555 gera um sinal quadrado para o circuito de step-up
      • Módulo de chaveamento, indução de sobre-voltagem e retificação
        Baseado num transistor de potência BD139, um indutor de 3.3mH para elevação de voltagem, diodo schottky para retificação e acumuladores. Um transistor de uso geral e um diodo comum também funcionariam. O valor do inductor não é crítico e indutores entre 20uH a 30mH podem ser usados, desde que a frequência do oscilador seja ajustada. Utilize um multímetro para ajustar o oscilador de modo a obter a maior tensão possível e assim, o melhor rendimento.
        Junto com o módulo oscilador, compõe o circuito de step-up.
      • Módulo regulador de voltagem
        Baseado num 7805

Labels: , , , , , ,

2010/03/05

Gym4Us 1.0 - O Que Você Precisa Para Fazê-lo

Se quer já começar a correr atrás dos componentes necessários para o projeto, segue uma lista parcial:

  • Osciloscópio
    Pode ser qualquer.
    Eu mesmo uso um equipamento de baixo custo que funciona via USB. Trata-se do DSO-2150 USB que me custou USD$ 150,00 no eBay.
  • Multímetro
    Novamente pode ser qualquer aparelho - até mesmo aqueles de R$ 15,00 que se encontra nos camelôs.
  • Cinta transmissora de monitoramento cardíaco compatível com o padrão de 5KHz ou 5.4KHz
    Eu uso a Polar T31 non-coded
  • Opcional: Relógio ou equipamento receptor para a cinta transmissora de modo que você possa conferir a recepção e transmissão
    Estou sem relógio para a cinta Polar T31. Inicialmente tinha a cinta e o relógio do Polar RS300X, mas foi vendido e não tenho mais.
    O que sobrou foi um sistema de monitoramento Timex com o relógio e a cinta, mas a cinta é incompatível com o Gym4Us, pois transmite seus dados num sistema RF digital que é totalmente diferente do que foi utilizado no projeto do Gym4Us 1.0. Dessa forma, só utilzei o Timex para conferir se o batimento cardíaco que calculei estava correto (e está!). Obviamente usei as duas cintas simultâneamente para poder conferir o resultado. Mas se você já tiver o relógio para sua cinta, com certeza será melhor até mesmo para o uso prático/diário, pois poderá olhar no relógio quando precisar, sem ter que ficar dependendo unicamente do celular para conferir seus batimentos.
  • Módulo Bluetooth para Perfil de Porta Serial com UART
    Eu desativei o módulo GPS de um GPS Bluetooth e estou usando somente o módulo Bluetooth dele para transmitir os dados
  • Opcional: Dongle USB Bluetooth
    Se seu desktop ou notebook já tiver suporte a Bluetooth, não é necessário. Qualquer adaptador serve. De qualquer forma, é opcional se você não for depurar pelo PC. Se você for comprar um adaptador Bluetooth, compre algum que tenha o gerenciado da BlueSoleil ou Widcomm/Broadcomm, pois o gerenciador do Windows é quase inútil!
    No meu caso foi extremamente útil no desenvolvimento do Gym4Us, desde a fase de testes, até a fase de descoberta do protocolo aceito pelo Nokia Sports Tracker.
  • Microcontrolador PIC16F628A
    Futuramente irei usar outro microcontrolador. Provavelmente um ARM7 da família LPC2000 da NXP que consome pouca energia, é barato e pequeno.
  • Programador para o PIC16F628A
    Eu tenho um ICD2 da Labtools. Você pode até mesmo fazer o seu, há vários projetos na Internet que ensinam a montar programadores para PIC. No Mercado Livre também pode-se encontrar soluções prontas de baixo custo.

Reaproveitando Componentes de Sucata para o Projeto Gym4Us

Durante toda a pesquisa e desenvolvimento do que me levou ao Gym4Us, tive em mente minha atual falta de grana e por isso evitei ao máximo adquirir qualquer componente eletrônico. Me limitei aos que já possuo em meu laboratório - que também é meu escritório e quarto de visitas. Tenho 99.9% de coisas entulhadas em meu laboratório que nunca utilizo e dessa vez quis dar uso a algumas delas.

Do Monitor CRT: Fios Esmaltados

Como exemplo, cito o monitor CRT que não funcionava mais e que já estava sem uso há mais de um ano e que o desmontei para retirar os fios esmaltados que necessitava. Preferi retirar os fios do monitor, do que de transformadores velhos que tenho de montes - dá muito trabalho retirar estes fios de transformadores velhos e corre-se sempre o risco de machucar-se com as placas de ferro de seu núcleo e carcaça; eu sempre acabo por me cortar quando tento retirá-las.

Do MODEM: Indutores

Além do monitor e dos transformadores, também ao longo de duas décadas, acumulei uma série de outros aparelhos que já não funcionam mais, mas que acabo guardando para que justamente possa reaproveitar seus componentes e assim, mesmo a custa de tempo, tentar economizar algum dinheiro.

Tinha alguns MODEMs e switches velhos e vi que eles tinham indutores que poderiam ser úteis posteriormente no projeto.

Do Rádio AM/FM: Bobina com Núcleo de Ferrite para Ondas Curtas

Do rádio velho que não funcionava, tirei a bobina com núcleo de ferrite. Ela poderia ser útil no caso de eu desenvolver uma bobina para a captação a distância (uns 30cm a 1m) do campo magnético oscilatório gerado pelo transmissor da cinta de monitoramento cardíaco.

GPS Bluetooth: Energia e Módulo Bluetooth

Há alguns anos atrás, por meados de 2006/2007, ao notar que naquela época havia um nicho - que já não há mais - de mercado, comecei a vender GPSs Bluetooth. Naquela época a qualidade dos equipamentos era outra, bem como as marcas que comercializava e o preço era coisa importante em tempos de dólar alto e tecnologia nova. Dessa forma, naquela época, optei por equipamentos que fossem mais baratos para que pudesse vendê-los - diferentemente de hoje que a marca dos equipamentos que vendo são de qualidade e os produtos também o são e apesar do preço ser superior, a qualidade também o é e não tenho problema. Como resultado da tecnologia ser nova e o equipamento ser de baixo custo, acabei por receber um ou outro equipamento com defeito. Ao longo do tempo, conforme ia identificado os equipamentos defeituosos, após providenciar outro equipamento ao cliente ou a devolução do valor pago, os separava de modo a devolvé-los ao fabricante numa futura oportunidade. A questão é que devolver equipamentos que não são fabricados no Brasil para o fabricante no exterior, é coisa complicada, cara e burocrática. Dessa forma, tive que assumir o prejuízo e ficar com as unidades defeituosas. Não as joguei fora, simplesmente anotei o problema e as deixei separadas para que pudesse usá-los como sucata. Devo ter uma dúzia de GPS Bluetooth com problemas.

A cinta de monitoramento utilizada pelo Nokia Sports Tracker transmite seus dados via Bluetooth e logo de início imaginei que o protocolo utilizado era o SPP (SPP - Serial Port Profile). Para ter certeza, fiz alguns testes utilizando um adaptador Bluetooth plugado ao meu computador e realizei o pareamento com o Nokia Sports Tracker. O NST buscava justamente pelo serviço de porta serial. Após eu indicar ao NST que ele deveria se conectar ao computador, ele o fazia conectando-se ao serviço de SPP que havia habilitado no computador. O gerenciador WidComm me indicava a conexão e o NST ficava aguardando dados do dispositivo Bluetooth, no caso, o computador. Dessa forma, tive certeza que realmente era necessário um módulo Bluetooth com o perfil de porta serial.

Como sabia que iria precisar de um módulo bluetooth para poder transmitir a informação do batimento cardíaco ao celular, logo após desconsiderar o gasto de dinheiro com aquisição de um módulo bluetooth no exterior, acabei por me lembrar deste monte de GPS Bluetooth com problema. Para quem não sabe, os GPS Bluetooth utilizam o perfil de porta serial. O próprio protocolo NMEA 0183 foi criado pensando-se numa comunicação serial e geralmente os GPS Bluetooth trabalham com o protocolo NMEA 0183. Dessa forma, tem-se um módulo Bluetooth com suporte ao perfil de porta serial em cada um dos GPS Bluetooth. Pensei que a chance conseguir reaproveitar algum módulo bluetooth dos GPS Bluetooth seria pequena, mas mesmo assim, devia tentar.

Como justamente iria usar um GPS Bluetooth com problemas, tinha que ter certeza que o problema não estaria na parte bluetooth, ou do contrário, não me teria utilidade. Comecei escolhendo algum GPS Bluetooth que eu tivesse certeza que o bluetooth funcionava. Para tanto, liguei o GPS Bluetooth e realizei o pareamento do GPS Bluetooth com o computador e capturei as sentenças NMEA utilizando um programa de comunicação serial. Se você não tem experiência com dispositivos seriais com os GPS Bluetooth, saiba que qualquer programa de comunicação serial serve. Incluindo: Hyperterminal, Putty, screen, gtkterm e outros. Então usando o programa de comunicação serial, vi que as sentenças estavam sendo recebidas corretamente. O problema do GPS Bluetooth parecia estar no próprio módulo GPS que nunca conseguia estabelecer sua posição, mesmo quando em condições de recepção excelentes. Ótimo! Consegui um módulo Bluetooth.

Identificado um aparelho que tivesse o módulo Bluetooth funcionando, após abri-lo, podia-se ver claramente o que era o módulo GPS e o que era o módulo Bluetooth. O próximo trabalho seria identificar qual o pino onde se encontra a saída UART (TX - saída da porta serial) do módulo GPS. O conceito é simples: o GPS envia os dados de suas sentenças utilizando-se de uma saída serial; esta saída serial deve estar ligada a uma porta serial de entrada (RX - recepção) da UART do módulo Bluetooth. Assim, o GPS transmite os dados das sentenças para o módulo Bluetooth e o módulo Bluetooth as recebe. Então bastava-se encontrar o pino de saída do GPS ou o pino de recepção do módulo Bluetooth. Para isso, sabia previamente de algumas características do sinal que deveria identificar, sendo:

  • A comunicação típica de qualquer GPS é 4800 bauds, nenhuma paridade, um bit de parada e sem controle de fluxo.
    As vezes o baudrate é outro, mas isto é incomum. Tenho visto módulos GPS com baud rates de 4800, 9600 e 38400.
  • O nível do sinal da UART seria LVTTL. No caso, poderia estar entre 1,8V a 3,6V quando em nível alto e abaixo de 0,6V quando em nível baixo;
  • As sentenças NMEA são enviadas todas de uma vez e após serem enviadas, há uma pequena pausa na transmissão do GPS, ou seja, após uma atividade, há um pequno período onde não há atividade alguma na UART do GPS. Este padrão se repete a cada segundo.
  • Por fim, tendo sorte, haveria um pino do lado do módulo GPS que teria um pino com os mesmos sinais do lado do módulo Bluetooth, ou seja, um pino com a TX do GPS e do lado do Bluetooth, haveria uma RX.

Com o GPS Bluetooth ligado e transmitindo para o bluetooth do computador (se não estiver transmitindo, geralmente o GPS é desligado para economizar energia e seria impossível identificar atividade), após inspecionar, com ajuda de um multímetro (não cheguei a usar o oscilóscopio até aqui) vários pinos do lado do GPS e do lado Bluetooth, encontrei um padrão de sinal que parecia ser o característico de uma UART transmitindo dados típicos de GPS (sentenças NMEA). Para ter certeza, aí então, usei o oscilóscopio para "ver" se realmente o sinal estava dentro do que seria uma UART. Pelo oscilóscopio, mesmo sem fazer uma análise dos dados à nível digital, vi que realmente era uma UART e que a transmissão estava se dando no que parecia ser 4800 bauds.

Identificado os pinos de transmissão do GPS e recepção do Bluetooth, o próximo passo foi desativar o pino de transmissão do GPS. Isto deu um pouquinho de trabalho pois se trata de componentes muito pequenos e com alta densidade de integração. Tentei simplesmente queimar com o ferro de solda o pino TX do módulo GPS, mas ainda assim, mesmo sem o pino RX do Bluetooth apresentar atividade aparente, todas as vezes que ligava o GPS Bluetooth, era transmitido alguns dados contendo a identificação da firmware do módulo GPS e após isso, nada mais era transmitido - naturalmente via isso com o programação de comunicação serial no computador. Então, presumi que talvez houvesse alguma outra saída que ainda estivesse se comunicando com o módulo Bluetooth, derrepente alguma saída de depuração ou mesmo algum outro tipo de saída, como: SPI ou I2C. Num ato de loucura, resolvi ir queimando pino-a-pino do módulo GPS até que nada fosse apresentado no programa de comunicação serial que usava no computador ao ligar o GPS Bluetooth. Após queimar alguns pinos, como eram muitos, já estava um tanto entediado com aquilo. Então, resolvi mesmo foi tentar remover na base da força bruta o módulo GPS do circuito. Peguei um alicate e tentei remover o módulo GPS, sem sucesso - estava muito bem preso ao resto do circuito. Insanamente, com o próprio alicate, comecei a "raspar" aquele monte de capacitores e resistores SMD em miniatura que haviam no módulo GPS (e somente no módulo GPS). Após isso, vi que ao ligar o GPS Bluetooth, nada mais era transmitido ao computador, apesar do Bluetooth ainda estar funcionando. Restava então saber, se seria capaz de transmitir dados para o módulo Bluetooth usando daquele pino de recepção que havia identificado previamente.

A continuar.... (estou escrevendo)

Labels: , , , , , ,

2010/03/04

Detectando o Batimento do Coração

Na busca de uma solução, tive antes que entender o funcionamento de uma série de coisas, inclusive como funcionam as cintas de monitoramento cardíaco, seus sistemas de captação, amplificação, filtragem, detecção, codificação e transmissão. Além disso, também estudei um pouco sobre o ECG e as diferentes maneiras de se perceber o batimento do coração. Não sou médico, nem engenheiro, nem cientista; sou um mero programador que gosta de xeretar, portanto, de antemão, peço desculpas pelas tolices que falei e falarei até o fim deste artigo e de futuros artigos correlatos. A seguir, irei expor o que entendi e como isso me direcionou ao longo da pesquisa e desenvolvimento da solução final. Somente ao fim de todos os artigos irei compilar e acrescentar as informações necessárias para se compor o projeto em si, de forma simples, direta e técnica do ponto de vista do hardware e software; antes disso, haverá muito blah-blah-blahh de minha parte.

Cintas de Monitoramento Cardíaco

O funcionamento das cintas de monitoramento cardíaco, pode ser descrito nos passos abaixo:

  1. As cintas de monitoramento cardíaco captam a diferença de potencial (voltagem) que ocorre no momento da contração/relaxamento das células cardíacas como um todo.
  2. Posteriormente o sinal captado é amplificado e filtrado. Este processo pode-se repetir várias vezes, até que o sinal possa ser utilizado no próximo estágio do circuito.
  3. O sinal amplificado pode ser aplicado num microcontrolador ou mesmo enviado para algum circuito analógico de detecção de pico, por exemplo.
  4. Dependendo da cinta de monitoramento, a informação sobre o batimento cardíaco poderá ser transmitida para algum monitor (relógio, computador, smartphone ou algum outro equipamento) utilizando-se uma das abordagens abaixo:
    • A cada batimento do coração um sinal é transmitido pela cinta de monitoramento para o equipamento receptor que fará a outra parte do monitoramento. Atualmente, vi que esta abordagem é a mais comum, ou seja, o coração bate, a cinta percebe isso e para notificar o equipamento receptor, envia um sinal que é interpretado, como: "o coração bateu".
    • Outra abordagem é a cinta transmissora perceber e acumular dois ou mais batimentos do coração, de modo que ela calcule a taxa de batimento do coração e já transmita essa informação para o receptor, como: "o coração está batendo a uma taxa de X batidas por minuto". Nesse caso, pode-se postergar o envio dessa informação de modo a enviá-la de tempos-em-tempos (caso do sistema Timex que envia de dois-em-dois segundos a taxa de batimento por minuto).

As vezes a cinta irá realizar a transmissão por algum processo que evite ou minimize a interferência com outros equipamentos, incluindo outras cintas de mesmo modelo. Há várias formas disso poder ser realizado e não irei listá-las aqui.

Sistemas de Transmissão

A cinta pode transmitir a informação do batimento cardíaco para o equipamento monitor utilizando-se diferentes meios físicos e lógicos, sendo que particularmente dois sistemas é de nosso interesse:

RF - radiofrequência, ou seja, ondas eletromagnéticas

Há diversas frequências que podem ser utilizadas e algumas vezes o sinal poderá ser ou não modulado, depende do modelo da cinta. Quando estiver modulado, algumas vezes a transmissão poderá ser digital. Sendo alguns deles:

  1. Modulação FM para envio de dados digitais (não sei a faixa de frequência)
    Caso do Timex
  2. Bluetooth (2.4GHz)
    Usado pela cinta Polar for Nokia, BioHarness da Zephyr, Spurty Chest Strap e FRWD B, por exemplo.
  3. ANT+ (2.4GHz)
    Usado pela Garmin e Timex, dentre outras.
  4. Demais sistemas de transmissão de alta-frequência
    Caso dos Garmin, alguns da Polar e outros muitas vezes utilizando a faixa de 2.4GHz, mas usando protocolos proprietários de cada fabricante e modelo de equipamento.

Vale ressaltar que a lista acima não tende a esgotar os sistemas RF em uso por monitores cardíacos, mas somente exemplificar o que é na verdade uma gigante variedade possível. E além da frequência de 2.4GHz, que é bastante utilizada por ser uma faixa para uso livre internacionalmente, outras faixas de frequências também são utilizadas.

O sistema de recepção para cintas que transmitam via rádiofrequência, são os convencionais para RF, mas variando desde simples receptores FM a sofisticados mecanismos de divisão de frequência. Ressaltando que posteriormente ao receptor RF, se encontra etapas decodificadoras características de cada solução.

Modulação de campo magnético

Este meio de transmissão cria um campo magnético e o modula de modo a transmitir a informação da cinta para o equipamento monitor. Com certeza, é a forma mais popular e ainda em uso existente, apesar de estar sendo substituída pela transmissão em RF, principalmente dados os atuais avanços dos últimos anos em relação a transmissão de dados via RF utilizando-se pouca energia.

Os equipamentos que utilizam a modulação de campo magnético, geralmente o fazem numa frequência de 5KHz ou 5,4KHz. A sequência de pulsos é breve e ocorre a cada batida do coração - para cada batida do coração, uma sequência de pulsos é enviada. A frequência da sequência de pulsos é de 5KHz e terá duração de 7ms a 13ms, mas isso poderá variar conforme o equipamento. Os equipamentos de ginástica de acadêmia que dão suporte ao uso da cinta de monitoramento cardíaco, geralmente exigem que a cinta utilize este esquema de transmissão, incluindo a frequência de 5KHz. Procurei saber se existe alguma norma ou especificação que padronize isto para os diferentes equipamentos de ginástica e cintas, mas não pesquisei o suficiente para concluir se há ou não normas sobre isto. o certo é que as cintas comerciais que utilizam este esquema de transmissão são compatíveis com esses equipamentos.

No caso das cintas da Polar com transmissores do tipo coded (codificado), estes, além de enviar um pulso a cada batida do coração, também, nos milissegundos posteriores, enviam duas outras sequências de pulsos. A ideia dos transmissores Polar coded é que a diferença de tempo entre a emissão das três sequências de pulsos para cada batida de coração deve ser variável em relação a diferentes transmissores, ou seja, cada transmissor coded enviará suas três sequências em tempos diferentes um do outro. Dessa forma, poderá um equipamento receptor de monitoramento poderá reconhecer que um dado conjunto de sinais é de uma determinada cinta e descartar os que não forem. Para isso, é necessário que inicialmente se utilize a cinta de monitoramento com o equipamento receptor de modo a estar longe de outras cintas transmissores, dessa forma o equipamento monitor poderá calcular a diferença de tempos entre as três sequências de pulsos do equipamento que se está utilizando e memorizar estes tempos para que posteriormente, quando se utilizar a cinta em ambiente onde haja outras cintas transmitindo, se possa identificar quais sequências de pulsos devem ser consideradas e quais não pelo equipamento receptor (relógio de monitoramento).

A vantagem deste sistema de campo magnético modulado, é que, na prática, ele não sofre interferência considerável dos sistemas de RF. Além disso, qualquer material não-metálico é praticamente transparente para o campo magnético e isto inclui o corpo humano e a água.

Eu fiquei de certa forma surpreso quando descobri que havia este sistema de transmissão. Note que se a transmissão fosse realizada via RF, o comprimento da onda de rádio seria de 60Km!!! Para quem conhece de eletrônica ou mesmo física básica, tem noção que isso é totalmente fora da faixa de rádio frequência comumente utilizado. Além disso, no caso de RF, quanto maior a onda, maior a energia necessária para criá-la. Também no caso de uma onda de comprimento de 60Km, a antena transmissora, por mais engenhosa que fosse, seria um tanto grande - eu creio. A bateria dessas cintas de monitoramento, duram entre meses a alguns anos, ou seja, essas cintas consomem pouca energia. Logo, quando se diz que a transmissão dessas cintas é realizada a 5KHz, se percebe que a transmissão não é via RF, mas nesse caso, via um simples campo magnético - no caso, que se faz oscilar a 5KHz, ou seja, se "liga" e "desliga" um campo magnético eletricamente formado.

Detectando o Campo Magnético Oscilante

É possível observar o sinal que a cinta de monitoramento emite para o aparelho receptor. Para tanto, será necessário o uso de uma cinta transmissora que realize a transmissão a 5KHz. Se for usar uma cinta Polar, opte por alguma que seja do tipo uncoded, ou seja, o tipo mais simples que tem. Caso utilize uma cinta Polar do tipo coded, deve-se levar em conta que esta transmite três sequências de pulsos ao invés de somente uma única sequência por batida do coração.

Para meus testes, inicialmente eu utilizei a cinta Polar coded que acompanha o RS300X e posteriormente, a vendemos e acabei conseguindo comprar uma Polar T31 uncoded usada, mas em bom estado e por um bom preço - custou R$ 78,00 no ML, já com o frete - e ainda veio com um conta giros do Polar S150 para a bike. Aqui em Brasília, numa feira que é conhecida como "Feira do Paraguay", mas que rebatizada - hipocritamente - para "Feira dos Importados", pode-se comprar a cinta transmissora Polar T31 non-coded por preços que variam entre R$ 85 a R$ 130. Mas como mencionei antes, qualquer cinta compatível de 5KHz, serve.

Para se perceber um campo magnético oscilante, pode-se utilizar uma simples bobina feita com fios. O campo magnético oscilante irá induzir uma pequena corrente elétrica na bobina. Para se ter ideia, dez voltas de fio comum encapado ou esmaltado enrolados numa caneta, já é suficiente para se detectar o campo magnético que é produzido pelas cintas de monitoramento cardíaco que utilizam este meio de transmissão. Faça o teste, enrole dez ou vinte voltas de fio encapado numa caneta ou lapis, ligue as duas extremidades do fio a um osciloscópio ou multímetro e aproxime ao máximo a bobina da cinta de monitoramento cardíaco. Lembre-se que a cinta só irá sinalizar o batimento do coração, ou seja, gerar o campo magnético oscilante a 5KHz durante um período de 5ms a 13ms, se você estiver usando essa cinta no peito, como normalmente faria. Na dúvida, utilize seu aparelho monitor (relógio usado com a cinta) para te indicar se a cinta está realmente transmitindo. Quando a cinta transmitir, você verá no osciloscópio um padrão senoidal de ondas com as características já mencionadas. No multímetro, verá uma pequena variação de tensão para cada batida do coração. Nota: se estiver usando uma cinta como as da Polar do tipo coded, poderá ver três sequências de pulsos no osciloscópio, ao invés de uma única por batida. As cintas codificadas da Polar irão atrapalhar a visualização do funcionamento do conceito de indução aqui descrito se usar um multímetro ao invés do osciloscópio - preferencialmente, use algum osciloscópio.

Se acaso não estiver detectando nada no osciloscópio, mesmo tendo certeza que a cinta está transmitindo, tente reposicionar a bobina ao longo do transmissor. Deixe a bobina o mais próximo possível do transmissor. Se mesmo assim não detectar nada, enrole o fio esmaltado ao redor do próprio transmissor da cinta e utilize uma fita adesiva para manter o fio devidamente enrolado - 20 a 30 espiras são suficientes. Comigo, de ambas as formas funcionaram, mas no fim, para não ter problema com a recepção quando estivesse usando a cinta e também para não aumentar o volume da cinta, preferi enrolar o fio diretamente em torno do transmissor da cinta.

Se for experiente com eletrônica analógica, amplificadores operacionais e filtros, com certeza ficará feliz em saber que poderá montar um receptor para sua cinta de monitoramento utilizando ampop ou preferencialmente, amplificadores de instrumentação ou mesmo tentando utilizar alguns JFET com amplificadores operacionais.

Também há vários projetos para recepção do sinal emitido pelas cinta de monitoramento que podem ser encontrados na web, veja alguns:

Polar Heart Rate Module - RMCM01

De todos os circuitos de recepção, com certeza, o mais fácil de se fazer, é utilizando o módulo RMCM01 da própria Polar. Este módulo receptor é um SOC - ele contém tudo o que é necessário para se captar o sinal transmitido por uma cinta de monitoramento cardíaco da Polar que transmita em 5KHz. O único componente externo que é requerido, é um cristal de 32KHz. Este módulo funciona tanto com as cintas coded como com as non-coded.

Quero muito testar este chip, mas não tive oportunidade (dinheiro) para fazê-lo. Este tipo de componente eletrônico não se encontra no Brasil e deve ser importado. Se acaso houver alguém que queira gentilmente ceder uma ou duas amostras deste chip, ficarei feliz de testá-lo e publicar o resultado dos testes aqui :)

Outras Formas de Detecção do Campo Magnético

Não cheguei a testar, mas creio ser possível utilizar um transistor de efeito hall com o objetivo de detectar o campo magnético.

A continuar.... (estou escrevendo)

Labels: , , , , , ,

2010/01/30

TIM 3G Ilimitado: EhLimitado, mesmo!!!

Abaixo, resposta oficial da TIM à reclamação que fiz via web pela seção de atendimento no website da própria TIM. Trata-se da picaretagem de venderem um plano que dizem ser ilimitado, mas que na verdade eles limitam a velocidade. Pior: como eu não sabia, acabei-me fidelizando num pacote de dados de 1Mbs!!!! Só agora, quando precisei, é que soube que eles limitavam. Quando fui realizar a comprar, apesar de ter questionado se havia algum tipo de limitação tráfego, a atendente da TIM (loja da TIM do ParkShopping de Brasília) disse que não havia nenhum tipo de limitação..

Meu Questionamento

Prezados(as),
   Até cerca de duas semanas atrás, estava muito satisfeito com plano Infinity 160 + 1Mbs de dados **** I LI M I T A D O ***. Uso a conexão de dados constantemente no trabalho, mas apenas para realizar pequenos acessos a e-mail e notícias - fazendo pouco download de arquivos. No entanto, este mês fiquei sem provedor em minha residência e fui obrigado a usar internet utilizando meu plano da TIM (meu celular é o Nokia 5800 XPM que adquiri num plano fidelidade com a TIM); fiz muitos downloads, possivelmente alguns gigabytes fora baixados. Neste fim de semana, me dei conta que minha conexão de dados 3G, que sempre funcionou muito bem, como eu já disse antes, agora não funciona a velocidade plena. Estou nos mesmos lugares que sempre estive, ou seja, nos mesmos lugares que sempre tiveram cobertura UMTS 3G e que antes alcança com facilidade velocidades de até 139Kbytes/s, mas que agora não passa de 23Kbytes/s com raros (menos de 0.01% do tempo) picos de exceção.
Dessa forma, gostaria que a TIM me informasse se ela impõe algum tipo de limite de velocidade quando o cliente ultrapasse alguma quantidade de dados trafegados (download ou upload). A TIM impõe essa limitação? Se faz, a partir de quantos GB (Gigabytes) trafegados? Se não impõe limite, por que não consigo mais obter as mesmas velocidades de antes se meu plano é de 1Mbs?!!!
Aguardo retorno.

Grato,
Marcio Wesley Borges
marciowb[*]gmail.com
(61) 8211-5400 / (61) 3xxx-xxxx

--------------------------------

Protocolo da TIM (auto atendimento via web)

Obrigado por entrar em contato com a TIM.
Sua mensagem foi enviada com sucesso e você receberá uma resposta em no máximo 2 dias úteis. Por favor, anote o número do seu chamado:

2010014653061

Resposta da TIM

Protocolo 2010014653061

Prezado Sr. Marcio

Conforme clausula 17 do termo de compromisso: Para todos os Pacotes após o consumo de 1GB, a TIM poderá, a seu exclusivo critério, reduzir a velocidade até o período de faturamento subseqüente.

Atenciosamente,      
Maria Ester
Central de Relacionamento com Clientes  
www.tim.com.br                                                     
Por favor, não responda esta mensagem. Caso necessário, envie uma nova mensagem através de nosso site TIM.

================================================================================

Cliente - Consumidor
Nome: MARCIO WESLEY BORGES
CPF/CNPJ: XXXXXXXXXXXXX
Administrador de contrato: não
Telefone: 06182115400
E-Mail: marciowb[*]9mail.com
Estado: DF
Tipo: Informação
Assunto: Serviços Avançados

Anatel e Ministério Público

Cadê a Anatel nessas horas?! Cadê o ministério público? A realidade é que já faz tempo que estamos desamparados. No Brasil, falou em telecoms, bancos e consumidor, somente os dois primeiros exercem (e usurpam!!!) seus direitos. Vamos protestar!!

Ainda nesta semana, após o ministério público resolver trabalhar, a Claro foi condenada por não entregar o devido serviço 3G que se contrata.

Labels: , , ,

2009/11/07

Icefaces+Facelets: Customizing the basic html (XHTML) tags using a simple Render Kit extension

Alright, the life, at least my life, isn't easy. But after fourteen hours, finally, I know how to do a simple task: insert the xmlns attribute into the final code of the html tag generated by Icefaces+Facelets couple.

I know that are several ways to insert this attribute, but I just want to play it using the JSF Render Kit. I don't want to filter the stream, or output the tag, or anything else. The render kit should be the way.

I just want to write:
   1:<?xml version='1.0' encoding='UTF-8' ?> 
   2:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   3:<html xmlns="http://www.w3.org/1999/xhtml"
   4:      xmlns:ui="http://java.sun.com/jsf/facelets"
   5:      xmlns:c="http://java.sun.com/jstl/core"
   6:      xmlns:h="http://java.sun.com/jsf/html"
   7:      xmlns:ice="http://www.icesoft.com/icefaces/component"
   8:      >
   9:    <body>
  10:
  11:        <ui:composition template="/WEB-INF/tmp/template.xhtml">
  12:
  13:            <ui:param name="hasLeftSection" value="false"/>
  14:            <ui:param name="pageDescription" value="${ArtistPage.pageDescription}"/>
  15:
  16:            <ui:define name="pageTitle">${ArtistPage.pageTitle}</ui:define>
  17:            <ui:define name="extraHeader">
  18:                <link rel="canonical" href="${ArtistPage.canonicalUrl}" />
  19:            </ui:define>
  20:
  21:            <ui:define name="body">
But the xmlns="http://www.w3.org/1999/xhtml" attribute is always trimmed by icefaces/facelets (maybe it's a simple thing to configure using com.icesoft.faces.facelets.D2DFaceletViewHandler or com.sun.facelets.compiler.Compiler - But I didn't investigate them to know).

I inspected the Icefaces code and I saw that it uses the renderer from com.icesoft.faces.renderkit.dom_html_basic.XMLRenderer to write out (to render) the most xhtml tags, like html, body, head, title etc. So, after a little test, was easy to write my own render to add the attribute that I need (or any other, also). The render code is:

   1:package com.solvoj.sondaletra.faces;
   2:
   3:import com.icesoft.faces.component.UIXhtmlComponent;
   4:import com.icesoft.faces.renderkit.dom_html_basic.XMLRenderer;
   5:import java.io.IOException;
   6:import java.util.Iterator;
   7:import java.util.Map;
   8:import javax.faces.component.UIComponent;
   9:import javax.faces.context.FacesContext;
  10:import javax.faces.context.ResponseWriter;
  11:
  12:/**
  13: * 
  14: * @author Marcio Wesley Borges
  15: */
  16:public class MyXMLRenderer extends XMLRenderer {
  17:
  18:    @Override
  19:    public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {
  20:        final UIXhtmlComponent xhtmlComponent = (UIXhtmlComponent) uiComponent;
  21:        final ResponseWriter writer = facesContext.getResponseWriter();
  22:        final String tag = xhtmlComponent.getTag();
  23:        writer.startElement(tag, xhtmlComponent);
  24:
25: if ("html".equals(tag)) { 26: writer.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml", null); 27: }
28: 29: final Iterator attributeIterator = xhtmlComponent.getTagAttributes().entrySet().iterator(); 30: while (attributeIterator.hasNext()) { 31: Map.Entry attribute = (Map.Entry) attributeIterator.next(); 32: writer.writeAttribute((String) attribute.getKey(), attribute.getValue(), null); 33: } 34: } 35: 36:} 37:
Also, we need to configure the application to use this render above while Icefaces will be playing with xhtml tags, so just add the following lines at the faces-config.xml file of your web application:
   1:<?xml version='1.0' encoding='UTF-8'?>
   2:<faces-config version="1.2"  xmlns="http://java.sun.com/xml/ns/javaee"
   3:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
   4:    <application>
   5:        <locale-config>
   6:            <default-locale>pt_BR</default-locale>
   7:            <supported-locale>pt_BR</supported-locale>
   8:            <supported-locale>en</supported-locale>
   9:        </locale-config>
  10:        <message-bundle>com.solvoj.sondaletra.web.Bundle</message-bundle>
  11:        <view-handler>com.icesoft.faces.facelets.D2DFaceletViewHandler</view-handler>
  12:    </application>
13: <render-kit> 14: <render-kit-id>ICEfacesRenderKit</render-kit-id> 15: <render-kit-class>com.icesoft.faces.renderkit.D2DRenderKit</render-kit-class> 16: <renderer> 17: <component-family>com.icesoft.faces.XhtmlComponent</component-family> 18: <renderer-type>com.icesoft.domXhtml</renderer-type> 19: <renderer-class>com.solvoj.sondaletra.faces.MyXMLRenderer</renderer-class> 20: </renderer> 21: <renderer> 22: <component-family>com.icesoft.faces.XhtmlComponent</component-family> 23: <renderer-type>com.icesoft.faces.Xhtml</renderer-type> 24: <renderer-class>com.solvoj.sondaletra.faces.MyXMLRenderer</renderer-class> 25: </renderer> 26: </render-kit>
It's enough to produce the resultant html page that I expect:
   1:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2:<html id="document:html" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
   3:<head>
The same principe can be used to add or change any attribute that you need to any xhtml tag using Icefaces/Facelets.

Labels: , , , , , ,

2009/04/04

woodstock.xhr.post: Do you see Google? See?!

How to post a JSON data via woodstock.xhr.post?

Woodstock Festival

Sometimes simple things may be hard to do... but I'm one of 'the last Woodstock survives
- No, I wasn't at Woodstock Festival - but, I wanted to.

I learned the Woodstock JSF Components (now officially abandoned by Sun) and I'm using it in at least two projects. Damn! I love Dojo! And Woodstock was all built with Dojo. But, now, after a long time learning (reading, trying, testing, experiencing and going mad), after finally to know what and how to do with Woodstock, the project was buried. I'm desolated!

I did a good work using Woodstock, but now I should migrate to Icefaces (acording Sun), but I don't want and I can't rewrite all my work to another technology.

Several troubles I had using Woodstock and nearly ten times, several troubles I solved with it.

AJAX using Woodstock

When I need to use AJAX with Woodstock pages, I don't use Dynafaces. Instead, I used submit or refresh standard Woodstock component feature to do a postback or I use AJAX request with servlet.

To do a AJAX request using the methdo GET is easy and well documented by Woodstock. Bellow, see example showing how to get customer data via AJAX using only the first and last customer names:

   1:function getCustomerByNames(lastName, firstName) {
   2:    var props = {
   3:        async: true,
   4:
   5:        onError: function(xhr) {
   6:            window.alert("An error occurs while sending an AJAX request. See: " + xhr)
   7:        },
   8:
   9:        onReady: function(xhr) {
  10:            var resp = eval('(' + xhr.responseText + ')');
  11:            window.alert("Customer is " + resp.name + " <" + resp.email + ">");  
  12:        },
  13:
  14:        url: "/AjaxBridge?a=Customer&t=getCustomerByCode"
  15:    };
  16:
  17:    props.url += "&lastName=" + lastName;
  18:    props.url += "&firstName=" + firstName;
  19:
  20:    woodstock.xhr.get(props);
  21:}
  22:

From the server-side, each AJAX "Agent" is a subclass of:

   1:package br.com.trilha21.web.store.ajax;
   2:
   3:import java.io.IOException;
   4:import java.io.PrintWriter; 
   5:import java.lang.reflect.Method;
   6:import java.util.logging.Level;
   7:import java.util.logging.Logger;
   8:import javax.servlet.ServletException;
   9:import javax.servlet.http.HttpServletRequest;
  10:import javax.servlet.http.HttpServletResponse;
  11:import net.marciowb.poison.web.jsf.JSFUtil;
  12:import org.json.JSONException;
  13:import org.json.JSONObject;
  14:
  15:/**
  16: *
  17: * @author Marcio Wesley Borges
  18: */
  19:public class AjaxAgent {
  20:    private static final Logger logger = Logger.getLogger(AjaxAgent.class.getName());
  21:    
  22:    final String task;  
  23:    protected final HttpServletRequest request;
  24:    protected final HttpServletResponse response;
  25:    protected final JSONObject mainObj;
  26:    
  27:    protected AjaxAgent(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  28:        this.request = request;
  29:        this.response = response;
  30:        response.setBufferSize(16384);
  31:        task = getParam("t");
  32:        try {
  33:            mainObj = new JSONObject();        
  34:            mainObj.put("agent", getClass().getSimpleName());
  35:            mainObj.put("by", task);
  36:        } catch (JSONException ex) {
  37:            throw new ServletException(ex);
  38:        }
  39:    }
  40:    
  41:    public String getTask() {
  42:        return task;
  43:    }
  44:    
  45:    protected static JSONObject toJSONObject(Object bean) {
  46:        try {
  47:            return JSFUtil.buildJSONObject(bean);
  48:        } catch (Exception ex) {
  49:            logger.log(Level.SEVERE, null, ex);
  50:        }
  51:        return null;
  52:    }
  53:    
  54:    private void outputJson() throws IOException, JSONException {
  55:        response.setContentType("text/json;charset=UTF-8");
  56:        response.setHeader("Cache-Control", "no-cache");        
  57:        final PrintWriter writer = response.getWriter();
  58:        writer.print(mainObj.toString());
  59:        writer.close();
  60:    } 
  61:    
  62:    protected String getParam(String name) {
  63:        return request.getParameter(name);
  64:    }
  65:
  66:    protected Long getParamAsLong(String name) {
  67:        final String p = getParam(name);
  68:        return Long.valueOf(p);
  69:    }
  70:
  71:    public final void exec() throws ServletException, IOException {
  72:        try {
  73:            final Method m = getClass().getMethod(task);
  74:            
  75:            m.invoke(this);
  76:            outputJson();
  77:        } catch (NoSuchMethodException ex) {
  78:            response.sendError( HttpServletResponse.SC_NOT_IMPLEMENTED );
  79:        } catch (Exception ex) {
  80:            logger.log(Level.SEVERE, "Error while executing an AJAX request.", ex);
  81:            response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.toString() );
  82:        }
  83:    }
  84:
  85:}
  86:

The servlet to attend AJAX request is like:

   1:package br.com.trilha21.web.store.ajax;
   2:
   3:import java.io.IOException;
   4:import java.lang.reflect.Constructor;
   5:import java.util.Map;
   6:import java.util.WeakHashMap;
   7:import java.util.logging.Level;
   8:import java.util.logging.Logger;
   9:import javax.servlet.ServletException;
  10:import javax.servlet.http.HttpServlet;
  11:import javax.servlet.http.HttpServletRequest;
  12:import javax.servlet.http.HttpServletResponse;
  13:
  14:/**
  15: * @author Marcio Wesley Borges
  16: */
  17:public class AjaxBridgeServlet extends HttpServlet {
  18:    private static final Logger logger = Logger.getLogger(AjaxBridgeServlet.class.getName());
  19:    
  20:    private static final String PCKG = AjaxBridgeServlet.class.getPackage().getName() + ".agents.";
  21:    private static final Map<String, Class<? extends AjaxAgent>> agents = new WeakHashMap<String, Class<? extends AjaxAgent>>();
  22:
  23:    private static final String AGENT_NAME_SUFIX = "Agent";
  24:   
  25:    private <T extends AjaxAgent> Class<T> getAgent(String agentName) {
  26:        if (!agentName.endsWith(AGENT_NAME_SUFIX))
  27:            agentName+=AGENT_NAME_SUFIX;
  28:
  29:        Class<T> agentClass = (Class<T>)agents.get(agentName);
  30:        if (agentClass==null) {
  31:            try {
  32:                agentClass = (Class<T>) Class.forName( PCKG + agentName );
  33:            } catch (ClassNotFoundException ex) {
  34:                return null;
  35:            }
  36:            agents.put(agentName, agentClass);
  37:        }
  38:        return agentClass;
  39:    }
  40:    
  41:    /** 
  42:    * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
  43:    * @param request servlet request
  44:    * @param response servlet response
  45:    */
  46:    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  47:    throws ServletException, IOException {
  48:        try {
  49://        response.setContentType("text/html;charset=UTF-8");
  50:            final String agentName = request.getParameter("a");
  51:            final Class<? extends AjaxAgent> agentClass = getAgent(agentName);
  52:            if (agentClass == null) {
  53:                response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
  54:                return;
  55:            }
  56:
  57:            final Constructor agentConstructor = agentClass.getConstructors()[0];
  58:            final AjaxAgent agent = (AjaxAgent)agentConstructor.newInstance(request, response);
  59:            agent.exec();
  60:            return;
  61:            
  62:        } catch (Throwable ex) {
  63:            logger.log(Level.SEVERE, "Error in AjaxBridgeServlet while processing the request: " + request, ex);
  64:        }
  65:        
  66:        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
  67:    } 
  68:
  69:    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
  70:    /** 
  71:    * Handles the HTTP <code>GET</code> method.
  72:    * @param request servlet request
  73:    * @param response servlet response
  74:    */
  75:    protected void doGet(HttpServletRequest request, HttpServletResponse response)
  76:    throws ServletException, IOException {
  77:        processRequest(request, response);
  78:    } 
  79:
  80:    /** 
  81:    * Handles the HTTP <code>POST</code> method.
  82:    * @param request servlet request
  83:    * @param response servlet response
  84:    */
  85:    protected void doPost(HttpServletRequest request, HttpServletResponse response)
  86:    throws ServletException, IOException {
  87:        processRequest(request, response);
  88:    }
  89:
  90:    /** 
  91:    * Returns a short description of the servlet.
  92:    */
  93:    public String getServletInfo() {
  94:        return "Short description";
  95:    }// </editor-fold>
  96:
  97:}
  98:

And, finally, the implementantion of the AJAX Agent (who is attending the AJAX requests) is like:

   1:package br.com.trilha21.web.store.ajax.agents;
   2:
   3:import br.com.trilha21.web.store.ajax.AjaxAgent;
   4:import br.com.trilha21.web.store.dao.Customer;
   5:import br.com.trilha21.web.store.ejb.CustomerLocal;
   6:import java.io.IOException;
   7:import javax.servlet.ServletException;
   8:import javax.servlet.http.HttpServletRequest;
   9:import javax.servlet.http.HttpServletResponse;
  10:import net.marciowb.poison.ejb.EJBUtil;
  11:import org.json.JSONException;
  12:
  13:/** 
  14: * @author Marcio Wesley Borges
  15: */
  16:public final class CustomerAgent extends AjaxAgent {
  17:    
  18:    final CustomerLocal customerBean = EJBUtil.lookupLocalBean(CustomerLocal.class);
  19:    
  20:    public CustomerAgent(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  21:        super(request,response);
  22:    }
  23:    
  24:    public void getCustomerByDoc() throws ServletException, IOException, JSONException {
  25:        final String customerDoc = getParam("customerDoc");
  26:        
  27:        final Customer customer = customerBean.get(customerDoc);
  28:        mainObj.put("customer", toJSONObject(customer));
  29:    }
  30:    
  31:    public void getCustomerByNames() throws ServletException, IOException, JSONException {
  32:        final String last = getParam("lastName");
  33:        final String first = getParam("firstName");
  34:        
  35:        final Customer customer = customerBean.getCustomerByNames(last,first);
  36:        mainObj.put("customer", toJSONObject(customer));
  37:    }
  38:}
  39:

The code above, works to HTTP requests (via GET method), but it doesn't works to post data (via POST method). To post data using woodstock.xhr, you must use woodstock.xhr.post instead of woodstock.xhr.get

Posting: woodstock.xhr.post

After quickly googling for "woodstock.xhr.post", I cried, 'cause nothing was returned! So, how to post (and recover) data via "woodstock.xhr.post" stuff?

Seeing the woodstock JS documentation, you will find the mention to the parameter content. All post data must be 'posted' via this parameter. So, the idea to pass complex data (as objects with several kinds of properties) is to encode the data in client side and decode in server side. As example, you can pass a object using JSON and decoding it using Java JSON library at server side.

Bellow you see (Object.toJSON is a Prototype utility method) the equivalent post data of the previous client side code supplied:

   1:function getCustomerByNames(lastName, firstName) {
   2:    var props = {
   3:        async: true,
   4:
   5:        onError: function(xhr) {
   6:            window.alert("An error occurs while sending an AJAX request. See: " + xhr)
   7:        },
   8:
   9:        onReady: function(xhr) {
  10:            var resp = eval('(' + xhr.responseText + ')');
  11:            window.alert("Customer is " + resp.name + " <" + resp.email + ">");  
  12:        },
  13:
  14:        url: "/AjaxBridge?a=Customer&t=getCustomerByCode",
15: content: Object.toJSON({ 16: 'lastName': lastName, 17: 'firstName': firstName 18: })
19: }; 20: 21: woodstock.xhr.post(props); 22:} 23:

To read the content parameter passed above in the servlet, you can do:

   1:public final class CustomerAgent extends AjaxAgent {
   2:    
   3:    final CustomerLocal customerBean = EJBUtil.lookupLocalBean(CustomerLocal.class);
   4:    
   5:    public CustomerAgent(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   6:        super(request,response);
   7:    }
   8:    
   9:    public void getCustomerByDoc() throws ServletException, IOException, JSONException {
  10:        final String customerDoc = getParam("customerDoc");
  11:        
  12:        final Customer customer = customerBean.get(customerDoc);
  13:        mainObj.put("customer", toJSONObject(customer));
  14:    }
  15:
16: public void getCustomerByNames() throws ServletException, IOException, JSONException { 17: final String data = IOUtil.readText(request.getInputStream());//Reads the 'content' parameter - it's equivalent to the post body. 18: final JSONObject json = new JSONObject(data); 19: final String lastName = json.getString("lastName"); 20: final String firstName = json.getString("firstName"); 21: final Customer customer = customerBean.getCustomerByNames(lastName,firstName); 22: mainObj.put("customer", toJSONObject(customer)); 23: }
24:} 25:

Good Icefaces look! I'll still with Woodstock for now.

Labels: , , ,