Página 1 de 1

Montando um construtor

MensagemEnviado: 28 Nov 2008 13:25
por jeanfernandes
To tentando entender os conceitos apresentados por um doido ae...

to com problema em definir
rtc_release(), para tornar ptr = null (resolvido) e assim garantir a reinicializacao de rtc na proxima chamada rtc_get
e em como melhorar a definicao de acesso aos membros da estrutura
(talvez um esquema mais poderoso de ponteiro pra funcao)...

eu nao sei se o uso de defines para acesso as variaveis é a melhor
maneira...se tem outras tecnicas de acesso a funcoes via ponteiro pra funcao, essas coisas... ajuda ae.. hehehehehe

algumas coisas precisam ser acrescentadas no modulo ou mesmo na mudanca dos defines para evitar por exemplo de voce ter que fazer varios acessos ao device para alterar um valor. Nao sei ate que ponto preciso pensar nisso...

e por ae vai...

Código: Selecionar todos
// Includes
#include <stdio.h>
#include <stdlib.h>

// Defines de acesso (macros)
// escrita
#define      rtc_set_dia(x)      rtc(RTC_READ)->dia = x
#define      rtc_set_mes(x)      rtc(RTC_READ)->mes = x
#define      rtc_set_ano(x)      rtc(RTC_READ)->ano = x
#define      rtc_set_hor(x)      rtc(RTC_READ)->hor = x
#define      rtc_set_min(x)      rtc(RTC_READ)->min = x
#define      rtc_set_seg(x)      rtc(RTC_READ)->seg = x
#define      rtc_set_dds(x)      rtc(RTC_READ)->dds = x

// leitura
#define      rtc_set_data(d,m,a)       rtc_set_dia(d); rtc_set_mes(m); rtc_set_ano(a)
#define      rtc_set_horario(h,m,s)    rtc_set_hor(h); rtc_set_min(m); rtc_set_seg(s)
#define   rtc_valor()         *rtc(RTC_READ)
#define      rtc_get_dia()       rtc(RTC_READ)->dia
#define      rtc_get_mes()       rtc(RTC_READ)->mes
#define      rtc_get_ano()       rtc(RTC_READ)->ano
#define      rtc_get_hor()       rtc(RTC_READ)->hor
#define      rtc_get_min()       rtc(RTC_READ)->min
#define      rtc_get_seg()       rtc(RTC_READ)->seg
#define      rtc_get_dds()       rtc(RTC_READ)->dds

#define      rtc_release()         rtc(RTC_RELEASE)

// Typedefs
typedef unsigned char       u08;
typedef unsigned short      u16;
typedef unsigned int        u32;

// Constantes
enum rtc_estado {RTC_READ, RTC_WRITE, RTC_RELEASE, RTC_LOCAL};

// Estruturas de dados
typedef struct {
   u08 dia;
   u08 mes;
   u08 ano;
   u08 hor;
   u08 min;
   u08 seg;
   u08 dds;
   
} st_rtc;


// leitura, inicializacao e release
st_rtc *
rtc(u08 modo)
{
   // inicializacao das variáveis
  static st_rtc rtc, *ptr = NULL;
   if (ptr == NULL)
   {
         // acesso ao device
      // iniciar as variaveis do rtc
      ptr             = &rtc;
      ptr->dia      = 1;
      ptr->mes      = 2;
      ptr->ano      = 3;
      ptr->hor      = 4;
      ptr->min      = 5;
      ptr->seg      = 6;
      ptr->dds      = 7;
   }
   
   switch (modo)
   {
      case RTC_LOCAL:
         // iniciar variaveis locais de outros modulos :)
         break;
     case RTC_READ:
         // leitura do device
         break;
     case RTC_WRITE:
         // escrita no device
         break;
     case RTC_RELEASE:
         ptr = NULL;
         break;
   }

   
   return ptr;
   
}

// atualizar tudo - falta terminar a read
void
rtc_set(st_rtc * valor)
{
   *(rtc(RTC_READ)) = *valor;
}

// aplicativo de testes
int
main(int argc, char *argv[])
{
   // usando como variavel local
  st_rtc valor;
   // iniciando a bagaca;
   
//   *((st_rtc *) &valor) = *rtc(); // exdruxulo mais funciona kkkkkkkk
  valor = rtc_valor(); // atribuindo a valor o conteudo de rtc

  printf("valor - variavel local\n");
  printf("dia = %u\n", valor.dia);
  printf("mes = %u\n", valor.mes);
  printf("ano = %u\n", valor.ano);
  printf("hor = %u\n", valor.hor);
  printf("min = %u\n", valor.min);
  printf("seg = %u\n", valor.seg);
  printf("dds = %u\n", valor.dds);
   
   rtc_set_data(11,12,13);
   rtc_set_horario(14,15,16);
   
  valor = rtc_valor(); // atribuindo a valor o conteudo de rtc

  printf("valor - variavel local\n");
  printf("dia = %u\n", valor.dia);
  printf("mes = %u\n", valor.mes);
  printf("ano = %u\n", valor.ano);
  printf("hor = %u\n", valor.hor);
  printf("min = %u\n", valor.min);
  printf("seg = %u\n", valor.seg);
  printf("dds = %u\n", valor.dds);

  rtc_release();
   
  valor = rtc_valor(); // atribuindo a valor o conteudo de rtc

  printf("valor - variavel local\n");
  printf("dia = %u\n", valor.dia);
  printf("mes = %u\n", valor.mes);
  printf("ano = %u\n", valor.ano);
  printf("hor = %u\n", valor.hor);
  printf("min = %u\n", valor.min);
  printf("seg = %u\n", valor.seg);
  printf("dds = %u\n", valor.dds);
   
   
  system("PAUSE");
   
  return 0;
}

// fim de arquivo




Com a palavra oces e o doido hehehehe

MensagemEnviado: 01 Dez 2008 06:40
por joao
Aparentemente eu acho que está certa, mas deixa eu dar apenas umas pinceladas em algumas coisas. :)

Nesta linha:
Código: Selecionar todos
   // inicializacao das variáveis
  static st_rtc rtc, *ptr = NULL;


Porque vc está passando o endereço de rtc para *ptr? Não pode passar direto rtc? Se for só por causa de zerar as variaveis, porque vc nao faz no case do RTC_RELEASE, o que vc está fazendo no IF (ptr == NULL) e dai faz um return NULL? Tudo isso dentro do SWITCH. Dai vc não teria este ponteiro a mais.

Outra coisa, Vc sempre chama esta função passando as opções do SWITCH? Se sim, vc deve criar a opção default nele, retornando como resultado, error. Dai vc sabe que na verdade, a sua função não está recebendo corretamente estes defines. Também


é isso.

[]'s

MensagemEnviado: 01 Dez 2008 08:32
por jeanfernandes
Joao

Ta eu deixo de usar o ponteiro e retorno sempre o endereco da funcao...
beleza..

fico pensando chefe, se a coisa crescer internamente em complexidade...
como falei...nao da pra ser pragmatico com coisas simples, quando se quer chegar a um padrao. pode parecer estranho agora, mas la na frente quem sabe se a filosofia de retorno por ptr nao acaba sendo a solucao.

MensagemEnviado: 01 Dez 2008 09:07
por joao
Hmmmm,

Só para deixar claro. Estamos falando em retornar o endereço da estrutura chamada rtc, certo?

Se vc fizer o teu switch assim:
Código: Selecionar todos
 switch (modo)
   {
      case RTC_LOCAL:
         // iniciar variaveis locais de outros modulos :)
         break;
     case RTC_READ:
         return ptr; //vc só precisa retornar aqui.
         // leitura do device
         break;
     case RTC_WRITE:
         // escrita no device
         break;
     case RTC_RELEASE:
            ptr->dia      = 1;
            ptr->mes      = 2;
            ptr->ano      = 3;
            ptr->hor      = 4;
            ptr->min      = 5;
            ptr->seg      = 6;
            ptr->dds      = 7;
            return OK; //Aqui vc cria um define com valor 0;

     case default:
            return -1;  //Cria um define ERROR que é melhor do que enviar -1, claro que vc precisa fazer um cast aqui.
   }
   
    return OK; //Aqui vc retorna 0;




Agora, relendo novamente o seu código, continuo com mais algumas perguntas e sugestoes:

1 - Vc poderia mudar o nome da VARIAVEL rtc que está dentro da FUNCAO rtc para outro nome. (rtc_local por exemplo?) fica menos complicado em entender.


2 - Existem dois defines de set na parte de leitura(rtc_set_data e rtc_set_horario), acho interessante vc arrumar isso para ficar mais facil de entender.

3 - Os teus defines de set estão usando o READ, apenas porque vc está retornando o ponteiro, logo vc não está usando o WRITE. Por isso, quem sabe seria interessante vc mudar de RTC_READ para RTC_POINTER

4 - Eu prefiro sempre usar CAPSLOCK quando uso defines, independente se é apenas defines ou macros. Fica mais fácil de ver no código que o que vc procura na verdade é apenas 1 linha e não uma função, por exemplo.

5 - Ultima! :) Eu faria uma função rtc() que tivesse dois parametros. Um seria o que deveria ser feito(READ, WRITE, RELEASE) e o segundo parametro poderia ser: retorno, no caso de READ ou os novos valores no caso de WRITE. Neste caso, o retorno da função seria apenas bool, para saber se deu certo ou não. Mas isso não muda em nada o que vc já fez, pois é apenas uma maneira diferente de programar.


PS: Eu to levando em consideração que vc está apenas fazendo a versão 0.0000001 de um futuro arquivo que a complexidade apenas os engenheiros da nasa irão entender. :)

[]'s

MensagemEnviado: 02 Dez 2008 20:44
por msamsoniuk
hehehe dah um zoio neste soft-rtc "bombadao" jean:

Código: Selecionar todos
void rtc_task()
{
  static unsigned timestamp=0;
  struct ipc_msg *msg;

  msg = ipc_recv();
  if(msg)
  {
    switch(msg->state)
    {
      case STATE_START:
        TBR0    = 0;
        TBR1    = 0;
        TBR2    = 0;
        TBON    = 1;
        TBIE    = 1;
        break;

      case STATE_EXPIRE:
        PTA0++;
        timestamp++;
        break;

      case STATE_READ:
        *((unsigned *)msg->buffer) = timestamp;
        msg->length = 2;
        break;

      case STATE_STOP:
        TBON    = 0;
        TBIE    = 0;
        break;
    }
  }
}


nao me prendi muito aos detalhes operacionais, estou soh retornando um timestamp para escala de 1/100 de segundo. enfim, eh uma taskzinha simples, que soh inicia um periferico e espera mensagens. ela eh criada e escalonada por um processo main()

Código: Selecionar todos
void main()
{
  struct ipc_msg msg;

  wdt_disable();
  pta_enable();

  msg.to    = rtc_task;
  msg.state = STATE_START;
  ipc_send(&msg);

  isr_enable();
  wdt_enable();

  for(;;)
  {
    wdt_clear();
    PTA1++;

    if(ipc_queue)
    {
      ipc_queue->to();
    }
    isr_wait();
  }
}


na primeira parte eh mudado o estado da rtc_task para se inicializar (e portanto inicializar o periferico). na segunda parte ela tem um loop que espera por interrupcoes, limpa o watchdog e escalona processos conforme existam mensagens para eles no topo da queue.

no caso, o sistema se mexe pq tem um modulo TBM configurado gerando interrucpcoes de 305Hz. a cada interrupcao um contador master decrementa e, chegando a um certo valor, eh gerada uma interrupcao. a minha ideia eh configurar aqui a base de tempo do sistema, no caso em torno de 100Hz:

Código: Selecionar todos
void rtc_isr(void) interrupt 17
{
  static unsigned rtc_count = 0;
  static struct ipc_msg rtc_msg;

  TACK = 1;

  if(!rtc_count)
  {
    rtc_count     = 3;
    rtc_msg.to    = rtc_task;
    rtc_msg.state = STATE_EXPIRE;
    ipc_send(&rtc_msg);
  }
  rtc_count--;
}


bom, precisa de um ajuste fino extra para cravar os 100Hz, mas enfim... a ideia eh atender a interrupcao rapidamente, tratar o codigo que gera os 100Hz e enviar a mensagem se for o caso. como caiu numa interrupcao, ele abre o loop lah em main e, como tem mensagem na queue, o rtc_task eh escalado. ele recebe a mensagem e processa, incrementando o contador de timestamp e piscando um led, que eu checo aqui com um frequencimetro :)

tem o codigo da queue de mensagens, mas eh simples. para otimizar, nao fiz uma fifo, fiz uma stack (lifo). em termos praticos, eu consigo testar a queue mais de 70 mil vezes por segundo em um HC908 com core rodando a 2.5MHz.

tamanho da brincadeira em linhas de codigo:

Código: Selecionar todos
   52 ipc.c
   59 main.c
   96 rtc.c
   59 ipc.h
   40 rtc.h
   51 rtos.h
  357 total


e em codigo gerado:

Código: Selecionar todos
Direct Internal RAM:
   Name             Start    End      Size     Max
   ---------------- -------- -------- -------- --------
   REG_BANK_0       0x00                  0        0
   REG_BANK_1       0x00                  0        0
   REG_BANK_2       0x00                  0        0
   REG_BANK_3       0x00                  0        0
   BSEG_BYTES       0x00                  0        0
   DATA             0x40     0x45         6      256
   ---------------- -------- -------- -------- --------
   TOTAL:           0x00     0x45         6      256

Stack starts at: 0xff (sp set to 0xfe)
Other memory:
   Name             Start    End      Size     Max
   ---------------- -------- -------- -------- --------
   INDIRECT RAM     0xff                  0        0
   EXTERNAL RAM     0x0044   0x0063      32    65536
   ROM/EPROM/FLASH  0xee00   0xefb2     435    65536


bom, isso para rodar em um mcu de 2.5MHz, 4MB de flash e 384 bytes de ram. ateh que tah sobrando espaco! para quem nao entende grego ainda, o codigo consome 38 bytes de ram e 435 bytes de flash.

proximo passo eh tentar fazer um ping-pong de mensagens para ver como o bicho vai e tentar botar uma uart_task no ar hehehe