

#include "signal.h"
#include "board.h"
#include "stdlib.h"
#include "stdio.h"
#include "debug.h"






typedef struct{
  void *mutex;
  signal_list *head;
}self_def;


static self_def g_self;



int signal_init(void)
{
  self_def *s=&g_self;
  if(s->mutex==0)
  {
    s->mutex=rt_mutex_create("signal_",RT_IPC_FLAG_FIFO);
  }
  return 0;
}







// static void cpy4byte(uint32_t *dst,uint32_t *src,int num_4byte)
// {
//   for(int i=0;i<num_4byte;i++)
//   {
//     dst[i]=src[i];
//   }
// }




#define SLOT_FUN_RUN(fun,param) \
  ((slot_fun_def)(fun))(param[0],param[1],param[2],\
    param[3],param[4],param[5],param[6],param[7])

typedef void (*slot_fun_def)(uint32_t a,uint32_t b,uint32_t c,uint32_t d,uint32_t e,uint32_t f,uint32_t g,uint32_t h);

static void slot_run(void *t)
{
  param_check(t);
  slot_run_def *s=t;
  int msg_size=sizeof(slot_msg_def)+sizeof(uint32_t)*8;
  slot_msg_def *msg=calloc(1,msg_size);
  while(s->run)
  {
    rt_mq_recv(s->mb,msg,msg_size,RT_WAITING_FOREVER);
    SLOT_FUN_RUN(msg->fun,msg->param);
  }
  free(msg);
}



// 创建一个线程
sig_thread thread_creat(int pro)
{
  static uint16_t count=0;
  char name[20]={0};
  slot_run_def *run=calloc(1,sizeof(slot_run_def));
  run->run=1;
  sprintf(name,"sig_mq#%d",count);
  run->mb=rt_mq_create(name,(sizeof(slot_msg_def)+sizeof(uint32_t)*8),30,RT_IPC_FLAG_FIFO);
  sprintf(name,"sig_t#%d",count);
  rt_thread_t rt_t=rt_thread_create(name,slot_run,run,1024,pro,20);
  rt_thread_startup(rt_t);
  count++;
  return run->mb;
}


void thread_delete(sig_thread t)
{
  // 删除线程需要删除与此线程相关的所有信号槽
  // 删除消息队列
  param_check(0);
}


// 如果这个类的信号已注册
static signal_list *find(void *sig_obj,void *signal_)
{
  self_def *s=&g_self;
  signal_list *l=s->head;
  while(l!=0)
  {
    if(l->signal_==signal_&&l->sig_obj==sig_obj)
      return l;
    l=l->next;
  }
  return 0;
}


int connect(void *sig_obj,void *signal_,sig_thread t,void *slot_obj,void *slot)
{
  self_def *s=&g_self;
  signal_def *sig;
  sig=signal_find(signal_);
  if(sig==0) return -1;
  rt_mutex_take(s->mutex,RT_WAITING_FOREVER);
  slot_list *slo=calloc(1,sizeof(slot_list));
  param_check(slo);
  slo->fun=slot;
  slo->mb=t;
  slo->next=0;
  slo->obj=slot_obj;
  signal_list *sig_l=find(sig_obj,signal_);

  if(sig_l==0){
    sig_l=calloc(1,sizeof(signal_list));
    param_check(sig_l);
    sig_l->signal_=signal_;
    sig_l->sig_obj=sig_obj;
    sig_l->next=s->head;
    s->head=sig_l;
  }
  slo->next=sig_l->head;
  sig_l->head=slo;
  //DBG_LOG("signal connect:%08x",slo);
  rt_mutex_release(s->mutex);
  return 0;
}



int disconnect(void *sig_obj,void *signal_,sig_thread t,void *slot_obj,void *slot)
{
  self_def *s=&g_self;
  signal_list *sig;
  sig=find(sig_obj,signal_);
  if(sig==0) return -1;
  int ret=-1;
  rt_mutex_take(s->mutex,RT_WAITING_FOREVER);
  slot_list *next=sig->head;
  slot_list *prev=0;
  while(next!=0)
  {
    if(next->fun==slot&&next->obj==slot_obj)
    {
      if(prev) prev->next=next->next;
      else sig->head=next->next;
      //DBG_LOG("signal disconnect:%08x",next);
      free(next);
      ret=0;
      break;
    }
    prev=next;
    next=next->next;
  }
  rt_mutex_release(s->mutex);
  return ret;
}


// 消除与指定对象相关的所有信号槽连接
int disconnect_sig(void *sig_obj)
{
  self_def *s=&g_self;
  rt_mutex_take(s->mutex,RT_WAITING_FOREVER);
  signal_list *sig=s->head;
  signal_list *prev_sig=0;
  while(sig!=0)
  {
    if(sig->sig_obj==sig_obj)
    {
      slot_list *next=sig->head;
      while(next!=0)
      {
        sig->head=next->next;
        free(next);
        next=sig->head;
      }
      if(prev_sig) prev_sig=sig->next;
      else s->head=sig->next;
      free(sig);
      break;
    }
    prev_sig=sig;
    sig=sig->next;
  }
  rt_mutex_release(s->mutex);
  return 0;
}


// 消除与指定对象相关的所有信号槽连接
int disconnect_slot(void *slot_obj)
{
  self_def *s=&g_self;
  rt_mutex_take(s->mutex,RT_WAITING_FOREVER);
  signal_list *sig=s->head;
  while(sig!=0)
  {
    slot_list *next=sig->head;
    slot_list *prev=0;
    while(next!=0)
    {
      if(next->obj==slot_obj)
      {
        if(prev) prev->next=next->next;
        else sig->head=next->next;
        free(next);
        break;
      }
      prev=next;
      next=next->next;
    }
    sig=sig->next;
  }
  rt_mutex_release(s->mutex);
  return 0;
}




signal_def *signal_find(void *signal_)
{
#if defined (__CC_ARM)  
  extern const int signalstruct$$Base;
  extern const int signalstruct$$Limit;
  signal_def *start=(signal_def *)&signalstruct$$Base;
  signal_def *end=(signal_def *)&signalstruct$$Limit;
#elif defined (__GNUC__)
  extern const int __start_signalstruct;
  extern const int __stop_signalstruct;
  signal_def *start=(signal_def *)&__start_signalstruct;
  signal_def *end=(signal_def *)&__stop_signalstruct;
#endif
  for(signal_def *t=start;t<end;t++)
  {
    if(t->signal_==signal_)
    {
      return t;
    }
  }
  return 0;
}


// 发送信号
int _signal_emit(void *sig_obj,void *signal_,uint32_t *param,int param_num)
{
  self_def *s=&g_self;
  signal_list *sig=find(sig_obj,signal_);
  if(sig==0) return -1;
  if(param_num>7) return -2;
  int size=sizeof(slot_msg_def)+sizeof(uint32_t)*(8);
  slot_msg_def *m=malloc(size);
  rt_mutex_take(s->mutex,RT_WAITING_FOREVER);
  slot_list *h=sig->head;
  m->param_num=param_num;
  m->src=signal_;
  while(h)
  {
    m->fun=h->fun;
    if(h->obj)
    {
      cpy4byte(m->param+1,param,param_num);
      m->param[0]=(uint32_t)h->obj;
    }else{
      cpy4byte(m->param,param,param_num);
    }
    if(h->mb){
      rt_mq_send(h->mb,m,size);
    }else{
      SLOT_FUN_RUN(m->fun,m->param);
    }
    h=h->next;
  }
  rt_mutex_release(s->mutex);
  free(m);
  return 0;
}










