di_return_t dryice_get_tamper_event(uint32_t *events, uint32_t *timestamp, int flags) { di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; if (di_state() == DI_STATE_VALID) { rc = DI_ERR_STATE; goto err; } if (events == NULL) { rc = DI_ERR_INVAL; goto err; } *events = di_read(DSR) & DSR_TAMPER_BITS; if (timestamp) { if (di_state() == DI_STATE_NON_VALID) *timestamp = di_read(DTCMR); else *timestamp = 0; } err: di_busy_clear(); return rc; }
di_return_t dryice_set_random_key(int flags) { uint32_t dcr; di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; if (di_state() == DI_STATE_FAILURE) { rc = DI_ERR_STATE; goto err; } dcr = di_read(DCR); if (dcr & DCR_RKHL) { rc = DI_ERR_HLOCK; goto err; } if (dcr & DCR_RKSL) { rc = DI_ERR_SLOCK; goto err; } todo_init((flags & DI_FUNC_FLAG_ASYNC) != 0); /* clear Random Key Error bit, if set */ if (di_read(DSR) & DSR_RKE) todo_write_val(DSR_RKE, DCR); /* load random key */ todo_write_val(DKCR_LRK, DKCR); /* wait for RKV (valid) or RKE (error) */ todo_wait_rkg(); if (flags & DI_FUNC_LOCK_FLAGS) { dcr = di_read(DCR); if (flags & DI_FUNC_FLAG_WRITE_LOCK) { if (flags & DI_FUNC_FLAG_HARD_LOCK) dcr |= DCR_RKHL; else dcr |= DCR_RKSL; } todo_write_val(dcr, DCR); } todo_start(); if (flags & DI_FUNC_FLAG_ASYNC) return 0; rc = todo_wait_done(); err: di_busy_clear(); return rc; }
di_return_t dryice_get_programmed_key(uint8_t *key_data, int key_bits) { int reg, byte, key_bytes; uint32_t dcr, dpkr; di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; if (key_data == NULL) { rc = DI_ERR_INVAL; goto err; } if (key_bits < 0 || key_bits > MAX_KEY_LEN || key_bits % 8) { rc = DI_ERR_INVAL; goto err; } #if 0 if (!di->key_programmed) { rc = DI_ERR_UNSET; goto err; } #endif if (di_state() == DI_STATE_FAILURE) { rc = DI_ERR_STATE; goto err; } dcr = di_read(DCR); if (dcr & DCR_PKRHL) { rc = DI_ERR_HLOCK; goto err; } if (dcr & DCR_PKRSL) { rc = DI_ERR_SLOCK; goto err; } key_bytes = key_bits / 8; /* read key */ for (reg = 0; reg < MAX_KEY_WORDS; reg++) { if (reg < (MAX_KEY_BYTES - key_bytes) / 4) continue; dpkr = di_read(DPKR7 - reg * 4); for (byte = 0; byte < 4; byte++) { if (reg * 4 + byte >= MAX_KEY_BYTES - key_bytes) { int shift = 24 - byte * 8; *key_data++ = (dpkr >> shift) & 0xff; } } dpkr = 0; /* cleared for security */ }
/* * write a dryice register and loop, waiting for it * to complete. use only during driver initialization. * returns 0 on success or 1 on write failure. */ static int di_write_loop(uint32_t val, int reg) { int rc = 0; int cnt; di_debug("FUNC: %s\n", __func__); di_write(val, reg); for (cnt = 0; cnt < DI_WRITE_LOOP_CNT; cnt++) { uint32_t dsr = di_read(DSR); if (dsr & DSR_WEF) { try_to_clear_wef(); rc = 1; } if (dsr & DSR_WCF) break; } di_debug("wait_write_loop looped %d times\n", cnt); if (cnt == DI_WRITE_LOOP_CNT) rc = 1; if (rc) di_warn("DryIce wait_write_done: WRITE ERROR!\n"); return rc; }
/* * set the seconds portion of dryice alarm register */ static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); unsigned long now; unsigned long alarm_time; int rc; dev_dbg(dev, "%s\n", __func__); rc = rtc_tm_to_time(&alarm->time, &alarm_time); if (rc) return rc; /* don't allow setting alarm in the past */ now = di_read(pdata, DTCMR); if (alarm_time < now) return -EINVAL; /* write the new alarm time */ di_write_wait_err(pdata, (u32)alarm_time, DCAMR, rc, err); if (alarm->enabled) di_int_enable(pdata, DIER_CAIE); /* enable alarm intr */ else di_int_disable(pdata, DIER_CAIE); /* disable alarm intr */ err: return rc; }
di_return_t dryice_release_programmed_key(void) { uint32_t dcr; di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; if (!di->key_programmed) { rc = DI_ERR_UNSET; goto err; } dcr = di_read(DCR); if (dcr & DCR_PKWHL) { rc = DI_ERR_HLOCK; goto err; } if (dcr & DCR_PKWSL) { rc = DI_ERR_SLOCK; goto err; } di->key_programmed = 0; err: di_busy_clear(); return rc; }
/* * disable a dryice interrupt */ static inline void di_int_disable(struct rtc_drv_data *pdata, u32 intr) { unsigned long flags; spin_lock_irqsave(&pdata->irq_lock, flags); di_write(pdata, di_read(pdata, DIER) & ~intr, DIER); spin_unlock_irqrestore(&pdata->irq_lock, flags); }
di_return_t dryice_check_key(di_key_t *key) { uint32_t dksr; di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; if (key == NULL) { rc = DI_ERR_INVAL; goto err; } dksr = di_read(DKSR); if (di_state() != DI_STATE_VALID) { dksr = DKSR_IIM_KEY; rc = DI_ERR_STATE; } else if (dksr == DI_KEY_RK || dksr == DI_KEY_FRK) { if (!(di_read(DSR) & DSR_RKV)) { dksr = DKSR_IIM_KEY; rc = DI_ERR_UNSET; } } switch (dksr) { case DKSR_IIM_KEY: *key = DI_KEY_FK; break; case DKSR_PROG_KEY: *key = DI_KEY_PK; break; case DKSR_RAND_KEY: *key = DI_KEY_RK; break; case DKSR_PROG_XOR_IIM_KEY: *key = DI_KEY_FPK; break; case DKSR_RAND_XOR_IIM_KEY: *key = DI_KEY_FRK; break; } err: di_busy_clear(); return rc; }
/* * dryice "normal" interrupt handler */ static irqreturn_t dryice_norm_irq(int irq, void *dev_id) { struct rtc_drv_data *pdata = dev_id; u32 dsr, dier; irqreturn_t rc = IRQ_NONE; dier = di_read(pdata, DIER); /* handle write complete and write error cases */ if ((dier & DIER_WCIE)) { /*If the write wait queue is empty then there is no pending operations. It means the interrupt is for DryIce -Security. IRQ must be returned as none.*/ if (list_empty_careful(&pdata->write_wait.task_list)) return rc; /* DSR_WCF clears itself on DSR read */ dsr = di_read(pdata, DSR); if ((dsr & (DSR_WCF | DSR_WEF))) { /* mask the interrupt */ di_int_disable(pdata, DIER_WCIE); /* save the dsr value for the wait queue */ pdata->dsr |= dsr; wake_up_interruptible(&pdata->write_wait); rc = IRQ_HANDLED; } } /* handle the alarm case */ if ((dier & DIER_CAIE)) { /* DSR_WCF clears itself on DSR read */ dsr = di_read(pdata, DSR); if (dsr & DSR_CAF) { /* mask the interrupt */ di_int_disable(pdata, DIER_CAIE); /* finish alarm in user context */ schedule_work(&pdata->work); rc = IRQ_HANDLED; } } return rc; }
/* * read the seconds portion of the current time from the dryice time counter */ static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); unsigned long now; dev_dbg(dev, "%s\n", __func__); now = di_read(pdata, DTCMR); rtc_time_to_tm(now, tm); return 0; }
/* * return the current state of dryice * (valid, non-valid, or failure) */ static enum di_states di_state(void) { enum di_states state = DI_STATE_VALID; uint32_t dsr = di_read(DSR); if (dsr & DSR_NVF) state = DI_STATE_NON_VALID; else if (dsr & DSR_SVF) state = DI_STATE_FAILURE; return state; }
/* * read the seconds portion of the alarm register. * the fractional part of the alarm register is always zero. */ static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); u32 dcamr; dev_dbg(dev, "%s\n", __func__); dcamr = di_read(pdata, DCAMR); rtc_time_to_tm(dcamr, &alarm->time); /* alarm is enabled if the interrupt is enabled */ alarm->enabled = (di_read(pdata, DIER) & DIER_CAIE) != 0; /* don't allow the DSR read to mess up DSR_WCF */ mutex_lock(&pdata->write_mutex); /* alarm is pending if the alarm flag is set */ alarm->pending = (di_read(pdata, DSR) & DSR_CAF) != 0; mutex_unlock(&pdata->write_mutex); return 0; }
/* * the write-error flag is something that shouldn't get set * during normal operation. if it's set something is terribly * wrong. the best we can do is try to clear the bit and hope * that dryice will recover. this situation is similar to an * unexpected bus fault in terms of severity. */ static void try_to_clear_wef(void) { int cnt; while (1) { di_write(DSR_WEF, DSR); for (cnt = 0; cnt < DI_WRITE_LOOP_CNT; cnt++) { if ((di_read(DSR) & DSR_WEF) == 0) break; } di_warn("WARNING: DryIce cannot clear DSR_WEF " "(Write Error Flag)!\n"); } }
/* * This function attempts to clear the dryice write-error flag. * * A dryice write error is similar to a bus fault and should not occur in * normal operation. Clearing the flag requires another write, so the root * cause of the problem may need to be fixed before the flag can be cleared. */ static void clear_write_error(struct rtc_drv_data *pdata) { int cnt; dev_warn(&pdata->pdev->dev, "WARNING: Register write error!\n"); for (;;) { /* clear the write error flag */ di_write(pdata, DSR_WEF, DSR); /* wait for it to take effect */ for (cnt = 0; cnt < 100; cnt++) { if ((di_read(pdata, DSR) & DSR_WEF) == 0) return; udelay(10); } dev_err(&pdata->pdev->dev, "ERROR: Cannot clear write-error flag!\n"); } }
/* * print out the contents of the dryice status register * with all the bits decoded */ static void show_dsr(const char *heading) { uint32_t dsr = di_read(DSR); di_info("%s\n", heading); if (dsr & DSR_TAMPER_BITS) { if (dsr & DSR_WTD) di_info("Wire-mesh Tampering Detected\n"); if (dsr & DSR_ETBD) di_info("External Tampering B Detected\n"); if (dsr & DSR_ETAD) di_info("External Tampering A Detected\n"); if (dsr & DSR_EBD) di_info("External Boot Detected\n"); if (dsr & DSR_SAD) di_info("Security Alarm Detected\n"); if (dsr & DSR_TTD) di_info("Temperature Tampering Detected\n"); if (dsr & DSR_CTD) di_info("Clock Tampering Detected\n"); if (dsr & DSR_VTD) di_info("Voltage Tampering Detected\n"); if (dsr & DSR_MCO) di_info("Monotonic Counter Overflow\n"); if (dsr & DSR_TCO) di_info("Time Counter Overflow\n"); } else di_info("No Tamper Events Detected\n"); di_info("%d Key Busy Flag\n", !!(dsr & DSR_KBF)); di_info("%d Write Busy Flag\n", !!(dsr & DSR_WBF)); di_info("%d Write Next Flag\n", !!(dsr & DSR_WNF)); di_info("%d Write Complete Flag\n", !!(dsr & DSR_WCF)); di_info("%d Write Error Flag\n", !!(dsr & DSR_WEF)); di_info("%d Random Key Error\n", !!(dsr & DSR_RKE)); di_info("%d Random Key Valid\n", !!(dsr & DSR_RKV)); di_info("%d Clock Alarm Flag\n", !!(dsr & DSR_CAF)); di_info("%d Non-Valid Flag\n", !!(dsr & DSR_NVF)); di_info("%d Security Violation Flag\n", !!(dsr & DSR_SVF)); }
di_return_t dryice_select_key(di_key_t key, int flags) { uint32_t dcr, dksr; di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; switch (key) { case DI_KEY_FK: dksr = DKSR_IIM_KEY; break; case DI_KEY_PK: dksr = DKSR_PROG_KEY; break; case DI_KEY_RK: dksr = DKSR_RAND_KEY; break; case DI_KEY_FPK: dksr = DKSR_PROG_XOR_IIM_KEY; break; case DI_KEY_FRK: dksr = DKSR_RAND_XOR_IIM_KEY; break; default: rc = DI_ERR_INVAL; goto err; } if (di->key_selected) { rc = DI_ERR_INUSE; goto err; } if (di_state() != DI_STATE_VALID) { rc = DI_ERR_STATE; goto err; } dcr = di_read(DCR); if (dcr & DCR_KSHL) { rc = DI_ERR_HLOCK; goto err; } if (dcr & DCR_KSSL) { rc = DI_ERR_SLOCK; goto err; } todo_init((flags & DI_FUNC_FLAG_ASYNC) != 0); /* select key */ todo_write_val(dksr, DKSR); todo_assign(di->key_selected, 1); if (flags & DI_FUNC_LOCK_FLAGS) { dcr = di_read(DCR); if (flags & DI_FUNC_FLAG_WRITE_LOCK) { if (flags & DI_FUNC_FLAG_HARD_LOCK) dcr |= DCR_KSHL; else dcr |= DCR_KSSL; } todo_write_val(dcr, DCR); } todo_start(); if (flags & DI_FUNC_FLAG_ASYNC) return 0; rc = todo_wait_done(); err: di_busy_clear(); return rc; }
di_return_t dryice_set_programmed_key(const void *key_data, int key_bits, int flags) { uint32_t dcr; int key_bytes, reg; di_return_t rc = 0; if (di_busy_set()) return DI_ERR_BUSY; if (key_data == NULL) { rc = DI_ERR_INVAL; goto err; } if (key_bits < 0 || key_bits > MAX_KEY_LEN || key_bits % 8) { rc = DI_ERR_INVAL; goto err; } if (flags & DI_FUNC_FLAG_WORD_KEY) { if (key_bits % 32 || (uint32_t)key_data & 0x3) { rc = DI_ERR_INVAL; goto err; } } if (di->key_programmed) { rc = DI_ERR_INUSE; goto err; } if (di_state() == DI_STATE_FAILURE) { rc = DI_ERR_STATE; goto err; } dcr = di_read(DCR); if (dcr & DCR_PKWHL) { rc = DI_ERR_HLOCK; goto err; } if (dcr & DCR_PKWSL) { rc = DI_ERR_SLOCK; goto err; } key_bytes = key_bits / 8; todo_init((flags & DI_FUNC_FLAG_ASYNC) != 0); /* accomodate busses that can only do 32-bit transfers */ if (flags & DI_FUNC_FLAG_WORD_KEY) { uint32_t *keyp = (void *)key_data; for (reg = 0; reg < MAX_KEY_WORDS; reg++) { if (reg < MAX_KEY_WORDS - key_bytes / 4) todo_write_val(0, DPKR7 - reg * 4); else { todo_write_ptr32(keyp, DPKR7 - reg * 4); keyp++; } } } else { uint8_t *keyp = (void *)key_data; for (reg = 0; reg < MAX_KEY_WORDS; reg++) { int size = key_bytes - (MAX_KEY_WORDS - reg - 1) * 4; if (size <= 0) todo_write_val(0, DPKR7 - reg * 4); else { if (size > 4) size = 4; todo_write_ptr(keyp, DPKR7 - reg * 4, size); keyp += size; } } } todo_assign(di->key_programmed, 1); if (flags & DI_FUNC_LOCK_FLAGS) { dcr = di_read(DCR); if (flags & DI_FUNC_FLAG_READ_LOCK) { if (flags & DI_FUNC_FLAG_HARD_LOCK) dcr |= DCR_PKRHL; else dcr |= DCR_PKRSL; } if (flags & DI_FUNC_FLAG_WRITE_LOCK) { if (flags & DI_FUNC_FLAG_HARD_LOCK) dcr |= DCR_PKWHL; else dcr |= DCR_PKWSL; } todo_write_val(dcr, DCR); } todo_start(); if (flags & DI_FUNC_FLAG_ASYNC) return 0; rc = todo_wait_done(); err: di_busy_clear(); return rc; }
void todo_cur(void) { di_debug("FUNC: %s[%d]\n", __func__, todo.cur); switch (TC.action) { case TODO_ACT_WRITE_VAL: di_debug(" TODO_ACT_WRITE_VAL\n"); /* enable the write-completion interrupt */ todo.status = TODO_ST_PEND_WCF; di_write(di_read(DIER) | DIER_WCIE, DIER); di_write(TC.src, TC.dst); break; case TODO_ACT_WRITE_PTR32: di_debug(" TODO_ACT_WRITE_PTR32\n"); /* enable the write-completion interrupt */ todo.status = TODO_ST_PEND_WCF; di_write(di_read(DIER) | DIER_WCIE, DIER); di_write(*(uint32_t *)TC.src, TC.dst); break; case TODO_ACT_WRITE_PTR: { uint8_t *p = (uint8_t *)TC.src; uint32_t val = 0; int num = TC.num; di_debug(" TODO_ACT_WRITE_PTR\n"); while (num--) val = (val << 8) | *p++; /* enable the write-completion interrupt */ todo.status = TODO_ST_PEND_WCF; di_write(di_read(DIER) | DIER_WCIE, DIER); di_write(val, TC.dst); } break; case TODO_ACT_ASSIGN: di_debug(" TODO_ACT_ASSIGN\n"); switch (TC.num) { case 1: *(uint8_t *)TC.dst = TC.src; break; case 2: *(uint16_t *)TC.dst = TC.src; break; case 4: *(uint32_t *)TC.dst = TC.src; break; default: di_warn("Unexpected size in TODO_ACT_ASSIGN\n"); break; } break; case TODO_ACT_WAIT_RKG: di_debug(" TODO_ACT_WAIT_RKG\n"); /* enable the random-key interrupt */ todo.status = TODO_ST_PEND_RKG; di_write(di_read(DIER) | DIER_RKIE, DIER); break; default: di_debug(" TODO_ACT_NOOP\n"); break; } }
/* * probe for dryice rtc device */ static int dryice_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; struct rtc_drv_data *pdata = NULL; void __iomem *ioaddr = NULL; int rc = 0; dev_dbg(&pdev->dev, "%s\n", __func__); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; pdata->pdev = pdev; pdata->irq = -1; pdata->size = res->end - res->start + 1; if (!request_mem_region(res->start, pdata->size, pdev->name)) { rc = -EBUSY; goto err; } pdata->baseaddr = res->start; ioaddr = ioremap(pdata->baseaddr, pdata->size); if (!ioaddr) { rc = -ENOMEM; goto err; } pdata->ioaddr = ioaddr; pdata->irq = platform_get_irq(pdev, 0); init_waitqueue_head(&pdata->write_wait); INIT_WORK(&pdata->work, dryice_work); mutex_init(&pdata->write_mutex); pdata->clk = clk_get(NULL, "dryice_clk"); clk_enable(pdata->clk); if (pdata->irq >= 0) { if (request_irq(pdata->irq, dryice_norm_irq, IRQF_SHARED, pdev->name, pdata) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); pdata->irq = -1; goto err; } } /* * Initialize dryice hardware */ /* put dryice into valid state */ if (di_read(pdata, DSR) & DSR_NVF) di_write_wait_err(pdata, DSR_NVF | DSR_SVF, DSR, rc, err); /* mask alarm interrupt */ di_int_disable(pdata, DIER_CAIE); /* initialize alarm */ di_write_wait_err(pdata, DCAMR_UNSET, DCAMR, rc, err); di_write_wait_err(pdata, 0, DCALR, rc, err); /* clear alarm flag */ if (di_read(pdata, DSR) & DSR_CAF) di_write_wait_err(pdata, DSR_CAF, DSR, rc, err); /* the timer won't count if it has never been written to */ if (!di_read(pdata, DTCMR)) di_write_wait_err(pdata, 0, DTCMR, rc, err); /* start keeping time */ if (!(di_read(pdata, DCR) & DCR_TCE)) di_write_wait_err(pdata, di_read(pdata, DCR) | DCR_TCE, DCR, rc, err); rtc = rtc_device_register(pdev->name, &pdev->dev, &dryice_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { rc = PTR_ERR(rtc); goto err; } pdata->rtc = rtc; platform_set_drvdata(pdev, pdata); return 0; err: if (pdata->rtc) rtc_device_unregister(pdata->rtc); if (pdata->irq >= 0) free_irq(pdata->irq, pdata); if (pdata->clk) { clk_disable(pdata->clk); clk_put(pdata->clk); } if (pdata->ioaddr) iounmap(pdata->ioaddr); if (pdata->baseaddr) release_mem_region(pdata->baseaddr, pdata->size); kfree(pdata); return rc; }
//===================================================================================== // Main Function // This is the main function where program start to execute //===================================================================================== void main(void) { //-------------------------------------------------------------------------------- // Program start // User can start to write/modify the program here //-------------------------------------------------------------------------------- // User is advised not to change or remove the initialization function called init(); // call initialization function of the setting in program while(1) { //-------------------------------------------------------------------------------- // This program is mainly for slave card,DI08. It will test the 3 push buttons // on MB00, the push buttons are active low, hence, when any of the push button // is pressed, value '0' will be sent to microcontroller on master card, MB00. // Hence, the program will test digital input port base on program //-------------------------------------------------------------------------------- if(sw1==0) // Test whether SW1 on IFC-MB00 is pressed { led1 = 1; // turn ON LED1 on MB00 by sending value '1' buzzer = 1; // turn ON buzzer on MB00 by sending value '1' delay(50000); // delay for buzzer ON time buzzer = 0; // turn OFF buzzer on MB00 by sending value '0' while(1) { // this is an infinity loop after SW1 on IFC-MB00 is pressed, // user need to press reset button on MB00 to exit from the mode if(di_read(add_di1, 1)==0) // If DI 1 detected signal { led5=1; // turn ON LED5 on MB00 by sending value '1' buzzer = 1; // turn ON buzzer on MB00 by sending value '1' delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer } if(di_read(add_di1,2)==0) // If DI 2 detected signal { led6=1; // turn ON LED6 on MB00 by sending value '1' buzzer = 1; // buzzer ON for first time delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer delay(50000); // delay for buzzer OFF time buzzer = 1; // buzzer ON for second times delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer } if((di_read(add_di1, 3)||di_read(add_di1, 4))==0) // If DI 3 and DI 4 detected signal { led=0xff; // All LED ON while(1); // infinity loop } } } if(sw2==0) // Test whether SW2 on IFC-MB00 is pressed { led2 = 1; // turn ON LED2 on MB00 by sending value '1' buzzer = 1; // buzzer ON for first time delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer delay(50000); // delay for buzzer OFF time buzzer = 1; // buzzer ON for second times delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer di_c1con(add_di1,1); // Activate Counter 1 di_c2con(add_di1,1); // Activate Counter 2 di_c1clr(add_di1); // Clear value in Counter 1 di_c2clr(add_di1); // Clear value in Counter 2 while(1) { // this is an infinity loop after SW2 on IFC-MB00 is pressed, // user need to press reset button on MB00 to exit from the mode if(di_c1val(add_di1)==3) // If value counter 1 = 3 { di_c2clr(add_di1); // Clear value in Counter 2 led7=1; // turn ON LED7 on MB00 by sending value '1' led8=0; // turn OFF LED8 on MB00 by sending value '0' } else if(di_c2val(add_di1)==3) // If value counter 2 = 3 { di_c1clr(add_di1); // Clear value in Counter 1 led8=1; // turn ON LED8 on MB00 by sending value '1' led7=0; // turn OFF LED7 on MB00 by sending value '0' } } } if(sw3==0) // Test whether SW3 on IFC-MB00 is pressed { led3 = 1; // turn ON LED3 on MB00 by sending value '1' buzzer = 1; // buzzer ON for first time delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer delay(50000); // delay for buzzer OFF time buzzer = 1; // buzzer ON for second times delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer delay(50000); // delay for buzzer OFF time buzzer = 1; // buzzer ON for third times delay(50000); // delay for buzzer ON time buzzer = 0; // OFF buzzer while(1) { // this is an infinity loop after SW3 on IFC-MB00 is pressed, // user need to press reset button on MB00 to exit from the mode if(di_read(add_di1,0)==0) // if ALL digital input detected signal { while(1) // Infinity loop for LED blinking { led=0x0f; delay(50000); led=0xf0; delay(50000); } } } } } }