SpiDrv.cpp
#include <>
From: https://github.com/arduino-libraries/WiFiLink-Library/blob/master/src/utility/spi/spi_drv.cpp
/*H*******************************************************
spi_drv.cpp - Library for Arduino WiFi shield.
Copyright ( c ) 2011-2014 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or ( at your option ) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
********************************************************/
#include "Arduino.h"
#include <SPI.h>
#include "utility/spi_drv.h"
#include "pins_arduino.h"
//#define _DEBUG_
extern "C" {
#include "utility/debug.h"
}
//************************* DEFINES ************************************
#define DATAOUT 11 // MOSI
#define DATAIN 12 // MISO
#define SPICLOCK 13 // SCK
#define SLAVESELECT 10 // SS
#define SLAVEREADY 7 // handshake pin
#define WIFILED 9 // LED on WiFi shield
#define DELAY_SPI( X ) { int ii=0; do { asm volatile( "nop" ); } while( ++ii < ( X*F_CPU/16000000 ) ); }
#define DELAY_TRANSFER() DELAY_SPI( 10 )
//************************* PROTOTYPES ************************************
//************************* VARIABLES ************************************
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
begin()
{
SPI.begin();
pinMode( SLAVESELECT, OUTPUT );
pinMode( SLAVEREADY, INPUT );
pinMode( WIFILED, OUTPUT );
// digitalWrite( SCK, LOW );
// digitalWrite( MOSI, LOW );
digitalWrite( SS, HIGH );
digitalWrite( SLAVESELECT, HIGH );
digitalWrite( WIFILED, LOW );
#ifdef _DEBUG_
INIT_TRIGGER()
#endif
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
end()
{
SPI.end();
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
spiSlaveSelect()
{
digitalWrite( SLAVESELECT,LOW );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
spiSlaveDeselect()
{
digitalWrite( SLAVESELECT,HIGH );
}
/*F********************************************************************
*
**********************************************************************/
char SpiDrv::
spiTransfer( volatile char data )
{
char result = SPI.transfer( data );
DELAY_TRANSFER();
return( result ); // RETURN RECEIVED BYTE
}
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
waitSpiChar( unsigned char waitChar )
{
int timeout = TIMEOUT_CHAR;
unsigned char _readChar = 0;
do
{
_readChar = readChar(); //get data byte
if( _readChar == ERR_CMD )
{
WARN( "Err cmd received\n" );
return -1;
}
}while( ( timeout-- > 0 ) && ( _readChar != waitChar ) );
return( _readChar == waitChar );
}
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
readAndCheckChar( char checkChar, char *readChar )
{
getParam( ( uint8_t* )readChar );
return( *readChar == checkChar );
}
/*F********************************************************************
*
**********************************************************************/
char SpiDrv::
readChar()
{
uint8_t readChar = 0;
getParam( &readChar );
return( readChar );
}
/*F********************************************************************
*
**********************************************************************/
#define WAIT_START_CMD(x) waitSpiChar( START_CMD )
#define IF_CHECK_START_CMD( x ) \
if( !WAIT_START_CMD( _data ) ) \
{ \
TOGGLE_TRIGGER() \
WARN( "Error waiting START_CMD" ); \
return 0; \
}
else \
#define CHECK_DATA( check, x ) \
if( !readAndCheckChar( check, &x ) ) \
{ \
TOGGLE_TRIGGER() \
WARN( "Reply error" ); \
INFO2( check, ( uint8_t )x ); \
return 0; \
}
else // \
#define waitSlaveReady
() ( digitalRead( SLAVEREADY ) == LOW )
#define waitSlaveSign
() ( digitalRead( SLAVEREADY ) == HIGH )
#define waitSlaveSignalH
() while( digitalRead( SLAVEREADY ) != HIGH ){}
#define waitSlaveSignalL
() while( digitalRead( SLAVEREADY ) != LOW ){}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
waitForSlaveSign()
{
while( !waitSlaveSign() );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
waitForSlaveReady()
{
while( !waitSlaveReady() );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
getParam( uint8_t *param )
{
// Get Params data
*param = spiTransfer( DUMMY_DATA );
DELAY_TRANSFER();
}
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
waitResponseCmd( uint8_t cmd, uint8_t numParam, uint8_t *param, uint8_t *param_len )
{
char _data = 0;
int ii = 0;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
CHECK_DATA( numParam, _data );
{
readParamLen8( param_len );
for( ii = 0; ii < (*param_len); ++ii )
{ // Get Params data
//param[ii] = spiTransfer( DUMMY_DATA );
getParam( ¶m[ii] );
}
}
readAndCheckChar( END_CMD, &_data );
}
return 1;
}
/*F********************************************************************
* 2 sets of code, 1st commented out
**********************************************************************/
/*
int SpiDrv::
waitResponse( uint8_t cmd, uint8_t numParam, uint8_t *param, uint16_t *param_len )
{
char _data = 0;
int i =0, ii = 0;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
CHECK_DATA( numParam, _data );
{
readParamLen16( param_len );
for( ii = 0; ii < (*param_len); ++ii )
{ // Get Params data
param[ii] = spiTransfer( DUMMY_DATA );
}
}
readAndCheckChar( END_CMD, &_data );
}
return 1;
}
*/
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
waitResponseData16( uint8_t cmd, uint8_t *param, uint16_t *param_len )
{
char _data = 0;
uint16_t ii = 0;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
uint8_t numParam = readChar();
if( numParam != 0 )
{
readParamLen16( param_len );
for( ii = 0; ii < (*param_len); ++ii )
{ // Get Params data
param[ii] = spiTransfer( DUMMY_DATA );
}
}
readAndCheckChar( END_CMD, &_data );
}
return 1;
}
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
waitResponseData8( uint8_t cmd, uint8_t* param, uint8_t* param_len )
{
char _data = 0;
int ii = 0;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
uint8_t numParam = readChar();
if( numParam != 0 )
{
readParamLen8( param_len );
for( ii = 0; ii < (*param_len); ++ii )
{ // Get Params data
param[ii] = spiTransfer( DUMMY_DATA );
}
}
readAndCheckChar( END_CMD, &_data );
}
return 1;
}
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
waitResponseParams( uint8_t cmd, uint8_t numParam, tParam* params )
{
char _data = 0;
int i =0, ii = 0;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
uint8_t _numParam = readChar();
if( _numParam != 0 )
{
for( i =0; i < _numParam; ++i )
{
params[i].paramLen = readParamLen8();
for( ii = 0; ii < params[i].paramLen; ++ii )
{ // Get Params data
params[i].param[ii] = spiTransfer( DUMMY_DATA );
}
}
} else
{
WARN( "Error numParam == 0" );
return 0;
}
if( numParam != _numParam )
{
WARN( "Mismatch numParam" );
return 0;
}
readAndCheckChar( END_CMD, &_data );
}
return 1;
}
/*F********************************************************************
* 2 sets of code,1st commented out
**********************************************************************/
/*
int SpiDrv::
waitResponse( uint8_t cmd, tParam* params, uint8_t* numParamRead
, uint8_t maxNumParams )
{
char _data = 0;
int i =0, ii = 0;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
uint8_t numParam = readChar();
if( numParam > maxNumParams )
{
numParam = maxNumParams;
}
*numParamRead = numParam;
if( numParam != 0 )
{
for( i =0; i < numParam; ++i )
{
params[i].paramLen = readParamLen8();
for( ii =0; ii < params[i].paramLen; ++ii )
{ // Get Params data
params[i].param[ii] = spiTransfer( DUMMY_DATA );
}
}
}
else
{
WARN( "Error numParams == 0" );
Serial.println( cmd, 16 );
return 0;
}
readAndCheckChar( END_CMD, &_data );
}
return 1;
}
*/
/*F********************************************************************
*
**********************************************************************/
int SpiDrv::
waitResponse( uint8_t cmd, uint8_t *numParamRead, uint8_t **params
, uint8_t maxNumParams )
{
char _data = 0;
int i =0, ii = 0;
char *index[WL_SSID_MAX_LENGTH];
for( i = 0 ; i < WL_NETWORKS_LIST_MAXNUM ; i++ )
index[i] = ( char*)params + WL_SSID_MAX_LENGTH*i;
IF_CHECK_START_CMD( _data )
{
CHECK_DATA( cmd | REPLY_FLAG, _data ){};
uint8_t numParam = readChar();
if( numParam > maxNumParams )
{
numParam = maxNumParams;
}
*numParamRead = numParam;
if( numParam != 0 )
{
for( i =0; i < numParam; ++i )
{
uint8_t paramLen = readParamLen8();
for( ii =0; ii < paramLen; ++ii )
{
//ssid[ii] = spiTransfer( DUMMY_DATA );
// Get Params data
index[i][ii] = ( uint8_t )spiTransfer( DUMMY_DATA );
}
index[i][ii]=0;
}
} else
{
WARN( "Error numParams == 0" );
readAndCheckChar( END_CMD, &_data );
return( 0 );
}
readAndCheckChar( END_CMD, &_data );
}
return( 1 );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
sendParam( const uint8_t* param, uint8_t param_len, uint8_t lastParam )
{
int i = 0;
sendParamLen8( param_len ); // SEND SPI PARAMLEN
for( i =0; i < param_len; ++i ) // SEND SPI PARAM DATA
spiTransfer( param[i] );
// if lastParam == 1 Send SPI END CMD
if( lastParam == 1 )
spiTransfer( END_CMD );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
sendParamLen8( uint8_t param_len )
{
// Send SPI paramLen
spiTransfer( param_len );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
sendParamLen16( uint16_t param_len )
{
// Send SPI paramLen
spiTransfer( (uint8_t)( ( param_len & 0xff00 ) >> 8 ) );
spiTransfer( (uint8_t)( param_len & 0xff ) );
}
/*F********************************************************************
*
**********************************************************************/
uint8_t SpiDrv::readParamLen8( uint8_t* param_len )
{
uint8_t _param_len = spiTransfer( DUMMY_DATA );
if( param_len != NULL )
*param_len = _param_len;
return( _param_len );
}
/*F********************************************************************
*
**********************************************************************/
uint16_t SpiDrv::
readParamLen16( uint16_t* param_len )
{
uint16_t _param_len = spiTransfer( DUMMY_DATA ) << 8
| ( spiTransfer( DUMMY_DATA )& 0xff );
if( param_len != NULL )
*param_len = _param_len;
return( _param_len );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
sendBuffer( uint8_t* param, uint16_t param_len, uint8_t lastParam )
{
uint16_t i = 0;
sendParamLen16( param_len );// SEND SPI PARAMLEN
for( i =0; i < param_len; ++i ) // SEND SPI PARAM DATA
{
spiTransfer( param[i] );
}
// if lastParam==1 Send SPI END CMD
if( lastParam == 1 )
spiTransfer( END_CMD );
}
/*F********************************************************************
*
**********************************************************************/
void SpiDrv::
sendParam( uint16_t param, uint8_t lastParam )
{
sendParamLen8( 2 ); // Send SPI paramLen
spiTransfer( ( uint8_t )( ( param & 0xff00 )>>8 ) );
spiTransfer( ( uint8_t )( param & 0xff ) );
// if lastParam==1 Send SPI END CMD
if( lastParam == 1 )
spiTransfer( END_CMD );
}
/*H*******************************************************
* Cmd Struct Message
* START CMD | C/R | CMD |[TOT LEN]| N.PARAM | PARAM LEN | PARAM | .. | END |
*___________|_____|_____|_________|_________|___________|_______|____|_____|
* 8 bit | 1bit| 7bit| 8bit | 8bit | 8bit | nbytes | ..| 8bit|
*___________|_____|_____|_________|_________|___________|________|___|_____|
*******************************************************/
void SpiDrv::
sendCmd( uint8_t cmd, uint8_t numParam )
{
spiTransfer( START_CMD ); // Send SPI START CMD
// waitForSlaveSign();
delayMicroseconds( SPI_START_CMD_DELAY ); // wait interrupt trigger on slave
spiTransfer( cmd & ~( REPLY_FLAG ) ); // Send SPI C + cmd
//spiTransfer( totLen ); // Send SPI totLen
spiTransfer( numParam ); // Send SPI numParam
// If numParam == 0 send END CMD
if( numParam == 0 )
spiTransfer( END_CMD );
}
SpiDrv spiDrv;