583 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			583 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| 
 | |
| #ifdef RT_THREAD
 | |
| 
 | |
| 
 | |
| #include "stdio.h"
 | |
| #include "rtthread.h"
 | |
| #include "board.h"
 | |
| #include "mystdlib.h"
 | |
| #include "list.h"
 | |
| #include "mystring.h"
 | |
| #include "signal.h"
 | |
| #include "prot_mcu.h"
 | |
| #include "debug.h"
 | |
| #include "handle.h"
 | |
| #include "prot_uc.h"
 | |
| #include "transmit.h"
 | |
| #include "commend.h"
 | |
| #include "dev_flash.h"
 | |
| #include "mymisc.h"
 | |
| #include "dev_backup.h"
 | |
| #include "compiler_info.h"
 | |
| #include "moter.h"
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| int main()
 | |
| {
 | |
|   const sys_param_def *par=sys_param();
 | |
|   debug_init();
 | |
|   app_init();
 | |
|   
 | |
|   protu_def *protu=app_variable("protu",0,0);
 | |
|   protu_def *protu2=app_variable("protu2",0,0);
 | |
|   tran_def *tran=app_variable("tran",0,0);
 | |
|   void *cmd=app_variable("cmd",0,0);
 | |
|   
 | |
|   connect(protu,protu_recv_signal,0,tran,tran_recv_slot);
 | |
|   connect(tran,tran_reply_signal,0,protu,protu_reply_call);
 | |
|   connect(tran,tran_send_signal,0,protu,protu_send_call);
 | |
| 
 | |
|   connect(protu2,protu_recv_signal,0,cmd,cmd_recv_slot);
 | |
|   connect(cmd,cmd_reply_signal,0,protu2,protu_send_call);
 | |
|   
 | |
| //  DBG_LOG("询预压");
 | |
| //  DBG_LOG("我知道");
 | |
|   //--diag_suppress=550,177
 | |
| 
 | |
|   
 | |
|   while(1)
 | |
|   {
 | |
|     rt_thread_mdelay(5000);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int init_wdog(void)
 | |
| {
 | |
|   if(bk_wdog_fun())
 | |
|   {
 | |
|     rt_thread_idle_sethook((void (*)(void))bk_wdog_fun());
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| app_init_export(init_wdog)
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| static int test(list_def *argv)
 | |
| {
 | |
|   if(list_length(argv)<2){
 | |
|     cmd_print("param num too less.");
 | |
|     return -1;
 | |
|   }
 | |
|   int num=str_atoi(list_get_str(argv,1));
 | |
|   cmd_print("test num=%d,hex=%x",num,num);
 | |
|   return 0;
 | |
| }
 | |
| commend_export(test,test,"cmd test")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| static int scheme_info(list_def *argv)
 | |
| {
 | |
|   const scheme_def *s=check_scheme();
 | |
|   const scheme_task_def *t;
 | |
|   if(s->plan_id==0xffffffff){
 | |
|     cmd_print("scheme is empty.");
 | |
|     return -1;
 | |
|   }
 | |
|   cmd_print("plan id:       %d",s->plan_id);
 | |
|   cmd_print("timeout_m:     %d",s->timeout_m);
 | |
|   cmd_print("task num:      %d",s->task_num);
 | |
|   for(int i=0;i<s->task_num;i++)
 | |
|   {
 | |
|     t=&s->task[i];
 | |
|     cmd_print("  task:%02d  id:%02d  err:%02x",t->taskindex,t->taskid,t->err);
 | |
|     for(int j=0;j<t->item_num;j++)
 | |
|     {
 | |
|       cmd_print("    max:%5d, min:%5d err:%02x    %s",t->range[j].max,t->range[j].min,
 | |
|       t->err,
 | |
|       t->range[j].max<t->range[j].min?"err":"ok");
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| commend_export(scheme,scheme_info,"print scheme info")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| typedef struct{
 | |
|   int updata_run;
 | |
| }updata_def;
 | |
| static updata_def g_updata;
 | |
| static int updata_slave(list_def *argv)
 | |
| {
 | |
|   void *ptr=flash_get_slave();
 | |
|   tran_def *tran=app_variable("tran",0,0);
 | |
|   uint8_t *data=ptr;
 | |
|   data+=FLASH_FILE_HEAD_SIZE;
 | |
|   flash_file *file=ptr;
 | |
|   if(tran==0){
 | |
|     DBG_WARN("can not find variable \"tran\"");
 | |
|     return -1;
 | |
|   }
 | |
|   if(list_length(argv)<2){
 | |
|     cmd_print("param num too less.");
 | |
|     return -1;
 | |
|   }
 | |
|   list_def *addrs=str_atod_list(list_get_str(argv,1),',');
 | |
|   for(int i=0;i<list_length(addrs);i++)
 | |
|   {
 | |
|     int addr=list_get_int(addrs,i);
 | |
|     port_mcu *mcu=tran_get_portm(tran,addr-1);
 | |
|     if(mcu){
 | |
|       port_start(mcu,updata_creat(data,file->file_size));
 | |
|       g_updata.updata_run++;
 | |
|     }
 | |
|   }
 | |
|   cmd_print("start updata,addr=%s",str_temp(list_string(addrs)));
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static void cmd_end_slot(void *obj,port_mcu *src,void *data,int ack,char *err_str)
 | |
| {
 | |
|   updata_def *self=obj;
 | |
|   if(self->updata_run>0)
 | |
|   {
 | |
|     cmd_print("addr:%d %s",port_get_addr(src),err_str);
 | |
|     self->updata_run--;
 | |
|   }
 | |
| }
 | |
| // 挂载命令行槽函数
 | |
| static int cmd_slot_init(void)
 | |
| {
 | |
|   void *tr=app_variable("tran",0,0);
 | |
|   if(tr){
 | |
|     for(int i=0;i<20;i++){
 | |
|       port_mcu *mcu=tran_get_portm(tr,i);
 | |
|       // 连接操作结束信号
 | |
|       if(mcu)
 | |
|         connect(mcu,port_end_signal,0,&g_updata,cmd_end_slot);
 | |
|     }
 | |
|   }
 | |
|   else{
 | |
|     app_valid_call("tran",(void (*)(void *))cmd_slot_init,0);
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| app_init_export(cmd_slot_init);
 | |
| 
 | |
| 
 | |
| 
 | |
| commend_export(updatas,updata_slave,"updata slave")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| static int memused(list_def *argv)
 | |
| {
 | |
|   uint32_t used,total,max_used;
 | |
|   rt_memory_info(&total,&used,&max_used);
 | |
|   cmd_print("mem total=%d,used=%d,max_used=%d",total,used,max_used);
 | |
|   used=mem_perused();
 | |
|   cmd_print("mem used=%d.",used);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| commend_export(memused,memused,"print the mem use info")
 | |
| 
 | |
| 
 | |
| 
 | |
| static int reboot(list_def *argv)
 | |
| {
 | |
|   cmd_print("mcu will reboot later");  
 | |
|   later_execute((void (*)(void *))bk_reboot_app,0,50);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| commend_export(reboot,reboot,"reboot mcu")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| static int moter(list_def *argv)
 | |
| {
 | |
|   const sys_param_def *par=sys_param();
 | |
|   cmd_print("moter ctl");
 | |
|   if(list_length(argv)<3){
 | |
|     cmd_print("param num too less.");
 | |
|     return -1;
 | |
|   }
 | |
|   int fre=str_atoi(list_get_str(argv,1));
 | |
|   int count=str_atoi(list_get_str(argv,2));
 | |
|   moter_start(fre,count);
 | |
|   cmd_print("moter start,fre=%d,count=%d",fre,count);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| commend_export(moter,moter,"control moter up or down|use:moter [frequency] [count]")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| static void print_sys_param(const sys_param_def *par)
 | |
| {
 | |
|   cmd_print(" - - - - - - - - - - - - - - ");
 | |
|   cmd_print("pack time:         %s",par->pack_time);
 | |
|   cmd_print("host if:           %s",par->host_if);
 | |
|   cmd_print("device type:       %s",par->device_type);
 | |
|   cmd_print("mac addr:          %02x.%02x.%02x.%02x.%02x.%02x",
 | |
|     par->mac[0],par->mac[1],par->mac[2],par->mac[3],par->mac[4],par->mac[5]);
 | |
|   cmd_print("local ip:          %d.%d.%d.%d",
 | |
|     par->local_ip[0],par->local_ip[1],par->local_ip[2],par->local_ip[3]);
 | |
|   cmd_print("host ip:           %d.%d.%d.%d",
 | |
|     par->host_ip[0],par->host_ip[1],par->host_ip[2],par->host_ip[3]);
 | |
|   cmd_print("host port:         %d",par->host_port);
 | |
|   cmd_print("local cmd port:    %d",par->local_cmd_port);
 | |
|   cmd_print("host log port:     %d",par->host_log_port);
 | |
|   cmd_print("local id:          %d",par->local_id);
 | |
|   cmd_print("host log ip:       %d.%d.%d.%d",
 | |
|     par->host_log_ip[0],par->host_log_ip[1],par->host_log_ip[2],par->host_log_ip[3]);
 | |
|   cmd_print("uart bsp:          %d",par->uartbsp);
 | |
|   cmd_print("coder ret mode:    %d",par->coder_ret_mode);
 | |
|   cmd_print("slave_addr_start:  %d",par->slave_addr_start);
 | |
|   cmd_print("moter_max_count:   %d",par->moter_max_count);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int sysinfo(list_def *argv)
 | |
| {
 | |
|   const sys_param_def *par=sys_param();
 | |
|   cmd_print("build time:      %s",BUILD_DATE);
 | |
|   cmd_print("soft version:    %s",SOFT_VERSION);
 | |
|   cmd_print("run time:        %d",rt_tick_get()/1000);
 | |
|   cmd_print("startup:         %s",bk_get_currtype());
 | |
|   cmd_print("watch dog:       %s",bk_wdog_fun()?"on":"off");
 | |
|   cmd_print("reboot times:    %d",bk_reboot_times());
 | |
|   print_sys_param(par);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| commend_export(sysinfo,sysinfo,"print the software info")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| static void print_sys_help(void)
 | |
| {
 | |
|   cmd_print("example for how to set system params:");
 | |
|   cmd_print("set hostif                 uart4/utcp");
 | |
|   cmd_print("set devicetype             checker/coder");
 | |
|   cmd_print("set localip                192.168.80.10");
 | |
|   cmd_print("set hostip                 192.168.80.100");
 | |
|   cmd_print("set hostport               7777");
 | |
|   cmd_print("set localcmdport           7777");
 | |
|   cmd_print("set hostlogport            12345");
 | |
|   cmd_print("set localid                1");
 | |
|   cmd_print("set hostlogip              192.168.80.80");
 | |
|   cmd_print("set uartbsp                115200");
 | |
|   cmd_print("set codermode              1/0");
 | |
|   cmd_print("set slave_addr_start       1/0");
 | |
|   cmd_print("set moter_max_count        0~30000");
 | |
|   cmd_print("set save");
 | |
| }
 | |
| 
 | |
| static int sys_set(list_def *argv)
 | |
| {
 | |
|   static sys_param_def *spar=0;
 | |
|   if(spar==0){
 | |
|     spar=calloc(1,sizeof(sys_param_def));
 | |
|     memcpy(spar,sys_param(),sizeof(sys_param_def));
 | |
|   }
 | |
|   if(list_length(argv)<2){
 | |
|     cmd_print(" - - - -SET TEMP- - - - ");
 | |
|     print_sys_param(spar);
 | |
|     return 0;
 | |
|   }
 | |
|   if(strcmp(list_get_str(argv,1),"help")==0)
 | |
|   {
 | |
|     print_sys_help();
 | |
|     return 0;
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"save")==0)
 | |
|   {
 | |
|     cmd_print(" - - - -SET TEMP- - - - ");
 | |
|     print_sys_param(spar);
 | |
|     flash_save_param(spar);
 | |
|     cmd_print("param saved,device will reboot later.");
 | |
|     later_execute((void (*)(void *))bk_reboot_app,0,100);
 | |
|     return 0;
 | |
|   }else{
 | |
|     if(list_length(argv)<3){
 | |
|       cmd_print("param num too less.");
 | |
|       print_sys_help();
 | |
|       return -1;
 | |
|     }
 | |
|   }
 | |
|   if(strcmp(list_get_str(argv,1),"hostif")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     memcpy(spar->host_if,str,strlen(str)+1);
 | |
|     cmd_print("host if: %s",spar->host_if);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"devicetype")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     memcpy(spar->device_type,str,strlen(str)+1);
 | |
|     cmd_print("device type: %s",spar->device_type);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"localip")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     list_def *ip=str_atod_list(str,'.');
 | |
|     spar->local_ip[0]=list_get_int(ip,0);
 | |
|     spar->local_ip[1]=list_get_int(ip,1);
 | |
|     spar->local_ip[2]=list_get_int(ip,2);
 | |
|     spar->local_ip[3]=list_get_int(ip,3);
 | |
|     cmd_print("local ip:        %d.%d.%d.%d",
 | |
|       spar->local_ip[0],spar->local_ip[1],spar->local_ip[2],spar->local_ip[3]);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"hostip")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     list_def *ip=str_atod_list(str,'.');
 | |
|     spar->host_ip[0]=list_get_int(ip,0);
 | |
|     spar->host_ip[1]=list_get_int(ip,1);
 | |
|     spar->host_ip[2]=list_get_int(ip,2);
 | |
|     spar->host_ip[3]=list_get_int(ip,3);
 | |
|     cmd_print("host ip:        %d.%d.%d.%d",
 | |
|       spar->host_ip[0],spar->host_ip[1],spar->host_ip[2],spar->host_ip[3]);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"hostport")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->host_port=str_atoi(str);
 | |
|     cmd_print("host port:       %d",spar->host_port);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"localcmdport")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->local_cmd_port=str_atoi(str);
 | |
|     cmd_print("local cmd port:  %d",spar->local_cmd_port);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"hostlogport")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->host_log_port=str_atoi(str);
 | |
|     cmd_print("local log port:  %d",spar->host_log_port);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"localid")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->local_id=str_atoi(str);
 | |
|     cmd_print("local id:        %d",spar->local_id);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"uartbsp")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->uartbsp=str_atoi(str);
 | |
|     cmd_print("uart bsp:        %d",spar->uartbsp);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"hostlogip")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     list_def *ip=str_atod_list(str,'.');
 | |
|     spar->host_log_ip[0]=list_get_int(ip,0);
 | |
|     spar->host_log_ip[1]=list_get_int(ip,1);
 | |
|     spar->host_log_ip[2]=list_get_int(ip,2);
 | |
|     spar->host_log_ip[3]=list_get_int(ip,3);
 | |
|     cmd_print("host log ip:        %d.%d.%d.%d",
 | |
|       spar->host_log_ip[0],spar->host_log_ip[1],spar->host_log_ip[2],spar->host_log_ip[3]);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"codermode")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->coder_ret_mode=str_atoi(str);
 | |
|     cmd_print("coder ret mode:        %d",spar->coder_ret_mode);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"slave_addr_start")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->slave_addr_start=str_atoi(str);
 | |
|     cmd_print("slave addr start:        %d",spar->slave_addr_start);
 | |
|   }
 | |
|   else if(strcmp(list_get_str(argv,1),"moter_max_count")==0)
 | |
|   {
 | |
|     char *str=list_get_str(argv,2);
 | |
|     spar->moter_max_count=str_atoi(str);
 | |
|     cmd_print("moter_max_count:        %d",spar->moter_max_count);
 | |
|   }
 | |
|   else{
 | |
|     cmd_print("unknown cmd for sysset.");
 | |
|     print_sys_help();
 | |
|     return -1;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| commend_export(set,sys_set,"set the system params")
 | |
| 
 | |
| 
 | |
| 
 | |
| #else
 | |
| 
 | |
| 
 | |
| #include "board.h"
 | |
| #include "dev_flash.h"
 | |
| #include "dev_backup.h"
 | |
| #include "crc.h"
 | |
| #include "dev_watchdog.h"
 | |
| #include "string.h"
 | |
| 
 | |
| #define APP_ADDR 0x08004000
 | |
| 
 | |
| void __set_msp(uint32_t addr);
 | |
| typedef void (*app)(void);
 | |
| void app_run(void)
 | |
| {
 | |
|   app app_fun;
 | |
|   if(((*(volatile uint32_t*)APP_ADDR)&0x2FFE0000)==0x20000000)
 | |
|   {
 | |
| //    wdog_start();
 | |
| //    bk_set_wdog_fun(wdog_refresh);
 | |
|     app_fun=(app)*(volatile uint32_t*)(APP_ADDR+4);
 | |
|     __set_msp(*(volatile uint32_t*)APP_ADDR);
 | |
|     app_fun();
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void param_init(rom_head *h);
 | |
| void app_updata(void);
 | |
| int main()
 | |
| {
 | |
|   uint32_t boot_type=bk_get_boottype();
 | |
|   bk_init();
 | |
|   switch(boot_type){
 | |
|     // 重启并升级
 | |
|     case REBOOT_APP_TO_BOOT:
 | |
|     {
 | |
|       uint8_t *rom;
 | |
|       rom_head *head;
 | |
|       rom=flash_get_rom(&head);
 | |
|       param_init(head);
 | |
|       if(rom)
 | |
|       {
 | |
|         if(head->crc==crc_crc32(rom,head->size))
 | |
|         {
 | |
|           flash_updata_app(rom,head->size);
 | |
|         }
 | |
|       }
 | |
|       bk_reboot_guide();
 | |
|       break;
 | |
|     }
 | |
|     // 重新运行boot
 | |
|     case REBOOT_BOOT_TO_BOOT:
 | |
|       break;
 | |
|     // 重启app
 | |
|     case REBOOT_APP_TO_APP:
 | |
|     // 引导至app
 | |
|     case REBOOT_BOOT_TO_APP:
 | |
|     // 断言失败重启
 | |
|     case REBOOT_PARAM_ERR:
 | |
|     // 硬件错误重启
 | |
|     case REBOOT_HARD_ERR:
 | |
|     // 看门狗重启
 | |
|     case REBOOT_INIT:
 | |
|     // 上电启动
 | |
|     default:
 | |
|       param_init(0);
 | |
|       app_run();
 | |
|       break;
 | |
|   }
 | |
|   while(1)
 | |
|   {
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| // 初始化mac地址
 | |
| void mac_init(uint8_t *mac)
 | |
| {
 | |
|   const uint8_t *mcu_id=(const uint8_t *)0x1FFF7A10;
 | |
|   for(int i=0;i<6;i++)
 | |
|   {
 | |
|     mac[i]=0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| // 参数初始化
 | |
| void param_init(rom_head *h)
 | |
| {
 | |
|   static sys_param_def pars={0};
 | |
|   memcpy(&pars,sys_param(),sizeof(sys_param_def));
 | |
|   if(h){
 | |
|     memcpy(pars.pack_time,h->pack_time,20);
 | |
|     if(pars.local_id==0xffffffff){
 | |
|       memcpy(pars.host_if,h->host_if,8);
 | |
|       memcpy(pars.device_type,"checker",8);
 | |
|       mac_init(pars.mac);
 | |
|       memcpy(pars.local_ip,h->local_ip,4);
 | |
|       memcpy(pars.host_ip,h->host_ip,4);
 | |
|       pars.host_port=h->host_port;
 | |
|       pars.local_cmd_port=7777;
 | |
|       pars.host_log_port=12345;
 | |
|       pars.local_id=1;
 | |
|     }
 | |
|     flash_save_param(&pars);
 | |
|   }
 | |
|   else{
 | |
|     // 填充默认配置
 | |
|     if(pars.local_id==0xffffffff){
 | |
|       memcpy(pars.pack_time,"initial app",12);
 | |
|       memcpy(pars.host_if,"uart4",6);
 | |
|       memcpy(pars.device_type,"coder",6);
 | |
|       mac_init(pars.mac);
 | |
|       memcpy(pars.local_ip,(uint8_t []){192,168,80,10},4);
 | |
|       memcpy(pars.host_ip,(uint8_t []){192,168,80,80},4);
 | |
|       memcpy(pars.host_log_ip,(uint8_t []){192,168,80,80},4);
 | |
|       pars.host_port=9527;
 | |
|       pars.local_cmd_port=7777;
 | |
|       pars.host_log_port=12345;
 | |
|       pars.local_id=1;
 | |
|       flash_save_param(&pars);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | 
