static inline void i2c_automaton(uint32_t state) { switch (state) { case I2C_START: case I2C_RESTART: I2cSendByte(i2c_slave_addr); I2cClearStart(); i2c_index = 0; break; case I2C_MR_DATA_ACK: if (i2c_index < i2c_len) { i2c_buf[i2c_index] = I2C_DATA_REG; i2c_index++; I2cReceive(i2c_index < i2c_len - 1); } else { /* error , we should have got NACK */ I2cSendStop(); } break; case I2C_MR_SLA_ACK: /* At least one char */ /* Wait and reply with ACK or NACK */ I2cReceive(i2c_index < i2c_len - 1); break; case I2C_MR_SLA_NACK: case I2C_MT_SLA_NACK: I2cSendStart(); break; case I2C_MT_SLA_ACK: case I2C_MT_DATA_ACK: if (i2c_index < i2c_len) { I2cSendByte(i2c_buf[i2c_index]); i2c_index++; } else { I2cSendStop(); } break; case I2C_MR_DATA_NACK: if (i2c_index < i2c_len) { i2c_buf[i2c_index] = I2C_DATA_REG; } I2cSendStop(); break; default: I2cSendStop(); /* LED_ON(2); FIXME log error */ } }
__attribute__ ((always_inline)) static inline void I2cAutomaton(int32_t state, struct i2c_periph* p) { struct i2c_transaction* trans = p->trans[p->trans_extract_idx]; switch (state) { case I2C_START: case I2C_RESTART: // Set R/W flag switch (trans->type) { case I2CTransRx : SetBit(trans->slave_addr,0); break; case I2CTransTx: case I2CTransTxRx: ClearBit(trans->slave_addr,0); break; default: break; } I2cSendByte(p->reg_addr,trans->slave_addr); I2cClearStart(p->reg_addr); p->idx_buf = 0; break; case I2C_MR_DATA_ACK: if (p->idx_buf < trans->len_r) { trans->buf[p->idx_buf] = ((i2cRegs_t *)(p->reg_addr))->dat; p->idx_buf++; I2cReceive(p->reg_addr,p->idx_buf < trans->len_r - 1); } else { /* error , we should have got NACK */ I2cFail(p,trans); } break; case I2C_MR_DATA_NACK: if (p->idx_buf < trans->len_r) { trans->buf[p->idx_buf] = ((i2cRegs_t *)(p->reg_addr))->dat; } I2cSendStop(p,trans); break; case I2C_MR_SLA_ACK: /* At least one char */ /* Wait and reply with ACK or NACK */ I2cReceive(p->reg_addr,p->idx_buf < trans->len_r - 1); break; case I2C_MR_SLA_NACK: case I2C_MT_SLA_NACK: /* Slave is not responding, transaction is failed */ I2cFail(p,trans); break; case I2C_MT_SLA_ACK: case I2C_MT_DATA_ACK: if (p->idx_buf < trans->len_w) { I2cSendByte(p->reg_addr,trans->buf[p->idx_buf]); p->idx_buf++; } else { if (trans->type == I2CTransTxRx) { trans->type = I2CTransRx; /* FIXME should not change type */ p->idx_buf = 0; trans->slave_addr |= 1; I2cSendStart(p); } else { I2cSendStop(p,trans); } } break; default: I2cFail(p,trans); /* FIXME log error */ break; } }