| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 6 | kaklik | /*! \file edp.c \brief Emerald Data Protocol System. */ |
| 2 | //***************************************************************************** |
||
| 3 | // |
||
| 4 | // File Name : 'edp.c' |
||
| 5 | // Title : Emerald Data Protocol System |
||
| 6 | // Author : Pascal Stang - Copyright (C) 2003 |
||
| 7 | // Created : 2003.07.01 |
||
| 8 | // Revised : 2003.07.21 |
||
| 9 | // Version : 0.1 |
||
| 10 | // Target MCU : Atmel AVR series |
||
| 11 | // Editor Tabs : 4 |
||
| 12 | // |
||
| 13 | // This code is distributed under the GNU Public License |
||
| 14 | // which can be found at http://www.gnu.org/licenses/gpl.txt |
||
| 15 | // |
||
| 16 | //***************************************************************************** |
||
| 17 | |||
| 18 | //----- Include Files --------------------------------------------------------- |
||
| 19 | #include <avr/io.h> // include I/O definitions (port names, pin names, etc) |
||
| 20 | #include <avr/interrupt.h> // include interrupt support |
||
| 21 | #include <avr/pgmspace.h> // include program-space support |
||
| 22 | |||
| 23 | #include "global.h" // include our global settings |
||
| 24 | #include "i2c.h" // include I2C support |
||
| 25 | #include "rprintf.h" // include printf function library |
||
| 26 | |||
| 27 | #include "edp.h" |
||
| 28 | |||
| 29 | // globals |
||
| 30 | // EDP master/command: response code and reply buffer |
||
| 31 | u08 EdpCommandResponseCode; |
||
| 32 | //u08 EdpCommandReplyLength; |
||
| 33 | u08 EdpCommandReplyBuffer[EDP_REPLY_BUFFER_SIZE]; |
||
| 34 | u08 EdpCommandReplyChecksum; |
||
| 35 | // EDP slave: response code and reply buffer |
||
| 36 | u08 EdpSlaveResponseCode; |
||
| 37 | u08 EdpSlaveReplyLength; |
||
| 38 | u08 EdpSlaveReplyBuffer[EDP_REPLY_BUFFER_SIZE]; |
||
| 39 | // EDP slave request handler function pointer |
||
| 40 | EdpSlaveHandlerFuncType edpSlaveHandlerFunc; |
||
| 41 | |||
| 42 | // functions |
||
| 43 | void edpInit(void) |
||
| 44 | { |
||
| 45 | // initialize i2c interface and function library |
||
| 46 | i2cInit(); |
||
| 47 | // set i2c bit rate to 30KHz |
||
| 48 | i2cSetBitrate(30); |
||
| 49 | // set the Slave Receive Handler function |
||
| 50 | // (this function will run whenever a master somewhere else on the bus |
||
| 51 | // writes data to us as a slave) |
||
| 52 | i2cSetSlaveReceiveHandler( edpSlaveReceiveService ); |
||
| 53 | // set the Slave Transmit Handler function |
||
| 54 | // (this function will run whenever a master somewhere else on the bus |
||
| 55 | // attempts to read data from us as a slave) |
||
| 56 | i2cSetSlaveTransmitHandler( edpSlaveTransmitService ); |
||
| 57 | } |
||
| 58 | |||
| 59 | void edpSetSlaveHandler(EdpSlaveHandlerFuncType edpSlaveHandlerFunction) |
||
| 60 | { |
||
| 61 | edpSlaveHandlerFunc = edpSlaveHandlerFunction; |
||
| 62 | } |
||
| 63 | |||
| 64 | // ************ EDP Master operations ************ |
||
| 65 | u08 edpSendCommand(u08 deviceAddr, u08 cmdLength, EdpCommand* edpCommand) |
||
| 66 | { |
||
| 67 | EdpReply* edpCommandReply = (EdpReply*)EdpCommandReplyBuffer; |
||
| 68 | u08* sendData; |
||
| 69 | u08* replyData; |
||
| 70 | u08 replyLength; |
||
| 71 | u08 checksum; |
||
| 72 | |||
| 73 | // initialize response variables |
||
| 74 | edpCommandReply->Length = 0; |
||
| 75 | EdpCommandReplyChecksum = 0; |
||
| 76 | |||
| 77 | #ifdef EDP_DEBUG |
||
| 78 | rprintf("\r\nBegin EdpSendCommand, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 79 | #endif |
||
| 80 | |||
| 81 | // disable TWI interrupt |
||
| 82 | cbi(TWCR, TWIE); |
||
| 83 | |||
| 84 | // clear TWI interface |
||
| 85 | //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)); |
||
| 86 | |||
| 87 | // send start condition |
||
| 88 | i2cSendStart(); |
||
| 89 | i2cWaitForComplete(); |
||
| 90 | #ifdef EDP_DEBUG |
||
| 91 | rprintf("Sent Start, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 92 | #endif |
||
| 93 | |||
| 94 | // send device address with write |
||
| 95 | i2cSendByte( (deviceAddr&0xFE) ); |
||
| 96 | i2cWaitForComplete(); |
||
| 97 | #ifdef EDP_DEBUG |
||
| 98 | rprintf("Sent Device Address+Write, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 99 | #endif |
||
| 100 | |||
| 101 | // check if device is present and live |
||
| 102 | if( i2cGetStatus() != TW_MT_SLA_ACK) |
||
| 103 | { |
||
| 104 | // device did not ACK it's address, command will not continue |
||
| 105 | // transmit stop condition |
||
| 106 | // leave with TWEA on for slave receiving |
||
| 107 | i2cSendStop(); |
||
| 108 | while( !(inb(TWCR) & BV(TWSTO)) ); |
||
| 109 | #ifdef EDP_DEBUG |
||
| 110 | rprintf("No Device!, Sent Stop, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 111 | #endif |
||
| 112 | // enable TWI interrupt |
||
| 113 | sbi(TWCR, TWIE); |
||
| 114 | // return error |
||
| 115 | return EDP_COMMAND_NODEV; |
||
| 116 | } |
||
| 117 | |||
| 118 | // send data |
||
| 119 | sendData = (u08*)edpCommand; |
||
| 120 | checksum = 0; |
||
| 121 | while(cmdLength) |
||
| 122 | { |
||
| 123 | i2cSendByte( *sendData ); |
||
| 124 | i2cWaitForComplete(); |
||
| 125 | #ifdef EDP_DEBUG |
||
| 126 | rprintf("Sent Data, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 127 | #endif |
||
| 128 | checksum += *sendData++; |
||
| 129 | cmdLength--; |
||
| 130 | } |
||
| 131 | |||
| 132 | // send the checksum |
||
| 133 | i2cSendByte( ~checksum ); |
||
| 134 | i2cWaitForComplete(); |
||
| 135 | #ifdef EDP_DEBUG |
||
| 136 | rprintf("Sent Checksum, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 137 | #endif |
||
| 138 | |||
| 139 | // send repeated start condition |
||
| 140 | i2cSendStart(); |
||
| 141 | i2cWaitForComplete(); |
||
| 142 | #ifdef EDP_DEBUG |
||
| 143 | rprintf("Sent Repeated Start, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 144 | #endif |
||
| 145 | |||
| 146 | // send device address with read |
||
| 147 | i2cSendByte( deviceAddr|0x01 ); |
||
| 148 | i2cWaitForComplete(); |
||
| 149 | #ifdef EDP_DEBUG |
||
| 150 | rprintf("Sent Device Address+Read, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 151 | #endif |
||
| 152 | |||
| 153 | // read response code, return NACK |
||
| 154 | i2cReceiveByte(FALSE); |
||
| 155 | i2cWaitForComplete(); |
||
| 156 | #ifdef EDP_DEBUG |
||
| 157 | rprintf("Read Data, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 158 | #endif |
||
| 159 | EdpCommandResponseCode = i2cGetReceivedByte(); |
||
| 160 | |||
| 161 | if(EdpCommandResponseCode==EDP_RESP_DATA_REPLY) |
||
| 162 | { |
||
| 163 | // a data reply is being sent |
||
| 164 | |||
| 165 | // send repeated start condition |
||
| 166 | i2cSendStart(); |
||
| 167 | i2cWaitForComplete(); |
||
| 168 | |||
| 169 | // send device address with read |
||
| 170 | i2cSendByte( deviceAddr|0x01 ); |
||
| 171 | i2cWaitForComplete(); |
||
| 172 | |||
| 173 | // get length, return ACK |
||
| 174 | i2cReceiveByte(TRUE); |
||
| 175 | i2cWaitForComplete(); |
||
| 176 | edpCommandReply->Length = i2cGetReceivedByte(); |
||
| 177 | // set temp variables |
||
| 178 | replyLength = edpCommandReply->Length; |
||
| 179 | replyData = edpCommandReply->Data; |
||
| 180 | |||
| 181 | // get data, return ACKs |
||
| 182 | // preset checksum with the datalength byte |
||
| 183 | checksum = replyLength; |
||
| 184 | while(replyLength > 1) |
||
| 185 | { |
||
| 186 | i2cReceiveByte(TRUE); // receive data byte and return ACK |
||
| 187 | i2cWaitForComplete(); |
||
| 188 | *replyData = i2cGetReceivedByte(); |
||
| 189 | checksum += *replyData++; |
||
| 190 | replyLength--; |
||
| 191 | } |
||
| 192 | |||
| 193 | // get last data (actually the checksum), return NACK (last-byte signal) |
||
| 194 | i2cReceiveByte(FALSE); |
||
| 195 | i2cWaitForComplete(); |
||
| 196 | *replyData = i2cGetReceivedByte(); |
||
| 197 | // add received checksum+1 to our checksum, the result should be zero |
||
| 198 | checksum += (*replyData) + 1; |
||
| 199 | // save the reply checksum |
||
| 200 | EdpCommandReplyChecksum = checksum; |
||
| 201 | } |
||
| 202 | |||
| 203 | // transmit stop condition |
||
| 204 | // leave with TWEA on for slave receiving |
||
| 205 | i2cSendStop(); |
||
| 206 | while( !(inb(TWCR) & BV(TWSTO)) ); |
||
| 207 | #ifdef EDP_DEBUG |
||
| 208 | rprintf("Sent Stop, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 209 | #endif |
||
| 210 | |||
| 211 | // enable TWI interrupt |
||
| 212 | sbi(TWCR, TWIE); |
||
| 213 | |||
| 214 | return EDP_COMMAND_OK; |
||
| 215 | } |
||
| 216 | |||
| 217 | // get the response code and reply from last command |
||
| 218 | u08 edpGetCommandReply(u08* responseCode, EdpReply** edpReply) |
||
| 219 | { |
||
| 220 | u08 retval=EDP_REPLY_OK; |
||
| 221 | |||
| 222 | // get the response code from last command |
||
| 223 | *responseCode = EdpCommandResponseCode; |
||
| 224 | // get the reply from last command |
||
| 225 | *edpReply = (EdpReply*)EdpCommandReplyBuffer; |
||
| 226 | |||
| 227 | // check response code |
||
| 228 | if(EdpCommandResponseCode == EDP_RESP_DATA_REPLY) |
||
| 229 | { |
||
| 230 | // there was a reply, check the checksum |
||
| 231 | // if it's non-zero, data corruption is present |
||
| 232 | if(EdpCommandReplyChecksum) |
||
| 233 | retval = EDP_REPLY_BADCHKSUM; |
||
| 234 | } |
||
| 235 | return retval; |
||
| 236 | } |
||
| 237 | |||
| 238 | /* |
||
| 239 | u08 edpSendCommand(u08 deviceAddr, u08 sendLength, u08* sendData) |
||
| 240 | { |
||
| 241 | u08* replyData = EdpCommandReplyBuffer; |
||
| 242 | u08 replyLength; |
||
| 243 | u08 checksum; |
||
| 244 | |||
| 245 | // initialize response variables |
||
| 246 | EdpCommandReplyLength = 0; |
||
| 247 | EdpCommandReplyChecksum = 0; |
||
| 248 | |||
| 249 | #ifdef EDP_DEBUG |
||
| 250 | rprintf("\r\nBegin EdpSendCommand, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 251 | #endif |
||
| 252 | |||
| 253 | // disable TWI interrupt |
||
| 254 | cbi(TWCR, TWIE); |
||
| 255 | |||
| 256 | // clear TWI interface |
||
| 257 | //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)); |
||
| 258 | |||
| 259 | // send start condition |
||
| 260 | i2cSendStart(); |
||
| 261 | i2cWaitForComplete(); |
||
| 262 | #ifdef EDP_DEBUG |
||
| 263 | rprintf("Sent Start, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 264 | #endif |
||
| 265 | |||
| 266 | // send device address with write |
||
| 267 | i2cSendByte( (deviceAddr&0xFE) ); |
||
| 268 | i2cWaitForComplete(); |
||
| 269 | #ifdef EDP_DEBUG |
||
| 270 | rprintf("Sent Device Address+Write, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 271 | #endif |
||
| 272 | |||
| 273 | // check if device is present and live |
||
| 274 | if( i2cGetStatus() != TW_MT_SLA_ACK) |
||
| 275 | { |
||
| 276 | // device did not ACK it's address, command will not continue |
||
| 277 | // transmit stop condition |
||
| 278 | // leave with TWEA on for slave receiving |
||
| 279 | i2cSendStop(); |
||
| 280 | while( !(inb(TWCR) & BV(TWSTO)) ); |
||
| 281 | #ifdef EDP_DEBUG |
||
| 282 | rprintf("No Device!, Sent Stop, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 283 | #endif |
||
| 284 | // enable TWI interrupt |
||
| 285 | sbi(TWCR, TWIE); |
||
| 286 | // return error |
||
| 287 | return EDP_COMMAND_NODEV; |
||
| 288 | } |
||
| 289 | |||
| 290 | // send data |
||
| 291 | checksum = 0; |
||
| 292 | while(sendLength) |
||
| 293 | { |
||
| 294 | i2cSendByte( *sendData ); |
||
| 295 | i2cWaitForComplete(); |
||
| 296 | #ifdef EDP_DEBUG |
||
| 297 | rprintf("Sent Data, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 298 | #endif |
||
| 299 | checksum += *sendData++; |
||
| 300 | sendLength--; |
||
| 301 | } |
||
| 302 | |||
| 303 | // send the checksum |
||
| 304 | i2cSendByte( ~checksum ); |
||
| 305 | i2cWaitForComplete(); |
||
| 306 | #ifdef EDP_DEBUG |
||
| 307 | rprintf("Sent Checksum, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 308 | #endif |
||
| 309 | |||
| 310 | // send repeated start condition |
||
| 311 | i2cSendStart(); |
||
| 312 | i2cWaitForComplete(); |
||
| 313 | #ifdef EDP_DEBUG |
||
| 314 | rprintf("Sent Repeated Start, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 315 | #endif |
||
| 316 | |||
| 317 | // send device address with read |
||
| 318 | i2cSendByte( deviceAddr|0x01 ); |
||
| 319 | i2cWaitForComplete(); |
||
| 320 | #ifdef EDP_DEBUG |
||
| 321 | rprintf("Sent Device Address+Read, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 322 | #endif |
||
| 323 | |||
| 324 | // read response code, return NACK |
||
| 325 | i2cReceiveByte(FALSE); |
||
| 326 | i2cWaitForComplete(); |
||
| 327 | #ifdef EDP_DEBUG |
||
| 328 | rprintf("Read Data, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 329 | #endif |
||
| 330 | EdpCommandResponseCode = i2cGetReceivedByte(); |
||
| 331 | |||
| 332 | if(EdpCommandResponseCode==EDP_RESP_DATA_REPLY) |
||
| 333 | { |
||
| 334 | // a data reply is being sent |
||
| 335 | |||
| 336 | // send repeated start condition |
||
| 337 | i2cSendStart(); |
||
| 338 | i2cWaitForComplete(); |
||
| 339 | |||
| 340 | // send device address with read |
||
| 341 | i2cSendByte( deviceAddr|0x01 ); |
||
| 342 | i2cWaitForComplete(); |
||
| 343 | |||
| 344 | // get length, return ACK |
||
| 345 | i2cReceiveByte(TRUE); |
||
| 346 | i2cWaitForComplete(); |
||
| 347 | replyLength = i2cGetReceivedByte(); |
||
| 348 | EdpCommandReplyLength = replyLength; |
||
| 349 | |||
| 350 | // get data, return ACKs |
||
| 351 | // preset checksum with the datalength byte |
||
| 352 | checksum = replyLength; |
||
| 353 | while(replyLength > 1) |
||
| 354 | { |
||
| 355 | i2cReceiveByte(TRUE); // receive data byte and return ACK |
||
| 356 | i2cWaitForComplete(); |
||
| 357 | *replyData = i2cGetReceivedByte(); |
||
| 358 | checksum += *replyData++; |
||
| 359 | replyLength--; |
||
| 360 | } |
||
| 361 | |||
| 362 | // get last data (actually the checksum), return NACK (last-byte signal) |
||
| 363 | i2cReceiveByte(FALSE); |
||
| 364 | i2cWaitForComplete(); |
||
| 365 | *replyData = i2cGetReceivedByte(); |
||
| 366 | // add received checksum+1 to our checksum, the result should be zero |
||
| 367 | checksum += (*replyData) + 1; |
||
| 368 | // save the reply checksum |
||
| 369 | EdpCommandReplyChecksum = checksum; |
||
| 370 | } |
||
| 371 | |||
| 372 | // transmit stop condition |
||
| 373 | // leave with TWEA on for slave receiving |
||
| 374 | i2cSendStop(); |
||
| 375 | while( !(inb(TWCR) & BV(TWSTO)) ); |
||
| 376 | #ifdef EDP_DEBUG |
||
| 377 | rprintf("Sent Stop, TWSR:0x%x\r\n",inb(TWSR)); |
||
| 378 | #endif |
||
| 379 | |||
| 380 | // enable TWI interrupt |
||
| 381 | sbi(TWCR, TWIE); |
||
| 382 | |||
| 383 | return EDP_COMMAND_OK; |
||
| 384 | } |
||
| 385 | |||
| 386 | u08 edpGetCommandReply(u08* responseCode, u08* replyLength, u08** replyData) |
||
| 387 | { |
||
| 388 | u08 retval=EDP_REPLY_OK; |
||
| 389 | |||
| 390 | // get the response code and reply data from last command |
||
| 391 | *responseCode = EdpCommandResponseCode; |
||
| 392 | // get the reply length from last command |
||
| 393 | *replyLength = EdpCommandReplyLength; |
||
| 394 | // get the reply data from last command |
||
| 395 | *replyData = EdpCommandReplyBuffer; |
||
| 396 | |||
| 397 | // check response code |
||
| 398 | if(EdpCommandResponseCode == EDP_RESP_DATA_REPLY) |
||
| 399 | { |
||
| 400 | // there was a reply, check the checksum |
||
| 401 | // if it's non-zero, data corruption is present |
||
| 402 | if(EdpCommandReplyChecksum) |
||
| 403 | retval = EDP_REPLY_BADCHKSUM; |
||
| 404 | } |
||
| 405 | return retval; |
||
| 406 | } |
||
| 407 | */ |
||
| 408 | |||
| 409 | // ************ EDP Slave operations ************ |
||
| 410 | |||
| 411 | // this function will run when a master somewhere else on the bus |
||
| 412 | // addresses us and wishes to write data to us |
||
| 413 | void edpSlaveReceiveService(u08 receiveDataLength, u08* receiveData) |
||
| 414 | { |
||
| 415 | u08 i,checksum; |
||
| 416 | |||
| 417 | // initialize the reply length from this command |
||
| 418 | EdpSlaveReplyLength = 0; |
||
| 419 | // verify the checksum |
||
| 420 | // initialize the checksum with 1 |
||
| 421 | checksum = 0x01; |
||
| 422 | // sum all the data in the packet and the data's checksum |
||
| 423 | for(i=0; i<receiveDataLength; i++) |
||
| 424 | { |
||
| 425 | checksum += receiveData[i]; |
||
| 426 | } |
||
| 427 | // if the checksum is non-zero, then the data is corrupt |
||
| 428 | if(checksum) |
||
| 429 | { |
||
| 430 | // set reply code |
||
| 431 | // [FIX] which should it be? |
||
| 432 | EdpSlaveResponseCode = EDP_RESP_DATA_CHK_ERROR; |
||
| 433 | //EdpSlaveResponseCode = EDP_RESP_CMD_CHK_ERROR; |
||
| 434 | return; |
||
| 435 | } |
||
| 436 | |||
| 437 | // make an EDP command pointer to the received I2C data |
||
| 438 | EdpCommand* edpCommand = (EdpCommand*)receiveData; |
||
| 439 | |||
| 440 | // if a slave handler is defined |
||
| 441 | if(edpSlaveHandlerFunc) |
||
| 442 | { |
||
| 443 | // then use it |
||
| 444 | EdpSlaveResponseCode = edpSlaveHandlerFunc( |
||
| 445 | receiveDataLength, edpCommand, |
||
| 446 | EDP_REPLY_BUFFER_SIZE, (EdpReply*)EdpSlaveReplyBuffer); |
||
| 447 | } |
||
| 448 | else |
||
| 449 | { |
||
| 450 | // otherwise reply with unknown command |
||
| 451 | EdpSlaveResponseCode = EDP_RESP_UNKWN_CMD; |
||
| 452 | } |
||
| 453 | } |
||
| 454 | |||
| 455 | // this function will run when a master somewhere else on the bus |
||
| 456 | // addresses us and wishes to read data from us |
||
| 457 | u08 edpSlaveTransmitService(u08 transmitDataLengthMax, u08* transmitData) |
||
| 458 | { |
||
| 459 | u08 i; |
||
| 460 | u08 checksum; |
||
| 461 | u08 transmitDataLength = 0; |
||
| 462 | |||
| 463 | EdpReply* edpReply = (EdpReply*)EdpSlaveReplyBuffer; |
||
| 464 | |||
| 465 | if(EdpSlaveResponseCode) |
||
| 466 | { |
||
| 467 | // reply code is non-zero, we must send it |
||
| 468 | *transmitData = EdpSlaveResponseCode; |
||
| 469 | transmitDataLength = 1; |
||
| 470 | // reset the reply code to flag that we've sent it |
||
| 471 | EdpSlaveResponseCode = 0; |
||
| 472 | } |
||
| 473 | else |
||
| 474 | { |
||
| 475 | // reply code already sent, now send data (if any) |
||
| 476 | // copy length of reply to transmit buffer (+1 for checksum) |
||
| 477 | *transmitData++ = edpReply->Length+1; |
||
| 478 | // initialize checksum |
||
| 479 | checksum = edpReply->Length+1; |
||
| 480 | // copy reply buffer to the transmit buffer |
||
| 481 | for(i=0; i<edpReply->Length; i++) |
||
| 482 | { |
||
| 483 | *transmitData++ = edpReply->Data[i]; |
||
| 484 | checksum += edpReply->Data[i]; |
||
| 485 | } |
||
| 486 | // copy checksum to transmit buffer |
||
| 487 | *transmitData++ = ~checksum; |
||
| 488 | // set number of bytes to transmit |
||
| 489 | transmitDataLength = edpReply->Length+2; |
||
| 490 | } |
||
| 491 | |||
| 492 | // return number of bytes written to transmit buffer |
||
| 493 | return transmitDataLength; |
||
| 494 | } |
Powered by WebSVN v2.8.3