Repo restyled using astyle (#683)
The rules are in .tools/astyle/config/style.cfg and can also be reviewed at https://www.mysensors.org/view/260#coding-guidelines-core-library
This commit is contained in:
+312
-292
@@ -65,44 +65,42 @@
|
||||
#define WPOLY 0x011B
|
||||
#define DPOLY 0x008D
|
||||
|
||||
const static byte s_fwd [0x100] PROGMEM =
|
||||
{
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
const static byte s_fwd [0x100] PROGMEM = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
} ;
|
||||
|
||||
const static byte s_inv [0x100] PROGMEM =
|
||||
{
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
const static byte s_inv [0x100] PROGMEM = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
} ;
|
||||
|
||||
// times 2 in the GF(2^8)
|
||||
@@ -111,38 +109,36 @@ const static byte s_inv [0x100] PROGMEM =
|
||||
|
||||
static byte s_box (byte x)
|
||||
{
|
||||
// return fwd_affine (pgm_read_byte (&inv [x])) ;
|
||||
return pgm_read_byte (& s_fwd [x]) ;
|
||||
// return fwd_affine (pgm_read_byte (&inv [x])) ;
|
||||
return pgm_read_byte (& s_fwd [x]) ;
|
||||
}
|
||||
|
||||
// Inverse Sbox
|
||||
static byte is_box (byte x)
|
||||
{
|
||||
// return pgm_read_byte (&inv [inv_affine (x)]) ;
|
||||
return pgm_read_byte (& s_inv [x]) ;
|
||||
// return pgm_read_byte (&inv [inv_affine (x)]) ;
|
||||
return pgm_read_byte (& s_inv [x]) ;
|
||||
}
|
||||
|
||||
|
||||
static void xor_block (byte * d, byte * s)
|
||||
{
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += 4)
|
||||
{
|
||||
*d++ ^= *s++ ; // some unrolling
|
||||
*d++ ^= *s++ ;
|
||||
*d++ ^= *s++ ;
|
||||
*d++ ^= *s++ ;
|
||||
}
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += 4) {
|
||||
*d++ ^= *s++ ; // some unrolling
|
||||
*d++ ^= *s++ ;
|
||||
*d++ ^= *s++ ;
|
||||
*d++ ^= *s++ ;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_and_key (byte * d, byte * s, byte * k)
|
||||
{
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += 4)
|
||||
{
|
||||
*d++ = *s++ ^ *k++ ; // some unrolling
|
||||
*d++ = *s++ ^ *k++ ;
|
||||
*d++ = *s++ ^ *k++ ;
|
||||
*d++ = *s++ ^ *k++ ;
|
||||
}
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += 4) {
|
||||
*d++ = *s++ ^ *k++ ; // some unrolling
|
||||
*d++ = *s++ ^ *k++ ;
|
||||
*d++ = *s++ ^ *k++ ;
|
||||
*d++ = *s++ ^ *k++ ;
|
||||
}
|
||||
}
|
||||
|
||||
// #define add_round_key(d, k) xor_block (d, k)
|
||||
@@ -151,88 +147,110 @@ static void copy_and_key (byte * d, byte * s, byte * k)
|
||||
|
||||
static void shift_sub_rows (byte st [N_BLOCK])
|
||||
{
|
||||
st [0] = s_box (st [0]) ; st [4] = s_box (st [4]) ;
|
||||
st [8] = s_box (st [8]) ; st [12] = s_box (st [12]) ;
|
||||
st [0] = s_box (st [0]) ;
|
||||
st [4] = s_box (st [4]) ;
|
||||
st [8] = s_box (st [8]) ;
|
||||
st [12] = s_box (st [12]) ;
|
||||
|
||||
byte tt = st [1] ;
|
||||
st [1] = s_box (st [5]) ; st [5] = s_box (st [9]) ;
|
||||
st [9] = s_box (st [13]) ; st [13] = s_box (tt) ;
|
||||
byte tt = st [1] ;
|
||||
st [1] = s_box (st [5]) ;
|
||||
st [5] = s_box (st [9]) ;
|
||||
st [9] = s_box (st [13]) ;
|
||||
st [13] = s_box (tt) ;
|
||||
|
||||
tt = st[2] ; st [2] = s_box (st [10]) ; st [10] = s_box (tt) ;
|
||||
tt = st[6] ; st [6] = s_box (st [14]) ; st [14] = s_box (tt) ;
|
||||
tt = st[2] ;
|
||||
st [2] = s_box (st [10]) ;
|
||||
st [10] = s_box (tt) ;
|
||||
tt = st[6] ;
|
||||
st [6] = s_box (st [14]) ;
|
||||
st [14] = s_box (tt) ;
|
||||
|
||||
tt = st[15] ;
|
||||
st [15] = s_box (st [11]) ; st [11] = s_box (st [7]) ;
|
||||
st [7] = s_box (st [3]) ; st [3] = s_box (tt) ;
|
||||
tt = st[15] ;
|
||||
st [15] = s_box (st [11]) ;
|
||||
st [11] = s_box (st [7]) ;
|
||||
st [7] = s_box (st [3]) ;
|
||||
st [3] = s_box (tt) ;
|
||||
}
|
||||
|
||||
static void inv_shift_sub_rows (byte st[N_BLOCK])
|
||||
{
|
||||
st [0] = is_box (st[0]) ; st [4] = is_box (st [4]);
|
||||
st [8] = is_box (st[8]) ; st [12] = is_box (st [12]);
|
||||
st [0] = is_box (st[0]) ;
|
||||
st [4] = is_box (st [4]);
|
||||
st [8] = is_box (st[8]) ;
|
||||
st [12] = is_box (st [12]);
|
||||
|
||||
byte tt = st[13] ;
|
||||
st [13] = is_box (st [9]) ; st [9] = is_box (st [5]) ;
|
||||
st [5] = is_box (st [1]) ; st [1] = is_box (tt) ;
|
||||
byte tt = st[13] ;
|
||||
st [13] = is_box (st [9]) ;
|
||||
st [9] = is_box (st [5]) ;
|
||||
st [5] = is_box (st [1]) ;
|
||||
st [1] = is_box (tt) ;
|
||||
|
||||
tt = st [2] ; st [2] = is_box (st [10]) ; st [10] = is_box (tt) ;
|
||||
tt = st [6] ; st [6] = is_box (st [14]) ; st [14] = is_box (tt) ;
|
||||
tt = st [2] ;
|
||||
st [2] = is_box (st [10]) ;
|
||||
st [10] = is_box (tt) ;
|
||||
tt = st [6] ;
|
||||
st [6] = is_box (st [14]) ;
|
||||
st [14] = is_box (tt) ;
|
||||
|
||||
tt = st [3] ;
|
||||
st [3] = is_box (st [7]) ; st [7] = is_box (st [11]) ;
|
||||
st [11] = is_box (st [15]) ; st [15] = is_box (tt) ;
|
||||
tt = st [3] ;
|
||||
st [3] = is_box (st [7]) ;
|
||||
st [7] = is_box (st [11]) ;
|
||||
st [11] = is_box (st [15]) ;
|
||||
st [15] = is_box (tt) ;
|
||||
}
|
||||
|
||||
/* SUB COLUMNS PHASE */
|
||||
|
||||
static void mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK])
|
||||
{
|
||||
byte j = 5 ;
|
||||
byte k = 10 ;
|
||||
byte l = 15 ;
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += N_COL)
|
||||
{
|
||||
byte a = st [i] ;
|
||||
byte b = st [j] ; j = (j+N_COL) & 15 ;
|
||||
byte c = st [k] ; k = (k+N_COL) & 15 ;
|
||||
byte d = st [l] ; l = (l+N_COL) & 15 ;
|
||||
byte a1 = s_box (a), b1 = s_box (b), c1 = s_box (c), d1 = s_box (d) ;
|
||||
byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ;
|
||||
dt[i] = a2 ^ b2^b1 ^ c1 ^ d1 ;
|
||||
dt[i+1] = a1 ^ b2 ^ c2^c1 ^ d1 ;
|
||||
dt[i+2] = a1 ^ b1 ^ c2 ^ d2^d1 ;
|
||||
dt[i+3] = a2^a1 ^ b1 ^ c1 ^ d2 ;
|
||||
}
|
||||
byte j = 5 ;
|
||||
byte k = 10 ;
|
||||
byte l = 15 ;
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += N_COL) {
|
||||
byte a = st [i] ;
|
||||
byte b = st [j] ;
|
||||
j = (j+N_COL) & 15 ;
|
||||
byte c = st [k] ;
|
||||
k = (k+N_COL) & 15 ;
|
||||
byte d = st [l] ;
|
||||
l = (l+N_COL) & 15 ;
|
||||
byte a1 = s_box (a), b1 = s_box (b), c1 = s_box (c), d1 = s_box (d) ;
|
||||
byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ;
|
||||
dt[i] = a2 ^ b2^b1 ^ c1 ^ d1 ;
|
||||
dt[i+1] = a1 ^ b2 ^ c2^c1 ^ d1 ;
|
||||
dt[i+2] = a1 ^ b1 ^ c2 ^ d2^d1 ;
|
||||
dt[i+3] = a2^a1 ^ b1 ^ c1 ^ d2 ;
|
||||
}
|
||||
}
|
||||
|
||||
static void inv_mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK])
|
||||
{
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += N_COL)
|
||||
{
|
||||
byte a1 = st [i] ;
|
||||
byte b1 = st [i+1] ;
|
||||
byte c1 = st [i+2] ;
|
||||
byte d1 = st [i+3] ;
|
||||
byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ;
|
||||
byte a4 = f2(a2), b4 = f2(b2), c4 = f2(c2), d4 = f2(d2) ;
|
||||
byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ;
|
||||
byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ;
|
||||
byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ;
|
||||
for (byte i = 0 ; i < N_BLOCK ; i += N_COL) {
|
||||
byte a1 = st [i] ;
|
||||
byte b1 = st [i+1] ;
|
||||
byte c1 = st [i+2] ;
|
||||
byte d1 = st [i+3] ;
|
||||
byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ;
|
||||
byte a4 = f2(a2), b4 = f2(b2), c4 = f2(c2), d4 = f2(d2) ;
|
||||
byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ;
|
||||
byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ;
|
||||
byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ;
|
||||
|
||||
dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ;
|
||||
dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ;
|
||||
dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ;
|
||||
dt[(i+15)&15] = is_box (a9^a2 ^ bc^b1 ^ c9 ^ dc^d2) ;
|
||||
}
|
||||
dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ;
|
||||
dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ;
|
||||
dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ;
|
||||
dt[(i+15)&15] = is_box (a9^a2 ^ bc^b1 ^ c9 ^ dc^d2) ;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
AES::AES(){
|
||||
AES::AES()
|
||||
{
|
||||
byte ar_iv[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 };
|
||||
memcpy(iv,ar_iv,8);
|
||||
memcpy(iv+8,ar_iv,8);
|
||||
arr_pad[0] = 0x01;
|
||||
arr_pad[0] = 0x01;
|
||||
arr_pad[1] = 0x02;
|
||||
arr_pad[2] = 0x03;
|
||||
arr_pad[3] = 0x04;
|
||||
@@ -253,208 +271,196 @@ AES::AES(){
|
||||
|
||||
byte AES::set_key (byte key [], int keylen)
|
||||
{
|
||||
byte hi ;
|
||||
switch (keylen)
|
||||
{
|
||||
case 16:
|
||||
case 128:
|
||||
keylen = 16; // 10 rounds
|
||||
round = 10 ;
|
||||
break;
|
||||
case 24:
|
||||
case 192:
|
||||
keylen = 24; // 12 rounds
|
||||
round = 12 ;
|
||||
break;
|
||||
case 32:
|
||||
case 256:
|
||||
keylen = 32; // 14 rounds
|
||||
round = 14 ;
|
||||
break;
|
||||
default:
|
||||
round = 0;
|
||||
return AES_FAILURE;
|
||||
}
|
||||
hi = (round + 1) << 4 ;
|
||||
copy_n_bytes (key_sched, key, keylen) ;
|
||||
byte t[4] ;
|
||||
byte next = keylen ;
|
||||
for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL)
|
||||
{
|
||||
for (byte i = 0 ; i < N_COL ; i++) {
|
||||
t[i] = key_sched [cc-4+i] ;
|
||||
}
|
||||
if (cc == next)
|
||||
{
|
||||
next += keylen ;
|
||||
byte ttt = t[0] ;
|
||||
t[0] = s_box (t[1]) ^ rc ;
|
||||
t[1] = s_box (t[2]) ;
|
||||
t[2] = s_box (t[3]) ;
|
||||
t[3] = s_box (ttt) ;
|
||||
rc = f2 (rc) ;
|
||||
}
|
||||
else if (keylen == 32 && (cc & 31) == 16)
|
||||
{
|
||||
for (byte i = 0 ; i < 4 ; i++) {
|
||||
t[i] = s_box (t[i]) ;
|
||||
}
|
||||
}
|
||||
byte tt = cc - keylen ;
|
||||
for (byte i = 0 ; i < N_COL ; i++) {
|
||||
key_sched [cc + i] = key_sched [tt + i] ^ t[i] ;
|
||||
}
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
byte hi ;
|
||||
switch (keylen) {
|
||||
case 16:
|
||||
case 128:
|
||||
keylen = 16; // 10 rounds
|
||||
round = 10 ;
|
||||
break;
|
||||
case 24:
|
||||
case 192:
|
||||
keylen = 24; // 12 rounds
|
||||
round = 12 ;
|
||||
break;
|
||||
case 32:
|
||||
case 256:
|
||||
keylen = 32; // 14 rounds
|
||||
round = 14 ;
|
||||
break;
|
||||
default:
|
||||
round = 0;
|
||||
return AES_FAILURE;
|
||||
}
|
||||
hi = (round + 1) << 4 ;
|
||||
copy_n_bytes (key_sched, key, keylen) ;
|
||||
byte t[4] ;
|
||||
byte next = keylen ;
|
||||
for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) {
|
||||
for (byte i = 0 ; i < N_COL ; i++) {
|
||||
t[i] = key_sched [cc-4+i] ;
|
||||
}
|
||||
if (cc == next) {
|
||||
next += keylen ;
|
||||
byte ttt = t[0] ;
|
||||
t[0] = s_box (t[1]) ^ rc ;
|
||||
t[1] = s_box (t[2]) ;
|
||||
t[2] = s_box (t[3]) ;
|
||||
t[3] = s_box (ttt) ;
|
||||
rc = f2 (rc) ;
|
||||
} else if (keylen == 32 && (cc & 31) == 16) {
|
||||
for (byte i = 0 ; i < 4 ; i++) {
|
||||
t[i] = s_box (t[i]) ;
|
||||
}
|
||||
}
|
||||
byte tt = cc - keylen ;
|
||||
for (byte i = 0 ; i < N_COL ; i++) {
|
||||
key_sched [cc + i] = key_sched [tt + i] ^ t[i] ;
|
||||
}
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::clean ()
|
||||
{
|
||||
for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) {
|
||||
key_sched [i] = 0 ;
|
||||
}
|
||||
round = 0 ;
|
||||
for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) {
|
||||
key_sched [i] = 0 ;
|
||||
}
|
||||
round = 0 ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::copy_n_bytes (byte * d, byte * s, byte nn)
|
||||
{
|
||||
while (nn >= 4)
|
||||
{
|
||||
*d++ = *s++ ; // some unrolling
|
||||
*d++ = *s++ ;
|
||||
*d++ = *s++ ;
|
||||
*d++ = *s++ ;
|
||||
nn -= 4 ;
|
||||
}
|
||||
while (nn--)
|
||||
*d++ = *s++ ;
|
||||
while (nn >= 4) {
|
||||
*d++ = *s++ ; // some unrolling
|
||||
*d++ = *s++ ;
|
||||
*d++ = *s++ ;
|
||||
*d++ = *s++ ;
|
||||
nn -= 4 ;
|
||||
}
|
||||
while (nn--) {
|
||||
*d++ = *s++ ;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
byte AES::encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK])
|
||||
{
|
||||
if (round)
|
||||
{
|
||||
byte s1 [N_BLOCK], r ;
|
||||
copy_and_key (s1, plain, (byte*) (key_sched)) ;
|
||||
if (round) {
|
||||
byte s1 [N_BLOCK], r ;
|
||||
copy_and_key (s1, plain, (byte*) (key_sched)) ;
|
||||
|
||||
for (r = 1 ; r < round ; r++)
|
||||
{
|
||||
byte s2 [N_BLOCK] ;
|
||||
mix_sub_columns (s2, s1) ;
|
||||
copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ;
|
||||
}
|
||||
shift_sub_rows (s1) ;
|
||||
copy_and_key (cipher, s1, (byte*) (key_sched + r * N_BLOCK)) ;
|
||||
}
|
||||
else
|
||||
return AES_FAILURE ;
|
||||
return AES_SUCCESS ;
|
||||
for (r = 1 ; r < round ; r++) {
|
||||
byte s2 [N_BLOCK] ;
|
||||
mix_sub_columns (s2, s1) ;
|
||||
copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ;
|
||||
}
|
||||
shift_sub_rows (s1) ;
|
||||
copy_and_key (cipher, s1, (byte*) (key_sched + r * N_BLOCK)) ;
|
||||
} else {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK])
|
||||
{
|
||||
while (n_block--)
|
||||
{
|
||||
xor_block (iv, plain) ;
|
||||
if (encrypt (iv, iv) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
copy_n_bytes (cipher, iv, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK ;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
while (n_block--) {
|
||||
xor_block (iv, plain) ;
|
||||
if (encrypt (iv, iv) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
copy_n_bytes (cipher, iv, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK ;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block)
|
||||
{
|
||||
while (n_block--)
|
||||
{
|
||||
xor_block (iv, plain) ;
|
||||
if (encrypt (iv, iv) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
copy_n_bytes (cipher, iv, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK ;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
while (n_block--) {
|
||||
xor_block (iv, plain) ;
|
||||
if (encrypt (iv, iv) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
copy_n_bytes (cipher, iv, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK ;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
byte AES::decrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK])
|
||||
{
|
||||
if (round)
|
||||
{
|
||||
byte s1 [N_BLOCK] ;
|
||||
copy_and_key (s1, plain, (byte*) (key_sched + round * N_BLOCK)) ;
|
||||
inv_shift_sub_rows (s1) ;
|
||||
if (round) {
|
||||
byte s1 [N_BLOCK] ;
|
||||
copy_and_key (s1, plain, (byte*) (key_sched + round * N_BLOCK)) ;
|
||||
inv_shift_sub_rows (s1) ;
|
||||
|
||||
for (byte r = round ; --r ; )
|
||||
{
|
||||
byte s2 [N_BLOCK] ;
|
||||
copy_and_key (s2, s1, (byte*) (key_sched + r * N_BLOCK)) ;
|
||||
inv_mix_sub_columns (s1, s2) ;
|
||||
}
|
||||
copy_and_key (cipher, s1, (byte*) (key_sched)) ;
|
||||
}
|
||||
else
|
||||
return AES_FAILURE ;
|
||||
return AES_SUCCESS ;
|
||||
for (byte r = round ; --r ; ) {
|
||||
byte s2 [N_BLOCK] ;
|
||||
copy_and_key (s2, s1, (byte*) (key_sched + r * N_BLOCK)) ;
|
||||
inv_mix_sub_columns (s1, s2) ;
|
||||
}
|
||||
copy_and_key (cipher, s1, (byte*) (key_sched)) ;
|
||||
} else {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK])
|
||||
{
|
||||
while (n_block--)
|
||||
{
|
||||
byte tmp [N_BLOCK] ;
|
||||
copy_n_bytes (tmp, cipher, N_BLOCK) ;
|
||||
if (decrypt (cipher, plain) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
xor_block (plain, iv) ;
|
||||
copy_n_bytes (iv, tmp, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
while (n_block--) {
|
||||
byte tmp [N_BLOCK] ;
|
||||
copy_n_bytes (tmp, cipher, N_BLOCK) ;
|
||||
if (decrypt (cipher, plain) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
xor_block (plain, iv) ;
|
||||
copy_n_bytes (iv, tmp, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block)
|
||||
{
|
||||
while (n_block--)
|
||||
{
|
||||
byte tmp [N_BLOCK] ;
|
||||
copy_n_bytes (tmp, cipher, N_BLOCK) ;
|
||||
if (decrypt (cipher, plain) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
xor_block (plain, iv) ;
|
||||
copy_n_bytes (iv, tmp, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
while (n_block--) {
|
||||
byte tmp [N_BLOCK] ;
|
||||
copy_n_bytes (tmp, cipher, N_BLOCK) ;
|
||||
if (decrypt (cipher, plain) != AES_SUCCESS) {
|
||||
return AES_FAILURE ;
|
||||
}
|
||||
xor_block (plain, iv) ;
|
||||
copy_n_bytes (iv, tmp, N_BLOCK) ;
|
||||
plain += N_BLOCK ;
|
||||
cipher += N_BLOCK;
|
||||
}
|
||||
return AES_SUCCESS ;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void AES::set_IV(unsigned long long int IVCl){
|
||||
void AES::set_IV(unsigned long long int IVCl)
|
||||
{
|
||||
memcpy(iv,&IVCl,8);
|
||||
memcpy(iv+8,&IVCl,8);
|
||||
IVC = IVCl;
|
||||
@@ -462,7 +468,8 @@ void AES::set_IV(unsigned long long int IVCl){
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::iv_inc(){
|
||||
void AES::iv_inc()
|
||||
{
|
||||
IVC += 1;
|
||||
memcpy(iv,&IVC,8);
|
||||
memcpy(iv+8,&IVC,8);
|
||||
@@ -470,31 +477,35 @@ void AES::iv_inc(){
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int AES::get_size(){
|
||||
int AES::get_size()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::set_size(int sizel){
|
||||
void AES::set_size(int sizel)
|
||||
{
|
||||
size = sizel;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::get_IV(byte *out){
|
||||
void AES::get_IV(byte *out)
|
||||
{
|
||||
memcpy(out,&IVC,8);
|
||||
memcpy(out+8,&IVC,8);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::calc_size_n_pad(int p_size){
|
||||
void AES::calc_size_n_pad(int p_size)
|
||||
{
|
||||
int s_of_p = p_size - 1;
|
||||
if ( s_of_p % N_BLOCK == 0){
|
||||
size = s_of_p;
|
||||
}else{
|
||||
if ( s_of_p % N_BLOCK == 0) {
|
||||
size = s_of_p;
|
||||
} else {
|
||||
size = s_of_p + (N_BLOCK-(s_of_p % N_BLOCK));
|
||||
}
|
||||
pad = size - s_of_p;
|
||||
@@ -505,59 +516,63 @@ void AES::calc_size_n_pad(int p_size){
|
||||
void AES::padPlaintext(void* in,byte* out)
|
||||
{
|
||||
memcpy(out,in,size);
|
||||
for (int i = size-pad; i < size; i++){;
|
||||
for (int i = size-pad; i < size; i++) {
|
||||
;
|
||||
out[i] = arr_pad[pad - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
bool AES::CheckPad(byte* in,int lsize){
|
||||
if (in[lsize-1] <= 0x0f){
|
||||
bool AES::CheckPad(byte* in,int lsize)
|
||||
{
|
||||
if (in[lsize-1] <= 0x0f) {
|
||||
int lpad = (int)in[lsize-1];
|
||||
for (int i = lsize - 1; i >= lsize-lpad; i--){
|
||||
if (arr_pad[lpad - 1] != in[i]){
|
||||
for (int i = lsize - 1; i >= lsize-lpad; i--) {
|
||||
if (arr_pad[lpad - 1] != in[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::printArray(byte output[],bool p_pad)
|
||||
{
|
||||
uint8_t i,j;
|
||||
uint8_t loops = size/N_BLOCK;
|
||||
uint8_t outp = N_BLOCK;
|
||||
for (j = 0; j < loops; j += 1){
|
||||
if (p_pad && (j == (loops - 1)) ) { outp = N_BLOCK - pad; }
|
||||
for (i = 0; i < outp; i++)
|
||||
{
|
||||
printf_P(PSTR("%c"),output[j*N_BLOCK + i]);
|
||||
}
|
||||
}
|
||||
printf_P(PSTR("\n"));
|
||||
uint8_t i,j;
|
||||
uint8_t loops = size/N_BLOCK;
|
||||
uint8_t outp = N_BLOCK;
|
||||
for (j = 0; j < loops; j += 1) {
|
||||
if (p_pad && (j == (loops - 1)) ) {
|
||||
outp = N_BLOCK - pad;
|
||||
}
|
||||
for (i = 0; i < outp; i++) {
|
||||
printf_P(PSTR("%c"),output[j*N_BLOCK + i]);
|
||||
}
|
||||
}
|
||||
printf_P(PSTR("\n"));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::printArray(byte output[],int sizel)
|
||||
{
|
||||
for (int i = 0; i < sizel; i++)
|
||||
{
|
||||
printf_P(PSTR("%x"),output[i]);
|
||||
}
|
||||
printf_P(PSTR("\n"));
|
||||
for (int i = 0; i < sizel; i++) {
|
||||
printf_P(PSTR("%x"),output[i]);
|
||||
}
|
||||
printf_P(PSTR("\n"));
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]){
|
||||
void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits,
|
||||
byte ivl [N_BLOCK])
|
||||
{
|
||||
calc_size_n_pad(size_p);
|
||||
byte plain_p[get_size()];
|
||||
padPlaintext(plain,plain_p);
|
||||
@@ -568,7 +583,8 @@ void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits){
|
||||
void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits)
|
||||
{
|
||||
calc_size_n_pad(size_p);
|
||||
byte plain_p[get_size()];
|
||||
padPlaintext(plain,plain_p);
|
||||
@@ -579,7 +595,9 @@ void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]){
|
||||
void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits,
|
||||
byte ivl [N_BLOCK])
|
||||
{
|
||||
set_size(size_c);
|
||||
int blocks = size_c / N_BLOCK;
|
||||
set_key (key, bits);
|
||||
@@ -588,7 +606,8 @@ void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits){
|
||||
void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits)
|
||||
{
|
||||
set_size(size_c);
|
||||
int blocks = size_c / N_BLOCK;
|
||||
set_key (key, bits);
|
||||
@@ -599,7 +618,8 @@ void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits
|
||||
/******************************************************************************/
|
||||
|
||||
#if defined(AES_LINUX)
|
||||
double AES::millis(){
|
||||
double AES::millis()
|
||||
{
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec + 0.000001 * tv.tv_usec);
|
||||
}
|
||||
|
||||
+120
-119
@@ -31,44 +31,44 @@
|
||||
This is an AES implementation that uses only 8-bit byte operations on the
|
||||
cipher state.
|
||||
*/
|
||||
|
||||
/* code was modified by george spanos <spaniakos@gmail.com>
|
||||
* 16/12/14
|
||||
*/
|
||||
|
||||
/* code was modified by george spanos <spaniakos@gmail.com>
|
||||
* 16/12/14
|
||||
*/
|
||||
/** AES class */
|
||||
class AES
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
/* The following calls are for a precomputed key schedule
|
||||
/* The following calls are for a precomputed key schedule
|
||||
|
||||
NOTE: If the length_type used for the key length is an
|
||||
unsigned 8-bit character, a key length of 256 bits must
|
||||
be entered as a length in bytes (valid inputs are hence
|
||||
128, 192, 16, 24 and 32).
|
||||
*/
|
||||
NOTE: If the length_type used for the key length is an
|
||||
unsigned 8-bit character, a key length of 256 bits must
|
||||
be entered as a length in bytes (valid inputs are hence
|
||||
128, 192, 16, 24 and 32).
|
||||
*/
|
||||
/** \fn AES()
|
||||
* \brief AES constructor
|
||||
*
|
||||
*
|
||||
* This function initialized an instance of AES.
|
||||
*/
|
||||
AES();
|
||||
|
||||
/** Set the cipher key for the pre-keyed version.
|
||||
|
||||
/** Set the cipher key for the pre-keyed version.
|
||||
* @param key[] pointer to the key string.
|
||||
* @param keylen Integer that indicates the length of the key.
|
||||
* @note NOTE: If the length_type used for the key length is an unsigned 8-bit character,
|
||||
* a key length of 256 bits must be entered as a length in bytes
|
||||
* @note NOTE: If the length_type used for the key length is an unsigned 8-bit character,
|
||||
* a key length of 256 bits must be entered as a length in bytes
|
||||
* (valid inputs are hence 128, 192, 16, 24 and 32).
|
||||
*
|
||||
*/
|
||||
byte set_key (byte key[], int keylen) ;
|
||||
|
||||
|
||||
/** clean up subkeys after use.
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
void clean () ; // delete key schedule after use
|
||||
|
||||
|
||||
/** copying and xoring utilities.
|
||||
* @param *AESt byte pointer of the AEStination array.
|
||||
* @param *src byte pointer of the source array.
|
||||
@@ -92,9 +92,9 @@ class AES
|
||||
*
|
||||
*/
|
||||
byte encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) ;
|
||||
|
||||
|
||||
/** CBC encrypt a number of blocks (input and return an IV).
|
||||
*
|
||||
*
|
||||
* @param *plain Pointer, points to the plaintex.
|
||||
* @param *cipher Pointer, points to the ciphertext that will be created.
|
||||
* @param n_block integer, indicated the number of blocks to be ciphered.
|
||||
@@ -103,9 +103,9 @@ class AES
|
||||
*
|
||||
*/
|
||||
byte cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) ;
|
||||
|
||||
|
||||
/** CBC encrypt a number of blocks (input and return an IV).
|
||||
*
|
||||
*
|
||||
* @param *plain Pointer, points to the plaintex.
|
||||
* @param *cipher Pointer, points to the ciphertext that will be created.
|
||||
* @param n_block integer, indicated the number of blocks to be ciphered.
|
||||
@@ -115,7 +115,7 @@ class AES
|
||||
byte cbc_encrypt (byte * plain, byte * cipher, int n_block) ;
|
||||
|
||||
|
||||
/** Decrypt a single block of 16 bytes
|
||||
/** Decrypt a single block of 16 bytes
|
||||
* @param cipher Array of the ciphertext.
|
||||
* @param plain Array of the plaintext.
|
||||
* @note The N_BLOCK is defined in AES_config.h as,
|
||||
@@ -128,9 +128,9 @@ class AES
|
||||
*
|
||||
*/
|
||||
byte decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK]) ;
|
||||
|
||||
/** CBC decrypt a number of blocks (input and return an IV)
|
||||
*
|
||||
|
||||
/** CBC decrypt a number of blocks (input and return an IV)
|
||||
*
|
||||
* @param *cipher Pointer, points to the ciphertext that will be created.
|
||||
* @param *plain Pointer, points to the plaintex.
|
||||
* @param n_block integer, indicated the number of blocks to be ciphered.
|
||||
@@ -139,9 +139,9 @@ class AES
|
||||
*
|
||||
*/
|
||||
byte cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) ;
|
||||
|
||||
/** CBC decrypt a number of blocks (input and return an IV)
|
||||
*
|
||||
|
||||
/** CBC decrypt a number of blocks (input and return an IV)
|
||||
*
|
||||
* @param *cipher Pointer, points to the ciphertext that will be created.
|
||||
* @param *plain Pointer, points to the plaintex.
|
||||
* @param n_block integer, indicated the number of blocks to be ciphered.
|
||||
@@ -149,7 +149,7 @@ class AES
|
||||
*
|
||||
*/
|
||||
byte cbc_decrypt (byte * cipher, byte * plain, int n_block) ;
|
||||
|
||||
|
||||
/** Sets IV (initialization vector) and IVC (IV counter).
|
||||
* This function changes the ivc and iv variables needed for AES.
|
||||
*
|
||||
@@ -158,62 +158,62 @@ class AES
|
||||
* @code unsigned long long int my_iv = 01234567; @endcode
|
||||
*/
|
||||
void set_IV(unsigned long long int IVCl);
|
||||
|
||||
|
||||
/** increase the iv (initialization vector) and IVC (IV counter) by 1
|
||||
*
|
||||
*
|
||||
* This function increased the VI by one step in order to have a different IV each time
|
||||
*
|
||||
*
|
||||
*/
|
||||
void iv_inc();
|
||||
|
||||
|
||||
/** Getter method for size
|
||||
*
|
||||
*
|
||||
* This function return the size
|
||||
* @return an integer, that is the size of the of the padded plaintext,
|
||||
* thus, the size of the ciphertext.
|
||||
*/
|
||||
int get_size();
|
||||
|
||||
|
||||
/** Setter method for size
|
||||
*
|
||||
* This function sets the size of the plaintext+pad
|
||||
*
|
||||
*
|
||||
*/
|
||||
void set_size(int sizel);
|
||||
|
||||
|
||||
/** Getter method for IV
|
||||
*
|
||||
*
|
||||
* This function return the IV
|
||||
* @param out byte pointer that gets the IV.
|
||||
* @return none, the IV is writed to the out pointer.
|
||||
*/
|
||||
void get_IV(byte *out);
|
||||
|
||||
|
||||
/** Calculates the size of the plaintext and the padding.
|
||||
*
|
||||
*
|
||||
* Calculates the size of theplaintext with the padding
|
||||
* and the size of the padding needed. Moreover it stores them in their class variables.
|
||||
*
|
||||
*
|
||||
* @param p_size the size of the byte array ex sizeof(plaintext)
|
||||
*/
|
||||
void calc_size_n_pad(int p_size);
|
||||
|
||||
|
||||
/** Pads the plaintext
|
||||
*
|
||||
* This function pads the plaintext and returns an char array with the
|
||||
* plaintext and the padding in order for the plaintext to be compatible with
|
||||
*
|
||||
* This function pads the plaintext and returns an char array with the
|
||||
* plaintext and the padding in order for the plaintext to be compatible with
|
||||
* 16bit size blocks required by AES
|
||||
*
|
||||
*
|
||||
* @param in the string of the plaintext in a byte array
|
||||
* @param out The string of the out array.
|
||||
* @return no return, The padded plaintext is stored in the out pointer.
|
||||
*/
|
||||
void padPlaintext(void* in,byte* out);
|
||||
|
||||
|
||||
/** Check the if the padding is correct.
|
||||
*
|
||||
*
|
||||
* This functions checks the padding of the plaintext.
|
||||
*
|
||||
*
|
||||
* @param in the string of the plaintext in a byte array
|
||||
* @param size the size of the string
|
||||
* @return true if correct / false if not
|
||||
@@ -221,26 +221,26 @@ class AES
|
||||
bool CheckPad(byte* in,int size);
|
||||
|
||||
/** Prints the array given.
|
||||
*
|
||||
* This function prints the given array and pad,
|
||||
*
|
||||
* This function prints the given array and pad,
|
||||
* It is mainlly used for debugging purpuses or to output the string.
|
||||
*
|
||||
*
|
||||
* @param output[] the string of the text in a byte array
|
||||
* @param p_pad optional, used to print with out the padding characters
|
||||
*/
|
||||
void printArray(byte output[],bool p_pad = true);
|
||||
|
||||
|
||||
/** Prints the array given.
|
||||
*
|
||||
*
|
||||
* This function prints the given array in Hexadecimal.
|
||||
*
|
||||
*
|
||||
* @param output[] the string of the text in a byte array
|
||||
* @param sizel the size of the array.
|
||||
*/
|
||||
void printArray(byte output[],int sizel);
|
||||
|
||||
|
||||
/** User friendly implementation of AES-CBC encryption.
|
||||
*
|
||||
*
|
||||
* @param *plain pointer to the plaintext
|
||||
* @param size_p size of the plaintext
|
||||
* @param *cipher pointer to the ciphertext
|
||||
@@ -250,9 +250,9 @@ class AES
|
||||
* @note The key will be stored in class variable.
|
||||
*/
|
||||
void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]);
|
||||
|
||||
|
||||
/** User friendly implementation of AES-CBC encryption.
|
||||
*
|
||||
*
|
||||
* @param *plain pointer to the plaintext
|
||||
* @param size_p size of the plaintext
|
||||
* @param *cipher pointer to the ciphertext
|
||||
@@ -261,9 +261,9 @@ class AES
|
||||
* @note The key will be stored in class variable.
|
||||
*/
|
||||
void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits);
|
||||
|
||||
|
||||
/** User friendly implementation of AES-CBC decryption.
|
||||
*
|
||||
*
|
||||
* @param *cipher pointer to the ciphertext
|
||||
* @param size_c size of the ciphertext
|
||||
* @param *plain pointer to the plaintext
|
||||
@@ -273,9 +273,9 @@ class AES
|
||||
* @note The key will be stored in class variable.
|
||||
*/
|
||||
void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]);
|
||||
|
||||
|
||||
/** User friendly implementation of AES-CBC decryption.
|
||||
*
|
||||
*
|
||||
* @param *cipher pointer to the ciphertext
|
||||
* @param size_c size of the ciphertext
|
||||
* @param *plain pointer to the plaintext
|
||||
@@ -285,27 +285,28 @@ class AES
|
||||
*/
|
||||
void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits);
|
||||
|
||||
#if defined(AES_LINUX)
|
||||
/**
|
||||
* used in linux in order to retrieve the time in milliseconds.
|
||||
*
|
||||
* @return returns the milliseconds in a double format.
|
||||
*/
|
||||
double millis();
|
||||
#endif
|
||||
private:
|
||||
int round ;/**< holds the number of rounds to be used. */
|
||||
byte key_sched [KEY_SCHEDULE_BYTES] ;/**< holds the pre-computed key for the encryption/decrpytion. */
|
||||
unsigned long long int IVC;/**< holds the initialization vector counter in numerical format. */
|
||||
byte iv[16];/**< holds the initialization vector that will be used in the cipher. */
|
||||
int pad;/**< holds the size of the padding. */
|
||||
int size;/**< hold the size of the plaintext to be ciphered */
|
||||
#if defined(AES_LINUX)
|
||||
#if defined(AES_LINUX)
|
||||
/**
|
||||
* used in linux in order to retrieve the time in milliseconds.
|
||||
*
|
||||
* @return returns the milliseconds in a double format.
|
||||
*/
|
||||
double millis();
|
||||
#endif
|
||||
private:
|
||||
int round ;/**< holds the number of rounds to be used. */
|
||||
byte key_sched [KEY_SCHEDULE_BYTES]
|
||||
;/**< holds the pre-computed key for the encryption/decrpytion. */
|
||||
unsigned long long int IVC;/**< holds the initialization vector counter in numerical format. */
|
||||
byte iv[16];/**< holds the initialization vector that will be used in the cipher. */
|
||||
int pad;/**< holds the size of the padding. */
|
||||
int size;/**< hold the size of the plaintext to be ciphered */
|
||||
#if defined(AES_LINUX)
|
||||
timeval tv;/**< holds the time value on linux */
|
||||
byte arr_pad[15];/**< holds the hexadecimal padding values on linux */
|
||||
#else
|
||||
#else
|
||||
byte arr_pad[15];// = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };/**< holds the hexadecimal padding values */
|
||||
#endif
|
||||
#endif
|
||||
} ;
|
||||
|
||||
|
||||
@@ -319,33 +320,33 @@ class AES
|
||||
* This is an example of how to use AES in CBC mode easily.
|
||||
* The text and keys can be either in HEX or String format.<br />
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example aes.cpp
|
||||
* <b>For Rasberry pi</b><br>
|
||||
* <b>Updated: spaniakos 2015 </b><br>
|
||||
*
|
||||
* This is an example of how to use AES in CBC mode easily.
|
||||
* The text and keys can be either in HEX or String format.<br />
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example test_vectors.pde
|
||||
* <b>For Arduino</b><br>
|
||||
* <b>Updated: spaniakos 2015 </b><br>
|
||||
*
|
||||
* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.<br />
|
||||
* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example test_vectors.cpp
|
||||
* <b>For Rasberry pi</b><br>
|
||||
* <b>Updated: spaniakos 2015 </b><br>
|
||||
*
|
||||
* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.<br />
|
||||
* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example aes.cpp
|
||||
* <b>For Rasberry pi</b><br>
|
||||
* <b>Updated: spaniakos 2015 </b><br>
|
||||
*
|
||||
* This is an example of how to use AES in CBC mode easily.
|
||||
* The text and keys can be either in HEX or String format.<br />
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example test_vectors.pde
|
||||
* <b>For Arduino</b><br>
|
||||
* <b>Updated: spaniakos 2015 </b><br>
|
||||
*
|
||||
* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.<br />
|
||||
* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example test_vectors.cpp
|
||||
* <b>For Rasberry pi</b><br>
|
||||
* <b>Updated: spaniakos 2015 </b><br>
|
||||
*
|
||||
* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.<br />
|
||||
* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup aeslib AES library for Arduino and Raspberry pi
|
||||
@@ -362,21 +363,21 @@ class AES
|
||||
*
|
||||
* @section Acknowledgements Acknowledgements
|
||||
* This is an AES library for the Arduino, based on tzikis's AES library, which you can find <a href= "https://github.com/tzikis/arduino">here:</a>.<br />
|
||||
* Tzikis library was based on scottmac`s library, which you can find <a href="https://github.com/scottmac/arduino">here:</a><br />
|
||||
*
|
||||
* Tzikis library was based on scottmac`s library, which you can find <a href="https://github.com/scottmac/arduino">here:</a><br />
|
||||
*
|
||||
* @section Installation Installation
|
||||
* <h3>Arduino</h3>
|
||||
* Create a folder named _AES_ in the _libraries_ folder inside your Arduino sketch folder. If the
|
||||
* Create a folder named _AES_ in the _libraries_ folder inside your Arduino sketch folder. If the
|
||||
* libraries folder doesn't exist, create it. Then copy everything inside. (re)launch the Arduino IDE.<br />
|
||||
* You're done. Time for a mojito
|
||||
*
|
||||
*
|
||||
* <h3>Raspberry pi</h3>
|
||||
* <b>install</b><br /><br />
|
||||
*
|
||||
*
|
||||
* sudo make install<br />
|
||||
* cd examples_Rpi<br />
|
||||
* make<br /><br />
|
||||
*
|
||||
*
|
||||
* <b>What to do after changes to the library</b><br /><br />
|
||||
* sudo make clean<br />
|
||||
* sudo make install<br />
|
||||
@@ -392,7 +393,7 @@ class AES
|
||||
* <b>How to start a sketch</b><br /><br />
|
||||
* cd examples_Rpi<br />
|
||||
* sudo ./\<sketch\><br /><br />
|
||||
*
|
||||
*
|
||||
* @section AesNews News
|
||||
*
|
||||
* If issues are discovered with the documentation, please report them <a href="https://github.com/spaniakos/spaniakos.github.io/issues"> here</a>
|
||||
@@ -411,6 +412,6 @@ class AES
|
||||
* - Arduino
|
||||
* - Intel Galileo support
|
||||
* - Raspberry Pi Support
|
||||
*
|
||||
*
|
||||
* - The library has not been tested to other boards, but it should suppport ATMega 328 based boards,Mega Boards,Arduino Due,ATTiny board
|
||||
*/
|
||||
|
||||
+17
-17
@@ -7,34 +7,34 @@
|
||||
|
||||
#if (defined(__linux) || defined(linux)) && !defined(__ARDUINO_X86__)
|
||||
|
||||
#define AES_LINUX
|
||||
#define AES_LINUX
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__ARDUINO_X86__) || (defined (__linux) || defined (linux))
|
||||
#undef PROGMEM
|
||||
#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||
#define pgm_read_byte(p) (*(p))
|
||||
typedef unsigned char byte;
|
||||
#define printf_P printf
|
||||
#define PSTR(x) (x)
|
||||
#undef PROGMEM
|
||||
#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||
#define pgm_read_byte(p) (*(p))
|
||||
typedef unsigned char byte;
|
||||
#define printf_P printf
|
||||
#define PSTR(x) (x)
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
#include <pgmspace.h>
|
||||
#include <pgmspace.h>
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define printf_P printf
|
||||
#define printf_P printf
|
||||
#else
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#define N_ROW 4
|
||||
|
||||
@@ -15,33 +15,33 @@ unsigned long long int my_iv = 01234567;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
printf("\n===testng mode\n") ;
|
||||
printf("\n===testng mode\n") ;
|
||||
|
||||
for (int i=0;i<1;i++){
|
||||
prekey_test () ;
|
||||
}
|
||||
for (int i=0; i<1; i++) {
|
||||
prekey_test () ;
|
||||
}
|
||||
}
|
||||
|
||||
void prekey (int bits)
|
||||
{
|
||||
byte iv [N_BLOCK] ;
|
||||
byte plain_p[sizeof(plain) + (N_BLOCK - (sizeof(plain) % 16)) - 1];
|
||||
byte cipher[sizeof(plain_p)];
|
||||
aes.do_aes_encrypt(plain,sizeof(plain),cipher,key,bits);
|
||||
aes.get_IV(iv);
|
||||
aes.do_aes_dencrypt(cipher,aes.get_size(),plain_p,key,bits,iv);
|
||||
//normally u have sizeof(cipher) but if its in the same sketch you cannot determin it dynamically
|
||||
byte iv [N_BLOCK] ;
|
||||
byte plain_p[sizeof(plain) + (N_BLOCK - (sizeof(plain) % 16)) - 1];
|
||||
byte cipher[sizeof(plain_p)];
|
||||
aes.do_aes_encrypt(plain,sizeof(plain),cipher,key,bits);
|
||||
aes.get_IV(iv);
|
||||
aes.do_aes_dencrypt(cipher,aes.get_size(),plain_p,key,bits,iv);
|
||||
//normally u have sizeof(cipher) but if its in the same sketch you cannot determin it dynamically
|
||||
|
||||
printf("\n\nPLAIN :");
|
||||
aes.printArray(plain);
|
||||
printf("\nCIPHER:");
|
||||
aes.printArray(cipher);
|
||||
printf("\nPlain2:");
|
||||
aes.printArray(plain_p);
|
||||
printf("\n============================================================\n");
|
||||
printf("\n\nPLAIN :");
|
||||
aes.printArray(plain);
|
||||
printf("\nCIPHER:");
|
||||
aes.printArray(cipher);
|
||||
printf("\nPlain2:");
|
||||
aes.printArray(plain_p);
|
||||
printf("\n============================================================\n");
|
||||
}
|
||||
|
||||
void prekey_test ()
|
||||
{
|
||||
prekey (128) ;
|
||||
prekey (128) ;
|
||||
}
|
||||
|
||||
@@ -18,108 +18,113 @@ void monte_carlo (int bits);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
printf ("AES library test vectors") ;
|
||||
printf ("AES library test vectors") ;
|
||||
|
||||
monte_carlo (128) ;
|
||||
monte_carlo (128) ;
|
||||
|
||||
for (int keysize = 128 ; keysize <= 256 ; keysize += 64)
|
||||
{
|
||||
prekey_test_var_plaintext (keysize) ;
|
||||
prekey_test_var_key (keysize) ;
|
||||
}
|
||||
for (int keysize = 128 ; keysize <= 256 ; keysize += 64) {
|
||||
prekey_test_var_plaintext (keysize) ;
|
||||
prekey_test_var_key (keysize) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void prekey_test_var_plaintext (int bits)
|
||||
{
|
||||
printf ("\nECB Varying Plaintext %i bits\n",bits) ;
|
||||
|
||||
byte succ ;
|
||||
set_bits (bits, key, 0) ; // all zero key
|
||||
succ = aes.set_key (key, bits) ;
|
||||
if (succ != SUCCESS)
|
||||
printf("Failure set_key\n") ;
|
||||
printf ("\nECB Varying Plaintext %i bits\n",bits) ;
|
||||
|
||||
byte succ ;
|
||||
set_bits (bits, key, 0) ; // all zero key
|
||||
succ = aes.set_key (key, bits) ;
|
||||
if (succ != SUCCESS) {
|
||||
printf("Failure set_key\n") ;
|
||||
}
|
||||
|
||||
|
||||
for (int bitcount = 1 ; bitcount <= 128 ; bitcount++)
|
||||
{
|
||||
printf ("COUNT = %i \n",bitcount-1);
|
||||
print_value ("KEY = ", key, bits) ;
|
||||
set_bits (128, plain, bitcount) ;
|
||||
|
||||
print_value ("PLAINTEXT = ", plain, 128) ;
|
||||
|
||||
succ = aes.encrypt (plain, cipher) ;
|
||||
if (succ != SUCCESS)
|
||||
printf ("Failure encrypt\n") ;
|
||||
for (int bitcount = 1 ; bitcount <= 128 ; bitcount++) {
|
||||
printf ("COUNT = %i \n",bitcount-1);
|
||||
print_value ("KEY = ", key, bits) ;
|
||||
set_bits (128, plain, bitcount) ;
|
||||
|
||||
print_value ("CIPHERTEXT = ", cipher, 128) ;
|
||||
|
||||
succ = aes.decrypt (cipher, check) ;
|
||||
if (succ != SUCCESS)
|
||||
printf ("Failure decrypt\n") ;
|
||||
print_value ("PLAINTEXT = ", plain, 128) ;
|
||||
|
||||
//print_value ("CHECK = ", check, 128) ;
|
||||
check_same (plain, check, 128) ;
|
||||
printf ("\n") ;
|
||||
}
|
||||
succ = aes.encrypt (plain, cipher) ;
|
||||
if (succ != SUCCESS) {
|
||||
printf ("Failure encrypt\n") ;
|
||||
}
|
||||
|
||||
print_value ("CIPHERTEXT = ", cipher, 128) ;
|
||||
|
||||
succ = aes.decrypt (cipher, check) ;
|
||||
if (succ != SUCCESS) {
|
||||
printf ("Failure decrypt\n") ;
|
||||
}
|
||||
|
||||
//print_value ("CHECK = ", check, 128) ;
|
||||
check_same (plain, check, 128) ;
|
||||
printf ("\n") ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void prekey_test_var_key (int bits)
|
||||
{
|
||||
printf ("\nECB Varying key %i bits\n",bits);
|
||||
|
||||
byte succ ;
|
||||
set_bits (128, plain, 0) ;
|
||||
printf ("\nECB Varying key %i bits\n",bits);
|
||||
|
||||
for (int bitcount = 1 ; bitcount <= bits ; bitcount++)
|
||||
{
|
||||
set_bits (bits, key, bitcount) ; // all zero key
|
||||
succ = aes.set_key (key, bits) ;
|
||||
if (succ != SUCCESS)
|
||||
printf ("Failure set_key\n") ;
|
||||
printf ("COUNT = %i\n",bitcount-1);
|
||||
print_value ("KEY = ", key, bits) ;
|
||||
byte succ ;
|
||||
set_bits (128, plain, 0) ;
|
||||
|
||||
print_value ("PLAINTEXT = ", plain, 128) ;
|
||||
for (int bitcount = 1 ; bitcount <= bits ; bitcount++) {
|
||||
set_bits (bits, key, bitcount) ; // all zero key
|
||||
succ = aes.set_key (key, bits) ;
|
||||
if (succ != SUCCESS) {
|
||||
printf ("Failure set_key\n") ;
|
||||
}
|
||||
printf ("COUNT = %i\n",bitcount-1);
|
||||
print_value ("KEY = ", key, bits) ;
|
||||
|
||||
succ = aes.encrypt (plain, cipher) ;
|
||||
if (succ != SUCCESS)
|
||||
printf ("Failure encrypt\n") ;
|
||||
print_value ("PLAINTEXT = ", plain, 128) ;
|
||||
|
||||
print_value ("CIPHERTEXT = ", cipher, 128) ;
|
||||
succ = aes.encrypt (plain, cipher) ;
|
||||
if (succ != SUCCESS) {
|
||||
printf ("Failure encrypt\n") ;
|
||||
}
|
||||
|
||||
succ = aes.decrypt (cipher, check) ;
|
||||
if (succ != SUCCESS)
|
||||
printf ("Failure decrypt\n") ;
|
||||
print_value ("CIPHERTEXT = ", cipher, 128) ;
|
||||
|
||||
check_same (plain, check, 128) ;
|
||||
printf("\n");
|
||||
}
|
||||
succ = aes.decrypt (cipher, check) ;
|
||||
if (succ != SUCCESS) {
|
||||
printf ("Failure decrypt\n") ;
|
||||
}
|
||||
|
||||
check_same (plain, check, 128) ;
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void set_bits (int bits, byte * a, int count)
|
||||
{
|
||||
bits >>= 3 ;
|
||||
byte bcount = count >> 3 ;
|
||||
for (byte i = 0 ; i < bcount ; i++)
|
||||
a [i] = 0xFF ;
|
||||
if ((count & 7) != 0)
|
||||
a [bcount++] = 0xFF & (0xFF00 >> (count & 7)) ;
|
||||
for (byte i = bcount ; i < bits ; i++)
|
||||
a [i] = 0x00 ;
|
||||
bits >>= 3 ;
|
||||
byte bcount = count >> 3 ;
|
||||
for (byte i = 0 ; i < bcount ; i++) {
|
||||
a [i] = 0xFF ;
|
||||
}
|
||||
if ((count & 7) != 0) {
|
||||
a [bcount++] = 0xFF & (0xFF00 >> (count & 7)) ;
|
||||
}
|
||||
for (byte i = bcount ; i < bits ; i++) {
|
||||
a [i] = 0x00 ;
|
||||
}
|
||||
}
|
||||
|
||||
void check_same (byte * a, byte * b, int bits)
|
||||
{
|
||||
bits >>= 3 ;
|
||||
for (byte i = 0 ; i < bits ; i++)
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
printf ("Failure plain != check\n") ;
|
||||
return ;
|
||||
}
|
||||
bits >>= 3 ;
|
||||
for (byte i = 0 ; i < bits ; i++)
|
||||
if (a[i] != b[i]) {
|
||||
printf ("Failure plain != check\n") ;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
char hex[] = "0123456789abcdef" ;
|
||||
@@ -127,57 +132,51 @@ char hex[] = "0123456789abcdef" ;
|
||||
|
||||
void print_value (const char * str, byte * a, int bits)
|
||||
{
|
||||
printf ("%s",str) ;
|
||||
bits >>= 3 ;
|
||||
for (int i = 0 ; i < bits ; i++)
|
||||
{
|
||||
byte b = a[i] ;
|
||||
printf("%c%c",hex[b >> 4],hex [b & 15]);
|
||||
//Serial.print (hex [b >> 4]) ;
|
||||
//Serial.print (hex [b & 15]) ;
|
||||
}
|
||||
printf("\n") ;
|
||||
printf ("%s",str) ;
|
||||
bits >>= 3 ;
|
||||
for (int i = 0 ; i < bits ; i++) {
|
||||
byte b = a[i] ;
|
||||
printf("%c%c",hex[b >> 4],hex [b & 15]);
|
||||
//Serial.print (hex [b >> 4]) ;
|
||||
//Serial.print (hex [b & 15]) ;
|
||||
}
|
||||
printf("\n") ;
|
||||
}
|
||||
|
||||
byte monteplain [] =
|
||||
{ 0xb9, 0x14, 0x5a, 0x76, 0x8b, 0x7d, 0xc4, 0x89,
|
||||
0xa0, 0x96, 0xb5, 0x46, 0xf4, 0x3b, 0x23, 0x1f } ;
|
||||
byte montekey [] =
|
||||
{ 0x13, 0x9a, 0x35, 0x42, 0x2f, 0x1d, 0x61, 0xde,
|
||||
0x3c, 0x91, 0x78, 0x7f, 0xe0, 0x50, 0x7a, 0xfd } ;
|
||||
byte monteplain [] = {
|
||||
0xb9, 0x14, 0x5a, 0x76, 0x8b, 0x7d, 0xc4, 0x89,
|
||||
0xa0, 0x96, 0xb5, 0x46, 0xf4, 0x3b, 0x23, 0x1f
|
||||
} ;
|
||||
byte montekey [] = {
|
||||
0x13, 0x9a, 0x35, 0x42, 0x2f, 0x1d, 0x61, 0xde,
|
||||
0x3c, 0x91, 0x78, 0x7f, 0xe0, 0x50, 0x7a, 0xfd
|
||||
} ;
|
||||
|
||||
void monte_carlo (int bits)
|
||||
{
|
||||
printf ("\nMonte Carlo %i bits\n",bits);
|
||||
byte succ;
|
||||
for (int i = 0 ; i < 16 ; i++)
|
||||
{
|
||||
plain [i] = monteplain [i] ;
|
||||
key [i] = montekey [i] ;
|
||||
}
|
||||
for (int i = 0 ; i < 100 ; i++)
|
||||
{
|
||||
printf ("COUNT = %i\n",i);
|
||||
print_value ("KEY = ", key, bits) ;
|
||||
print_value ("PLAINTEXT = ", plain, 128) ;
|
||||
succ = aes.set_key (key, bits) ;
|
||||
for (int j = 0 ; j < 1000 ; j++)
|
||||
{
|
||||
succ = aes.encrypt (plain, cipher) ;
|
||||
aes.copy_n_bytes (plain, cipher, 16) ;
|
||||
}
|
||||
print_value ("CIPHERTEXT = ", cipher, 128) ;
|
||||
printf("\n");
|
||||
if (bits == 128)
|
||||
{
|
||||
for (byte k = 0 ; k < 16 ; k++)
|
||||
key [k] ^= cipher [k] ;
|
||||
}
|
||||
else if (bits == 192)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
printf ("\nMonte Carlo %i bits\n",bits);
|
||||
byte succ;
|
||||
for (int i = 0 ; i < 16 ; i++) {
|
||||
plain [i] = monteplain [i] ;
|
||||
key [i] = montekey [i] ;
|
||||
}
|
||||
for (int i = 0 ; i < 100 ; i++) {
|
||||
printf ("COUNT = %i\n",i);
|
||||
print_value ("KEY = ", key, bits) ;
|
||||
print_value ("PLAINTEXT = ", plain, 128) ;
|
||||
succ = aes.set_key (key, bits) ;
|
||||
for (int j = 0 ; j < 1000 ; j++) {
|
||||
succ = aes.encrypt (plain, cipher) ;
|
||||
aes.copy_n_bytes (plain, cipher, 16) ;
|
||||
}
|
||||
print_value ("CIPHERTEXT = ", cipher, 128) ;
|
||||
printf("\n");
|
||||
if (bits == 128) {
|
||||
for (byte k = 0 ; k < 16 ; k++) {
|
||||
key [k] ^= cipher [k] ;
|
||||
}
|
||||
} else if (bits == 192) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-13
@@ -5,7 +5,7 @@
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
/* Galileo support from spaniakos <spaniakos@gmail.com> */
|
||||
/* Galileo support from spaniakos <spaniakos@gmail.com> */
|
||||
|
||||
/**
|
||||
* @file printf.h
|
||||
@@ -21,36 +21,36 @@
|
||||
|
||||
int serial_putc( char c, FILE * )
|
||||
{
|
||||
Serial.write( c );
|
||||
Serial.write( c );
|
||||
|
||||
return c;
|
||||
return c;
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
fdevopen( &serial_putc, 0 );
|
||||
fdevopen( &serial_putc, 0 );
|
||||
}
|
||||
|
||||
#elif defined (__arm__)
|
||||
|
||||
void printf_begin(void){}
|
||||
void printf_begin(void) {}
|
||||
|
||||
#elif defined(__ARDUINO_X86__)
|
||||
int serial_putc( char c, FILE * )
|
||||
{
|
||||
Serial.write( c );
|
||||
Serial.write( c );
|
||||
|
||||
return c;
|
||||
return c;
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
//JESUS - For reddirect stdout to /dev/ttyGS0 (Serial Monitor port)
|
||||
stdout = freopen("/dev/ttyGS0","w",stdout);
|
||||
delay(500);
|
||||
printf("redirecting to Serial...");
|
||||
|
||||
//JESUS -----------------------------------------------------------
|
||||
//JESUS - For reddirect stdout to /dev/ttyGS0 (Serial Monitor port)
|
||||
stdout = freopen("/dev/ttyGS0","w",stdout);
|
||||
delay(500);
|
||||
printf("redirecting to Serial...");
|
||||
|
||||
//JESUS -----------------------------------------------------------
|
||||
}
|
||||
#else
|
||||
#error This example is only for use on Arduino.
|
||||
|
||||
+408
-445
File diff suppressed because it is too large
Load Diff
@@ -244,8 +244,8 @@ void atsha204_idle(void);
|
||||
void atsha204_sleep(void);
|
||||
uint8_t atsha204_wakeup(uint8_t *response);
|
||||
uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
|
||||
uint8_t datalen1, uint8_t *data1, uint8_t tx_size,
|
||||
uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
|
||||
uint8_t datalen1, uint8_t *data1, uint8_t tx_size,
|
||||
uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
|
||||
uint8_t atsha204_getSerialNumber(uint8_t *response);
|
||||
|
||||
#endif
|
||||
|
||||
+142
-126
@@ -1,7 +1,7 @@
|
||||
#include <string.h>
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
#define PRIPSTR "%S"
|
||||
#include <avr/pgmspace.h>
|
||||
#define PRIPSTR "%S"
|
||||
#elif defined(ESP8266)
|
||||
#include <pgmspace.h>
|
||||
#endif
|
||||
@@ -9,132 +9,146 @@
|
||||
|
||||
|
||||
const uint32_t sha256K[] PROGMEM = {
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
|
||||
#define BUFFER_SIZE 64
|
||||
|
||||
const uint8_t sha256InitState[] PROGMEM = {
|
||||
0x67,0xe6,0x09,0x6a, // H0
|
||||
0x85,0xae,0x67,0xbb, // H1
|
||||
0x72,0xf3,0x6e,0x3c, // H2
|
||||
0x3a,0xf5,0x4f,0xa5, // H3
|
||||
0x7f,0x52,0x0e,0x51, // H4
|
||||
0x8c,0x68,0x05,0x9b, // H5
|
||||
0xab,0xd9,0x83,0x1f, // H6
|
||||
0x19,0xcd,0xe0,0x5b // H7
|
||||
0x67,0xe6,0x09,0x6a, // H0
|
||||
0x85,0xae,0x67,0xbb, // H1
|
||||
0x72,0xf3,0x6e,0x3c, // H2
|
||||
0x3a,0xf5,0x4f,0xa5, // H3
|
||||
0x7f,0x52,0x0e,0x51, // H4
|
||||
0x8c,0x68,0x05,0x9b, // H5
|
||||
0xab,0xd9,0x83,0x1f, // H6
|
||||
0x19,0xcd,0xe0,0x5b // H7
|
||||
};
|
||||
|
||||
void Sha256Class::init(void) {
|
||||
memcpy_P(state.b,sha256InitState,32);
|
||||
byteCount = 0;
|
||||
bufferOffset = 0;
|
||||
void Sha256Class::init(void)
|
||||
{
|
||||
memcpy_P(state.b,sha256InitState,32);
|
||||
byteCount = 0;
|
||||
bufferOffset = 0;
|
||||
}
|
||||
|
||||
uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits) {
|
||||
return ((number << (32-bits)) | (number >> bits));
|
||||
uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits)
|
||||
{
|
||||
return ((number << (32-bits)) | (number >> bits));
|
||||
}
|
||||
|
||||
void Sha256Class::hashBlock() {
|
||||
uint8_t i;
|
||||
uint32_t a,b,c,d,e,f,g,h,t1,t2;
|
||||
void Sha256Class::hashBlock()
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t a,b,c,d,e,f,g,h,t1,t2;
|
||||
|
||||
a=state.w[0];
|
||||
b=state.w[1];
|
||||
c=state.w[2];
|
||||
d=state.w[3];
|
||||
e=state.w[4];
|
||||
f=state.w[5];
|
||||
g=state.w[6];
|
||||
h=state.w[7];
|
||||
a=state.w[0];
|
||||
b=state.w[1];
|
||||
c=state.w[2];
|
||||
d=state.w[3];
|
||||
e=state.w[4];
|
||||
f=state.w[5];
|
||||
g=state.w[6];
|
||||
h=state.w[7];
|
||||
|
||||
for (i=0; i<64; i++) {
|
||||
if (i>=16) {
|
||||
t1 = buffer.w[i&15] + buffer.w[(i-7)&15];
|
||||
t2 = buffer.w[(i-2)&15];
|
||||
t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10);
|
||||
t2 = buffer.w[(i-15)&15];
|
||||
t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3);
|
||||
buffer.w[i&15] = t1;
|
||||
}
|
||||
t1 = h;
|
||||
t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e)
|
||||
t1 += g ^ (e & (g ^ f)); // Ch(e,f,g)
|
||||
t1 += pgm_read_dword(sha256K+i); // Ki
|
||||
t1 += buffer.w[i&15]; // Wi
|
||||
t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a)
|
||||
t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c)
|
||||
h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2;
|
||||
}
|
||||
state.w[0] += a;
|
||||
state.w[1] += b;
|
||||
state.w[2] += c;
|
||||
state.w[3] += d;
|
||||
state.w[4] += e;
|
||||
state.w[5] += f;
|
||||
state.w[6] += g;
|
||||
state.w[7] += h;
|
||||
for (i=0; i<64; i++) {
|
||||
if (i>=16) {
|
||||
t1 = buffer.w[i&15] + buffer.w[(i-7)&15];
|
||||
t2 = buffer.w[(i-2)&15];
|
||||
t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10);
|
||||
t2 = buffer.w[(i-15)&15];
|
||||
t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3);
|
||||
buffer.w[i&15] = t1;
|
||||
}
|
||||
t1 = h;
|
||||
t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e)
|
||||
t1 += g ^ (e & (g ^ f)); // Ch(e,f,g)
|
||||
t1 += pgm_read_dword(sha256K+i); // Ki
|
||||
t1 += buffer.w[i&15]; // Wi
|
||||
t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a)
|
||||
t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c)
|
||||
h=g;
|
||||
g=f;
|
||||
f=e;
|
||||
e=d+t1;
|
||||
d=c;
|
||||
c=b;
|
||||
b=a;
|
||||
a=t1+t2;
|
||||
}
|
||||
state.w[0] += a;
|
||||
state.w[1] += b;
|
||||
state.w[2] += c;
|
||||
state.w[3] += d;
|
||||
state.w[4] += e;
|
||||
state.w[5] += f;
|
||||
state.w[6] += g;
|
||||
state.w[7] += h;
|
||||
}
|
||||
|
||||
void Sha256Class::addUncounted(uint8_t data) {
|
||||
buffer.b[bufferOffset ^ 3] = data;
|
||||
bufferOffset++;
|
||||
if (bufferOffset == BUFFER_SIZE) {
|
||||
hashBlock();
|
||||
bufferOffset = 0;
|
||||
}
|
||||
void Sha256Class::addUncounted(uint8_t data)
|
||||
{
|
||||
buffer.b[bufferOffset ^ 3] = data;
|
||||
bufferOffset++;
|
||||
if (bufferOffset == BUFFER_SIZE) {
|
||||
hashBlock();
|
||||
bufferOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Sha256Class::write(uint8_t data) {
|
||||
++byteCount;
|
||||
addUncounted(data);
|
||||
void Sha256Class::write(uint8_t data)
|
||||
{
|
||||
++byteCount;
|
||||
addUncounted(data);
|
||||
}
|
||||
|
||||
void Sha256Class::pad() {
|
||||
// Implement SHA-256 padding (fips180-2 §5.1.1)
|
||||
void Sha256Class::pad()
|
||||
{
|
||||
// Implement SHA-256 padding (fips180-2 §5.1.1)
|
||||
|
||||
// Pad with 0x80 followed by 0x00 until the end of the block
|
||||
addUncounted(0x80);
|
||||
while (bufferOffset != 56) {
|
||||
// Pad with 0x80 followed by 0x00 until the end of the block
|
||||
addUncounted(0x80);
|
||||
while (bufferOffset != 56) {
|
||||
addUncounted(0x00);
|
||||
}
|
||||
|
||||
// Append length in the last 8 bytes
|
||||
addUncounted(0); // We're only using 32 bit lengths
|
||||
addUncounted(0); // But SHA-1 supports 64 bit lengths
|
||||
addUncounted(0); // So zero pad the top bits
|
||||
addUncounted(byteCount >> 29); // Shifting to multiply by 8
|
||||
addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as
|
||||
addUncounted(byteCount >> 13); // byte.
|
||||
addUncounted(byteCount >> 5);
|
||||
addUncounted(byteCount << 3);
|
||||
// Append length in the last 8 bytes
|
||||
addUncounted(0); // We're only using 32 bit lengths
|
||||
addUncounted(0); // But SHA-1 supports 64 bit lengths
|
||||
addUncounted(0); // So zero pad the top bits
|
||||
addUncounted(byteCount >> 29); // Shifting to multiply by 8
|
||||
addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as
|
||||
addUncounted(byteCount >> 13); // byte.
|
||||
addUncounted(byteCount >> 5);
|
||||
addUncounted(byteCount << 3);
|
||||
}
|
||||
|
||||
|
||||
uint8_t* Sha256Class::result(void) {
|
||||
// Pad to complete the last block
|
||||
pad();
|
||||
uint8_t* Sha256Class::result(void)
|
||||
{
|
||||
// Pad to complete the last block
|
||||
pad();
|
||||
|
||||
// Swap byte order back
|
||||
for (int i=0; i<8; i++) {
|
||||
uint32_t a,b;
|
||||
a=state.w[i];
|
||||
b=a<<24;
|
||||
b|=(a<<8) & 0x00ff0000;
|
||||
b|=(a>>8) & 0x0000ff00;
|
||||
b|=a>>24;
|
||||
state.w[i]=b;
|
||||
}
|
||||
// Swap byte order back
|
||||
for (int i=0; i<8; i++) {
|
||||
uint32_t a,b;
|
||||
a=state.w[i];
|
||||
b=a<<24;
|
||||
b|=(a<<8) & 0x00ff0000;
|
||||
b|=(a>>8) & 0x0000ff00;
|
||||
b|=a>>24;
|
||||
state.w[i]=b;
|
||||
}
|
||||
|
||||
// Return pointer to hash (20 characters)
|
||||
return state.b;
|
||||
// Return pointer to hash (20 characters)
|
||||
return state.b;
|
||||
}
|
||||
|
||||
#define HMAC_IPAD 0x36
|
||||
@@ -143,38 +157,40 @@ uint8_t* Sha256Class::result(void) {
|
||||
uint8_t keyBuffer[BLOCK_LENGTH]; // K0 in FIPS-198a
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
|
||||
void Sha256Class::initHmac(const uint8_t* key, int keyLength) {
|
||||
uint8_t i;
|
||||
memset(keyBuffer,0,BLOCK_LENGTH);
|
||||
if (keyLength > BLOCK_LENGTH) {
|
||||
// Hash long keys
|
||||
init();
|
||||
for (;keyLength--;) {
|
||||
void Sha256Class::initHmac(const uint8_t* key, int keyLength)
|
||||
{
|
||||
uint8_t i;
|
||||
memset(keyBuffer,0,BLOCK_LENGTH);
|
||||
if (keyLength > BLOCK_LENGTH) {
|
||||
// Hash long keys
|
||||
init();
|
||||
for (; keyLength--;) {
|
||||
write(*key++);
|
||||
}
|
||||
memcpy(keyBuffer,result(),HASH_LENGTH);
|
||||
} else {
|
||||
// Block length keys are used as is
|
||||
memcpy(keyBuffer,key,keyLength);
|
||||
}
|
||||
// Start inner hash
|
||||
init();
|
||||
for (i=0; i<BLOCK_LENGTH; i++) {
|
||||
write(keyBuffer[i] ^ HMAC_IPAD);
|
||||
}
|
||||
memcpy(keyBuffer,result(),HASH_LENGTH);
|
||||
} else {
|
||||
// Block length keys are used as is
|
||||
memcpy(keyBuffer,key,keyLength);
|
||||
}
|
||||
// Start inner hash
|
||||
init();
|
||||
for (i=0; i<BLOCK_LENGTH; i++) {
|
||||
write(keyBuffer[i] ^ HMAC_IPAD);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* Sha256Class::resultHmac(void) {
|
||||
uint8_t i;
|
||||
// Complete inner hash
|
||||
memcpy(innerHash,result(),HASH_LENGTH);
|
||||
// Calculate outer hash
|
||||
init();
|
||||
for (i=0; i<BLOCK_LENGTH; i++) {
|
||||
uint8_t* Sha256Class::resultHmac(void)
|
||||
{
|
||||
uint8_t i;
|
||||
// Complete inner hash
|
||||
memcpy(innerHash,result(),HASH_LENGTH);
|
||||
// Calculate outer hash
|
||||
init();
|
||||
for (i=0; i<BLOCK_LENGTH; i++) {
|
||||
write(keyBuffer[i] ^ HMAC_OPAD);
|
||||
}
|
||||
for (i=0; i<HASH_LENGTH; i++) {
|
||||
for (i=0; i<HASH_LENGTH; i++) {
|
||||
write(innerHash[i]);
|
||||
}
|
||||
return result();
|
||||
return result();
|
||||
}
|
||||
|
||||
+21
-21
@@ -8,33 +8,33 @@
|
||||
#define BLOCK_LENGTH 64
|
||||
|
||||
union _buffer {
|
||||
uint8_t b[BLOCK_LENGTH];
|
||||
uint32_t w[BLOCK_LENGTH/4];
|
||||
uint8_t b[BLOCK_LENGTH];
|
||||
uint32_t w[BLOCK_LENGTH/4];
|
||||
};
|
||||
union _state {
|
||||
uint8_t b[HASH_LENGTH];
|
||||
uint32_t w[HASH_LENGTH/4];
|
||||
uint8_t b[HASH_LENGTH];
|
||||
uint32_t w[HASH_LENGTH/4];
|
||||
};
|
||||
|
||||
class Sha256Class
|
||||
{
|
||||
public:
|
||||
void init(void);
|
||||
void initHmac(const uint8_t* secret, int secretLength);
|
||||
uint8_t* result(void);
|
||||
uint8_t* resultHmac(void);
|
||||
void write(uint8_t);
|
||||
private:
|
||||
void pad();
|
||||
void addUncounted(uint8_t data);
|
||||
void hashBlock();
|
||||
uint32_t ror32(uint32_t number, uint8_t bits);
|
||||
_buffer buffer;
|
||||
uint8_t bufferOffset;
|
||||
_state state;
|
||||
uint32_t byteCount;
|
||||
uint8_t keyBuffer[BLOCK_LENGTH];
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
public:
|
||||
void init(void);
|
||||
void initHmac(const uint8_t* secret, int secretLength);
|
||||
uint8_t* result(void);
|
||||
uint8_t* resultHmac(void);
|
||||
void write(uint8_t);
|
||||
private:
|
||||
void pad();
|
||||
void addUncounted(uint8_t data);
|
||||
void hashBlock();
|
||||
uint32_t ror32(uint32_t number, uint8_t bits);
|
||||
_buffer buffer;
|
||||
uint8_t bufferOffset;
|
||||
_state state;
|
||||
uint32_t byteCount;
|
||||
uint8_t keyBuffer[BLOCK_LENGTH];
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+444
-421
@@ -39,10 +39,10 @@
|
||||
* @brief struct for mapping digital pins
|
||||
*/
|
||||
struct pin_map_t {
|
||||
volatile uint8_t* ddr; /**< address of DDR for this pin */
|
||||
volatile uint8_t* pin; /**< address of PIN for this pin */
|
||||
volatile uint8_t* port; /**< address of PORT for this pin */
|
||||
uint8_t bit; /**< bit number for this pin */
|
||||
volatile uint8_t* ddr; /**< address of DDR for this pin */
|
||||
volatile uint8_t* pin; /**< address of PIN for this pin */
|
||||
volatile uint8_t* port; /**< address of PORT for this pin */
|
||||
uint8_t bit; /**< bit number for this pin */
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(__AVR_ATmega168__)\
|
||||
@@ -50,102 +50,102 @@ struct pin_map_t {
|
||||
||defined(__AVR_ATmega328P__)
|
||||
// 168 and 328 Arduinos
|
||||
const static pin_map_t pinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 8
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 9
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 10
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 11
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 12
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 13
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 14
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 15
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 16
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 17
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 18
|
||||
{&DDRC, &PINC, &PORTC, 5} // C5 19
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 8
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 9
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 10
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 11
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 12
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 13
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 14
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 15
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 16
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 17
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 18
|
||||
{&DDRC, &PINC, &PORTC, 5} // C5 19
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega1280__)\
|
||||
|| defined(__AVR_ATmega2560__)
|
||||
// Mega
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 0
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 1
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 2
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 3
|
||||
{&DDRG, &PING, &PORTG, 5}, // G5 4
|
||||
{&DDRE, &PINE, &PORTE, 3}, // E3 5
|
||||
{&DDRH, &PINH, &PORTH, 3}, // H3 6
|
||||
{&DDRH, &PINH, &PORTH, 4}, // H4 7
|
||||
{&DDRH, &PINH, &PORTH, 5}, // H5 8
|
||||
{&DDRH, &PINH, &PORTH, 6}, // H6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
|
||||
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
|
||||
{&DDRH, &PINH, &PORTH, 1}, // H1 16
|
||||
{&DDRH, &PINH, &PORTH, 0}, // H0 17
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 18
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 19
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 20
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 21
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 22
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 23
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 24
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 25
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 26
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 27
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 28
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 29
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 30
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 31
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 32
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 33
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 34
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 35
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 36
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 37
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 38
|
||||
{&DDRG, &PING, &PORTG, 2}, // G2 39
|
||||
{&DDRG, &PING, &PORTG, 1}, // G1 40
|
||||
{&DDRG, &PING, &PORTG, 0}, // G0 41
|
||||
{&DDRL, &PINL, &PORTL, 7}, // L7 42
|
||||
{&DDRL, &PINL, &PORTL, 6}, // L6 43
|
||||
{&DDRL, &PINL, &PORTL, 5}, // L5 44
|
||||
{&DDRL, &PINL, &PORTL, 4}, // L4 45
|
||||
{&DDRL, &PINL, &PORTL, 3}, // L3 46
|
||||
{&DDRL, &PINL, &PORTL, 2}, // L2 47
|
||||
{&DDRL, &PINL, &PORTL, 1}, // L1 48
|
||||
{&DDRL, &PINL, &PORTL, 0}, // L0 49
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 50
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 51
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 52
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 53
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 54
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 55
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 56
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 57
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 58
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 59
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 60
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 61
|
||||
{&DDRK, &PINK, &PORTK, 0}, // K0 62
|
||||
{&DDRK, &PINK, &PORTK, 1}, // K1 63
|
||||
{&DDRK, &PINK, &PORTK, 2}, // K2 64
|
||||
{&DDRK, &PINK, &PORTK, 3}, // K3 65
|
||||
{&DDRK, &PINK, &PORTK, 4}, // K4 66
|
||||
{&DDRK, &PINK, &PORTK, 5}, // K5 67
|
||||
{&DDRK, &PINK, &PORTK, 6}, // K6 68
|
||||
{&DDRK, &PINK, &PORTK, 7} // K7 69
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 0
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 1
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 2
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 3
|
||||
{&DDRG, &PING, &PORTG, 5}, // G5 4
|
||||
{&DDRE, &PINE, &PORTE, 3}, // E3 5
|
||||
{&DDRH, &PINH, &PORTH, 3}, // H3 6
|
||||
{&DDRH, &PINH, &PORTH, 4}, // H4 7
|
||||
{&DDRH, &PINH, &PORTH, 5}, // H5 8
|
||||
{&DDRH, &PINH, &PORTH, 6}, // H6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
|
||||
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
|
||||
{&DDRH, &PINH, &PORTH, 1}, // H1 16
|
||||
{&DDRH, &PINH, &PORTH, 0}, // H0 17
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 18
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 19
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 20
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 21
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 22
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 23
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 24
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 25
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 26
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 27
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 28
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 29
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 30
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 31
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 32
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 33
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 34
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 35
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 36
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 37
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 38
|
||||
{&DDRG, &PING, &PORTG, 2}, // G2 39
|
||||
{&DDRG, &PING, &PORTG, 1}, // G1 40
|
||||
{&DDRG, &PING, &PORTG, 0}, // G0 41
|
||||
{&DDRL, &PINL, &PORTL, 7}, // L7 42
|
||||
{&DDRL, &PINL, &PORTL, 6}, // L6 43
|
||||
{&DDRL, &PINL, &PORTL, 5}, // L5 44
|
||||
{&DDRL, &PINL, &PORTL, 4}, // L4 45
|
||||
{&DDRL, &PINL, &PORTL, 3}, // L3 46
|
||||
{&DDRL, &PINL, &PORTL, 2}, // L2 47
|
||||
{&DDRL, &PINL, &PORTL, 1}, // L1 48
|
||||
{&DDRL, &PINL, &PORTL, 0}, // L0 49
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 50
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 51
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 52
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 53
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 54
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 55
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 56
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 57
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 58
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 59
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 60
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 61
|
||||
{&DDRK, &PINK, &PORTK, 0}, // K0 62
|
||||
{&DDRK, &PINK, &PORTK, 1}, // K1 63
|
||||
{&DDRK, &PINK, &PORTK, 2}, // K2 64
|
||||
{&DDRK, &PINK, &PORTK, 3}, // K3 65
|
||||
{&DDRK, &PINK, &PORTK, 4}, // K4 66
|
||||
{&DDRK, &PINK, &PORTK, 5}, // K5 67
|
||||
{&DDRK, &PINK, &PORTK, 6}, // K6 68
|
||||
{&DDRK, &PINK, &PORTK, 7} // K7 69
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega1284P__)\
|
||||
@@ -160,110 +160,110 @@ static const pin_map_t pinMap[] = {
|
||||
#ifdef defined(VARIANT_MIGHTY)
|
||||
// Mighty Layout
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 24
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 25
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 26
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 27
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 28
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 29
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 30
|
||||
{&DDRA, &PINA, &PORTA, 7} // A7 31
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 24
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 25
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 26
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 27
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 28
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 29
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 30
|
||||
{&DDRA, &PINA, &PORTA, 7} // A7 31
|
||||
};
|
||||
#elif defined(VARIANT_BOBUINO)
|
||||
// Bobuino Layout
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 4
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 5
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 6
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 7
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 8
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 14
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 15
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 16
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 17
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 18
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 19
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 20
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 21
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 22
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 23
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 24
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 25
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 26
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 27
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 28
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 29
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 30
|
||||
{&DDRD, &PIND, &PORTD, 7} // D7 31
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 4
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 5
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 6
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 7
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 8
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 14
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 15
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 16
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 17
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 18
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 19
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 20
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 21
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 22
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 23
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 24
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 25
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 26
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 27
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 28
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 29
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 30
|
||||
{&DDRD, &PIND, &PORTD, 7} // D7 31
|
||||
};
|
||||
#elif defined(VARIANT_STANDARD)
|
||||
// Standard Layout
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 24
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 25
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 26
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 27
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 28
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 29
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 30
|
||||
{&DDRA, &PINA, &PORTA, 0} // A0 31
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 24
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 25
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 26
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 27
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 28
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 29
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 30
|
||||
{&DDRA, &PINA, &PORTA, 0} // A0 31
|
||||
};
|
||||
#else // VARIANT_MIGHTY
|
||||
#error Undefined variant 1284, 644, 324, 64, 32
|
||||
@@ -273,66 +273,66 @@ static const pin_map_t pinMap[] = {
|
||||
#ifdef CORE_TEENSY
|
||||
// Teensy 2.0
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 4
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 5
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 6
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 7
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 8
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 9
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 10
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 11
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 12
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 13
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 14
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 15
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 16
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 17
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 18
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 19
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 20
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 21
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 22
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 23
|
||||
{&DDRE, &PINE, &PORTE, 6} // E6 24
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 4
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 5
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 6
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 7
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 8
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 9
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 10
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 11
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 12
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 13
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 14
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 15
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 16
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 17
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 18
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 19
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 20
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 21
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 22
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 23
|
||||
{&DDRE, &PINE, &PORTE, 6} // E6 24
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#else // CORE_TEENSY
|
||||
// Leonardo
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 0
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 1
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 2
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 5
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 6
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 7
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 8
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 9
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 10
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 11
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 12
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 13
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 14
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 15
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 16
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 17
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 18
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 19
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 20
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 21
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 22
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 23
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 24
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 25
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 26
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 27
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 28
|
||||
{&DDRD, &PIND, &PORTD, 6} // D6 29
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 0
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 1
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 2
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 5
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 6
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 7
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 8
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 9
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 10
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 11
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 12
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 13
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 14
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 15
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 16
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 17
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 18
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 19
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 20
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 21
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 22
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 23
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 24
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 25
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 26
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 27
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 28
|
||||
{&DDRD, &PIND, &PORTD, 6} // D6 29
|
||||
};
|
||||
#endif // CORE_TEENSY
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -340,52 +340,52 @@ static const pin_map_t pinMap[] = {
|
||||
|| defined(__AVR_AT90USB1286__)
|
||||
// Teensy++ 1.0 & 2.0
|
||||
static const pin_map_t pinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 8
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 9
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 10
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 11
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 12
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 13
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 14
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 15
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 16
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 17
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 18
|
||||
{&DDRE, &PINE, &PORTE, 7}, // E7 19
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 20
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 21
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 22
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 23
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 24
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 25
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 26
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 27
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 28
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 29
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 30
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 31
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 32
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 33
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 34
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 35
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 36
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 37
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 38
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 39
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 40
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 41
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 42
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 43
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 44
|
||||
{&DDRF, &PINF, &PORTF, 7} // F7 45
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 8
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 9
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 10
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 11
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 12
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 13
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 14
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 15
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 16
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 17
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 18
|
||||
{&DDRE, &PINE, &PORTE, 7}, // E7 19
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 20
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 21
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 22
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 23
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 24
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 25
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 26
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 27
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 28
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 29
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 30
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 31
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 32
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 33
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 34
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 35
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 36
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 37
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 38
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 39
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 40
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 41
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 42
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 43
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 44
|
||||
{&DDRF, &PINF, &PORTF, 7} // F7 45
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#else // CPU type
|
||||
@@ -397,15 +397,16 @@ static const uint8_t digitalPinCount = sizeof(pinMap)/sizeof(pin_map_t);
|
||||
//==============================================================================
|
||||
/** generate bad pin number error */
|
||||
void badPinNumber(void)
|
||||
__attribute__((error("Pin number is too large or not a constant")));
|
||||
__attribute__((error("Pin number is too large or not a constant")));
|
||||
//------------------------------------------------------------------------------
|
||||
/** Check for valid pin number
|
||||
* @param[in] pin Number of pin to be checked.
|
||||
*/
|
||||
static ALWAYS_INLINE void badPinCheck(uint8_t pin) {
|
||||
if (!__builtin_constant_p(pin) || pin >= digitalPinCount) {
|
||||
badPinNumber();
|
||||
}
|
||||
static ALWAYS_INLINE void badPinCheck(uint8_t pin)
|
||||
{
|
||||
if (!__builtin_constant_p(pin) || pin >= digitalPinCount) {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** fast write helper
|
||||
@@ -413,29 +414,31 @@ static ALWAYS_INLINE void badPinCheck(uint8_t pin) {
|
||||
* @param[in] bit bit number to write
|
||||
* @param[in] level value for bit
|
||||
*/
|
||||
static ALWAYS_INLINE void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level) {
|
||||
uint8_t oldSREG;
|
||||
if (address > (uint8_t*)0X5F) {
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
}
|
||||
if (level) {
|
||||
*address |= 1 << bit;
|
||||
} else {
|
||||
*address &= ~(1 << bit);
|
||||
}
|
||||
if (address > (uint8_t*)0X5F) {
|
||||
SREG = oldSREG;
|
||||
}
|
||||
static ALWAYS_INLINE void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level)
|
||||
{
|
||||
uint8_t oldSREG;
|
||||
if (address > (uint8_t*)0X5F) {
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
}
|
||||
if (level) {
|
||||
*address |= 1 << bit;
|
||||
} else {
|
||||
*address &= ~(1 << bit);
|
||||
}
|
||||
if (address > (uint8_t*)0X5F) {
|
||||
SREG = oldSREG;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** read pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return value read
|
||||
*/
|
||||
static ALWAYS_INLINE bool fastDigitalRead(uint8_t pin) {
|
||||
badPinCheck(pin);
|
||||
return (*pinMap[pin].pin >> pinMap[pin].bit) & 1;
|
||||
static ALWAYS_INLINE bool fastDigitalRead(uint8_t pin)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
return (*pinMap[pin].pin >> pinMap[pin].bit) & 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** toggle a pin
|
||||
@@ -444,24 +447,26 @@ static ALWAYS_INLINE bool fastDigitalRead(uint8_t pin) {
|
||||
* If the pin is in output mode toggle the pin level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
static ALWAYS_INLINE void fastDigitalToggle(uint8_t pin) {
|
||||
badPinCheck(pin);
|
||||
if (pinMap[pin].pin > (uint8_t*)0X5F) {
|
||||
// must write bit to high address port
|
||||
*pinMap[pin].pin = 1 << pinMap[pin].bit;
|
||||
} else {
|
||||
// will compile to sbi and PIN register will not be read.
|
||||
*pinMap[pin].pin |= 1 << pinMap[pin].bit;
|
||||
}
|
||||
static ALWAYS_INLINE void fastDigitalToggle(uint8_t pin)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
if (pinMap[pin].pin > (uint8_t*)0X5F) {
|
||||
// must write bit to high address port
|
||||
*pinMap[pin].pin = 1 << pinMap[pin].bit;
|
||||
} else {
|
||||
// will compile to sbi and PIN register will not be read.
|
||||
*pinMap[pin].pin |= 1 << pinMap[pin].bit;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] level value to write
|
||||
*/
|
||||
static ALWAYS_INLINE void fastDigitalWrite(uint8_t pin, bool level) {
|
||||
badPinCheck(pin);
|
||||
fastBitWriteSafe(pinMap[pin].port, pinMap[pin].bit, level);
|
||||
static ALWAYS_INLINE void fastDigitalWrite(uint8_t pin, bool level)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
fastBitWriteSafe(pinMap[pin].port, pinMap[pin].bit, level);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** set pin mode
|
||||
@@ -470,9 +475,10 @@ static ALWAYS_INLINE void fastDigitalWrite(uint8_t pin, bool level) {
|
||||
*
|
||||
* fastPinMode does not enable or disable the 20K pullup for input mode.
|
||||
*/
|
||||
static ALWAYS_INLINE void fastPinMode(uint8_t pin, bool mode) {
|
||||
badPinCheck(pin);
|
||||
fastBitWriteSafe(pinMap[pin].ddr, pinMap[pin].bit, mode);
|
||||
static ALWAYS_INLINE void fastPinMode(uint8_t pin, bool mode)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
fastBitWriteSafe(pinMap[pin].ddr, pinMap[pin].bit, mode);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** set pin configuration
|
||||
@@ -481,9 +487,10 @@ static ALWAYS_INLINE void fastPinMode(uint8_t pin, bool mode) {
|
||||
* @param[in] level If mode is output, set level high/low.
|
||||
* If mode is input, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
static ALWAYS_INLINE void fastPinConfig(uint8_t pin, bool mode, bool level) {
|
||||
fastPinMode(pin, mode);
|
||||
fastDigitalWrite(pin, level);
|
||||
static ALWAYS_INLINE void fastPinConfig(uint8_t pin, bool mode, bool level)
|
||||
{
|
||||
fastPinMode(pin, mode);
|
||||
fastDigitalWrite(pin, level);
|
||||
}
|
||||
//==============================================================================
|
||||
/**
|
||||
@@ -491,96 +498,112 @@ static ALWAYS_INLINE void fastPinConfig(uint8_t pin, bool mode, bool level) {
|
||||
* @brief Fast AVR digital port I/O
|
||||
*/
|
||||
template<uint8_t PinNumber>
|
||||
class DigitalPin {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor */
|
||||
DigitalPin() {}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor
|
||||
* @param[in] pinMode if true set output mode else input mode.
|
||||
*/
|
||||
explicit DigitalPin(bool pinMode) {
|
||||
mode(pinMode);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor
|
||||
* @param[in] mode If true set output mode else input mode
|
||||
* @param[in] level If mode is output, set level high/low.
|
||||
* If mode is input, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
DigitalPin(bool mode, bool level) {
|
||||
config(mode, level);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Asignment operator
|
||||
* @param[in] value If true set the pin's level high else set the
|
||||
* pin's level low.
|
||||
*
|
||||
* @return This DigitalPin instance.
|
||||
*/
|
||||
inline DigitalPin & operator = (bool value) __attribute__((always_inline)) {
|
||||
write(value);
|
||||
return *this;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Parenthesis operator
|
||||
* @return Pin's level
|
||||
*/
|
||||
inline operator bool () const __attribute__((always_inline)) {
|
||||
return read();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** set pin configuration
|
||||
* @param[in] mode If true set output mode else input mode
|
||||
* @param[in] level If mode is output, set level high/low.
|
||||
* If mode is input, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
ALWAYS_INLINE void config(bool mode, bool level) {
|
||||
fastPinConfig(PinNumber, mode, level);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||
*/
|
||||
ALWAYS_INLINE void high() {write(true);}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||
*/
|
||||
ALWAYS_INLINE void low() {write(false);}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin mode
|
||||
* @param[in] pinMode if true set output mode else input mode.
|
||||
*
|
||||
* mode() does not enable or disable the 20K pullup for input mode.
|
||||
*/
|
||||
ALWAYS_INLINE void mode(bool pinMode) {
|
||||
fastPinMode(PinNumber, pinMode);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** @return Pin's level */
|
||||
ALWAYS_INLINE bool read() const {
|
||||
return fastDigitalRead(PinNumber);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** toggle a pin
|
||||
*
|
||||
* If the pin is in output mode toggle the pin's level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
ALWAYS_INLINE void toggle() {
|
||||
fastDigitalToggle(PinNumber);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Write the pin's level.
|
||||
* @param[in] value If true set the pin's level high else set the
|
||||
* pin's level low.
|
||||
*/
|
||||
ALWAYS_INLINE void write(bool value) {
|
||||
fastDigitalWrite(PinNumber, value);
|
||||
}
|
||||
class DigitalPin
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor */
|
||||
DigitalPin() {}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor
|
||||
* @param[in] pinMode if true set output mode else input mode.
|
||||
*/
|
||||
explicit DigitalPin(bool pinMode)
|
||||
{
|
||||
mode(pinMode);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor
|
||||
* @param[in] mode If true set output mode else input mode
|
||||
* @param[in] level If mode is output, set level high/low.
|
||||
* If mode is input, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
DigitalPin(bool mode, bool level)
|
||||
{
|
||||
config(mode, level);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Asignment operator
|
||||
* @param[in] value If true set the pin's level high else set the
|
||||
* pin's level low.
|
||||
*
|
||||
* @return This DigitalPin instance.
|
||||
*/
|
||||
inline DigitalPin & operator = (bool value) __attribute__((always_inline))
|
||||
{
|
||||
write(value);
|
||||
return *this;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Parenthesis operator
|
||||
* @return Pin's level
|
||||
*/
|
||||
inline operator bool () const __attribute__((always_inline))
|
||||
{
|
||||
return read();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** set pin configuration
|
||||
* @param[in] mode If true set output mode else input mode
|
||||
* @param[in] level If mode is output, set level high/low.
|
||||
* If mode is input, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
ALWAYS_INLINE void config(bool mode, bool level)
|
||||
{
|
||||
fastPinConfig(PinNumber, mode, level);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||
*/
|
||||
ALWAYS_INLINE void high()
|
||||
{
|
||||
write(true);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||
*/
|
||||
ALWAYS_INLINE void low()
|
||||
{
|
||||
write(false);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin mode
|
||||
* @param[in] pinMode if true set output mode else input mode.
|
||||
*
|
||||
* mode() does not enable or disable the 20K pullup for input mode.
|
||||
*/
|
||||
ALWAYS_INLINE void mode(bool pinMode)
|
||||
{
|
||||
fastPinMode(PinNumber, pinMode);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** @return Pin's level */
|
||||
ALWAYS_INLINE bool read() const
|
||||
{
|
||||
return fastDigitalRead(PinNumber);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** toggle a pin
|
||||
*
|
||||
* If the pin is in output mode toggle the pin's level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
ALWAYS_INLINE void toggle()
|
||||
{
|
||||
fastDigitalToggle(PinNumber);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Write the pin's level.
|
||||
* @param[in] value If true set the pin's level high else set the
|
||||
* pin's level low.
|
||||
*/
|
||||
ALWAYS_INLINE void write(bool value)
|
||||
{
|
||||
fastDigitalWrite(PinNumber, value);
|
||||
}
|
||||
};
|
||||
#endif // DigitalPin_h
|
||||
/** @} */
|
||||
@@ -32,22 +32,26 @@
|
||||
/** Constructor
|
||||
* @param[in] pin Pin assigned to this object.
|
||||
*/
|
||||
PinIO::PinIO(uint8_t pin) {
|
||||
begin(pin);
|
||||
PinIO::PinIO(uint8_t pin)
|
||||
{
|
||||
begin(pin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Initialize pin bit mask and port address.
|
||||
* @param[in] pin Arduino board pin number.
|
||||
* @return true for success or false if invalid pin number.
|
||||
*/
|
||||
bool PinIO::begin(uint8_t pin) {
|
||||
if (pin >= NUM_DIGITAL_PINS) return false;
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
pinReg_ = portInputRegister(port);
|
||||
bit_ = digitalPinToBitMask(pin);
|
||||
mask_ = ~bit_;
|
||||
portReg_ = pinReg_ + 2;
|
||||
return true;
|
||||
bool PinIO::begin(uint8_t pin)
|
||||
{
|
||||
if (pin >= NUM_DIGITAL_PINS) {
|
||||
return false;
|
||||
}
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
pinReg_ = portInputRegister(port);
|
||||
bit_ = digitalPinToBitMask(pin);
|
||||
mask_ = ~bit_;
|
||||
portReg_ = pinReg_ + 2;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Configure the pin
|
||||
@@ -59,10 +63,11 @@ bool PinIO::begin(uint8_t pin) {
|
||||
* This function may be used with interrupts enabled or disabled.
|
||||
* The previous interrupt state will be restored.
|
||||
*/
|
||||
void PinIO::config(bool mode, bool data) {
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
modeI(mode);
|
||||
writeI(data);
|
||||
}
|
||||
void PinIO::config(bool mode, bool data)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
modeI(mode);
|
||||
writeI(data);
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
|
||||
+147
-112
@@ -37,118 +37,153 @@
|
||||
* @class PinIO
|
||||
* @brief AVR port I/O with runtime pin numbers.
|
||||
*/
|
||||
class PinIO {
|
||||
public:
|
||||
/** Create a PinIO object with no assigned pin. */
|
||||
PinIO() : bit_(0), mask_(0XFF) {}
|
||||
/** Constructor
|
||||
* @param[in] pin Pin assigned to this object.
|
||||
*/
|
||||
explicit PinIO(uint8_t pin);
|
||||
/** Initialize pin bit mask and port address.
|
||||
* @param[in] pin Arduino board pin number.
|
||||
* @return true for success or false if invalid pin number.
|
||||
*/
|
||||
bool begin(uint8_t pin);
|
||||
/** Configure the pin
|
||||
*
|
||||
* @param[in] mode Configure as output mode if true else input mode.
|
||||
* @param[in] data For output mode set pin high if true else low.
|
||||
* For input mode enable 20K pullup if true else Hi-Z.
|
||||
*
|
||||
* This function may be used with interrupts enabled or disabled.
|
||||
* The previous interrupt state will be restored.
|
||||
*/
|
||||
void config(bool mode, bool data);
|
||||
//----------------------------------------------------------------------------
|
||||
/** @return Pin's level */
|
||||
ALWAYS_INLINE bool read() {return *pinReg_ & bit_;}
|
||||
//----------------------------------------------------------------------------
|
||||
/** toggle a pin
|
||||
*
|
||||
* If the pin is in output mode toggle the pin's level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
ALWAYS_INLINE void toggle() {*pinReg_ = bit_;}
|
||||
//============================================================================
|
||||
/**
|
||||
* Set pin high if output mode or enable 20K pullup if input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void highI() {writeI(1);}
|
||||
/**
|
||||
* Set pin low if output mode or disable 20K pullup if input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void lowI() {writeI(0);}
|
||||
/**
|
||||
* Set pin mode
|
||||
* @param[in] mode if true set output mode else input mode.
|
||||
*
|
||||
* mode() does not enable or disable the 20K pullup for input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void modeI(bool mode) {
|
||||
volatile uint8_t* ddrReg = pinReg_ + 1;
|
||||
*ddrReg = mode ? *ddrReg | bit_ : *ddrReg & mask_;
|
||||
}
|
||||
/** Write pin.
|
||||
*
|
||||
* @param[in] level If output mode set pin high if true else low.
|
||||
* If input mode enable 20K pullup if true else disable pullup.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void writeI(bool level) {
|
||||
*portReg_ = level ? *portReg_ | bit_ : *portReg_ & mask_;
|
||||
}
|
||||
//============================================================================
|
||||
/**
|
||||
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void high() {ATOMIC_BLOCK(ATOMIC_FORCEON) {highI();}}
|
||||
/**
|
||||
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void low() {ATOMIC_BLOCK(ATOMIC_FORCEON) {lowI();}}
|
||||
/**
|
||||
* Set pin mode
|
||||
* @param[in] pinMode if true set output mode else input mode.
|
||||
*
|
||||
* mode() does not enable or disable the 20K pullup for input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void mode(bool pinMode) {ATOMIC_BLOCK(ATOMIC_FORCEON) {modeI(pinMode);}}
|
||||
/** Write pin.
|
||||
*
|
||||
* @param[in] level If output mode set pin high if true else low.
|
||||
* If input mode enable 20K pullup if true else disable pullup.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void write(bool level) {ATOMIC_BLOCK(ATOMIC_FORCEON) {writeI(level);}}
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
uint8_t bit_;
|
||||
uint8_t mask_;
|
||||
volatile uint8_t* pinReg_;
|
||||
volatile uint8_t* portReg_;
|
||||
class PinIO
|
||||
{
|
||||
public:
|
||||
/** Create a PinIO object with no assigned pin. */
|
||||
PinIO() : bit_(0), mask_(0XFF) {}
|
||||
/** Constructor
|
||||
* @param[in] pin Pin assigned to this object.
|
||||
*/
|
||||
explicit PinIO(uint8_t pin);
|
||||
/** Initialize pin bit mask and port address.
|
||||
* @param[in] pin Arduino board pin number.
|
||||
* @return true for success or false if invalid pin number.
|
||||
*/
|
||||
bool begin(uint8_t pin);
|
||||
/** Configure the pin
|
||||
*
|
||||
* @param[in] mode Configure as output mode if true else input mode.
|
||||
* @param[in] data For output mode set pin high if true else low.
|
||||
* For input mode enable 20K pullup if true else Hi-Z.
|
||||
*
|
||||
* This function may be used with interrupts enabled or disabled.
|
||||
* The previous interrupt state will be restored.
|
||||
*/
|
||||
void config(bool mode, bool data);
|
||||
//----------------------------------------------------------------------------
|
||||
/** @return Pin's level */
|
||||
ALWAYS_INLINE bool read()
|
||||
{
|
||||
return *pinReg_ & bit_;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** toggle a pin
|
||||
*
|
||||
* If the pin is in output mode toggle the pin's level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
ALWAYS_INLINE void toggle()
|
||||
{
|
||||
*pinReg_ = bit_;
|
||||
}
|
||||
//============================================================================
|
||||
/**
|
||||
* Set pin high if output mode or enable 20K pullup if input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void highI()
|
||||
{
|
||||
writeI(1);
|
||||
}
|
||||
/**
|
||||
* Set pin low if output mode or disable 20K pullup if input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void lowI()
|
||||
{
|
||||
writeI(0);
|
||||
}
|
||||
/**
|
||||
* Set pin mode
|
||||
* @param[in] mode if true set output mode else input mode.
|
||||
*
|
||||
* mode() does not enable or disable the 20K pullup for input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void modeI(bool mode)
|
||||
{
|
||||
volatile uint8_t* ddrReg = pinReg_ + 1;
|
||||
*ddrReg = mode ? *ddrReg | bit_ : *ddrReg & mask_;
|
||||
}
|
||||
/** Write pin.
|
||||
*
|
||||
* @param[in] level If output mode set pin high if true else low.
|
||||
* If input mode enable 20K pullup if true else disable pullup.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
ALWAYS_INLINE void writeI(bool level)
|
||||
{
|
||||
*portReg_ = level ? *portReg_ | bit_ : *portReg_ & mask_;
|
||||
}
|
||||
//============================================================================
|
||||
/**
|
||||
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void high()
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
highI();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void low()
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
lowI();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set pin mode
|
||||
* @param[in] pinMode if true set output mode else input mode.
|
||||
*
|
||||
* mode() does not enable or disable the 20K pullup for input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void mode(bool pinMode)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
modeI(pinMode);
|
||||
}
|
||||
}
|
||||
/** Write pin.
|
||||
*
|
||||
* @param[in] level If output mode set pin high if true else low.
|
||||
* If input mode enable 20K pullup if true else disable pullup.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
ALWAYS_INLINE void write(bool level)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
writeI(level);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
uint8_t bit_;
|
||||
uint8_t mask_;
|
||||
volatile uint8_t* pinReg_;
|
||||
volatile uint8_t* portReg_;
|
||||
};
|
||||
#endif // PinIO_h
|
||||
/** @} */
|
||||
@@ -49,16 +49,17 @@
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool I2cMasterBase::transfer(uint8_t addrRW,
|
||||
void *buf, size_t nbytes, uint8_t option) {
|
||||
if (_state != STATE_REP_START) {
|
||||
start();
|
||||
}
|
||||
if (!write(addrRW)) {
|
||||
_state = addrRW & I2C_READ ? STATE_RX_ADDR_NACK : STATE_TX_ADDR_NACK;
|
||||
return false;
|
||||
}
|
||||
_state = addrRW & I2C_READ ? STATE_RX_DATA : STATE_TX_DATA;
|
||||
return transferContinue(buf, nbytes, option);
|
||||
void *buf, size_t nbytes, uint8_t option)
|
||||
{
|
||||
if (_state != STATE_REP_START) {
|
||||
start();
|
||||
}
|
||||
if (!write(addrRW)) {
|
||||
_state = addrRW & I2C_READ ? STATE_RX_ADDR_NACK : STATE_TX_ADDR_NACK;
|
||||
return false;
|
||||
}
|
||||
_state = addrRW & I2C_READ ? STATE_RX_DATA : STATE_TX_DATA;
|
||||
return transferContinue(buf, nbytes, option);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
@@ -76,30 +77,31 @@ bool I2cMasterBase::transfer(uint8_t addrRW,
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option) {
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
|
||||
if (_state == STATE_RX_DATA) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
p[i] = read(i == (nbytes - 1) && option != I2C_CONTINUE);
|
||||
}
|
||||
} else if (_state == STATE_TX_DATA) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
if (!write(p[i])) {
|
||||
_state = STATE_TX_DATA_NACK;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (option == I2C_STOP) {
|
||||
stop();
|
||||
_state = STATE_STOP;
|
||||
} else if (option == I2C_REP_START) {
|
||||
start();
|
||||
_state = STATE_STOP;
|
||||
}
|
||||
return true;
|
||||
bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option)
|
||||
{
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
|
||||
if (_state == STATE_RX_DATA) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
p[i] = read(i == (nbytes - 1) && option != I2C_CONTINUE);
|
||||
}
|
||||
} else if (_state == STATE_TX_DATA) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
if (!write(p[i])) {
|
||||
_state = STATE_TX_DATA_NACK;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (option == I2C_STOP) {
|
||||
stop();
|
||||
_state = STATE_STOP;
|
||||
} else if (option == I2C_REP_START) {
|
||||
start();
|
||||
_state = STATE_STOP;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//==============================================================================
|
||||
// WARNING don't change SoftI2cMaster unless you verify the change with a scope
|
||||
@@ -111,8 +113,9 @@ bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option) {
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin) {
|
||||
begin(sclPin, sdaPin);
|
||||
SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin)
|
||||
{
|
||||
begin(sclPin, sdaPin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
@@ -122,32 +125,33 @@ SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin) {
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin) {
|
||||
uint8_t port;
|
||||
void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin)
|
||||
{
|
||||
uint8_t port;
|
||||
|
||||
// Get bit mask and address of scl registers.
|
||||
_sclBit = digitalPinToBitMask(sclPin);
|
||||
port = digitalPinToPort(sclPin);
|
||||
_sclDDR = portModeRegister(port);
|
||||
volatile uint8_t* sclOutReg = portOutputRegister(port);
|
||||
// Get bit mask and address of scl registers.
|
||||
_sclBit = digitalPinToBitMask(sclPin);
|
||||
port = digitalPinToPort(sclPin);
|
||||
_sclDDR = portModeRegister(port);
|
||||
volatile uint8_t* sclOutReg = portOutputRegister(port);
|
||||
|
||||
// Get bit mask and address of sda registers.
|
||||
_sdaBit = digitalPinToBitMask(sdaPin);
|
||||
port = digitalPinToPort(sdaPin);
|
||||
_sdaDDR = portModeRegister(port);
|
||||
_sdaInReg = portInputRegister(port);
|
||||
volatile uint8_t* sdaOutReg = portOutputRegister(port);
|
||||
// Get bit mask and address of sda registers.
|
||||
_sdaBit = digitalPinToBitMask(sdaPin);
|
||||
port = digitalPinToPort(sdaPin);
|
||||
_sdaDDR = portModeRegister(port);
|
||||
_sdaInReg = portInputRegister(port);
|
||||
volatile uint8_t* sdaOutReg = portOutputRegister(port);
|
||||
|
||||
// Clear PORT bit for scl and sda.
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
*sclOutReg &= ~_sclBit;
|
||||
*sdaOutReg &= ~_sdaBit;
|
||||
SREG = s;
|
||||
// Clear PORT bit for scl and sda.
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
*sclOutReg &= ~_sclBit;
|
||||
*sdaOutReg &= ~_sdaBit;
|
||||
SREG = s;
|
||||
|
||||
// Set scl and sda high.
|
||||
writeScl(HIGH);
|
||||
writeSda(HIGH);
|
||||
// Set scl and sda high.
|
||||
writeScl(HIGH);
|
||||
writeSda(HIGH);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* Read a byte and send ACK if more reads follow else NACK to terminate read.
|
||||
@@ -156,51 +160,56 @@ void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin) {
|
||||
*
|
||||
* @return The byte read from the I2C bus.
|
||||
*/
|
||||
uint8_t SoftI2cMaster::read(uint8_t last) {
|
||||
uint8_t b = 0;
|
||||
uint8_t SoftI2cMaster::read(uint8_t last)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
|
||||
// Set sda to high Z mode for read.
|
||||
writeSda(HIGH);
|
||||
// Read a byte.
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
// Don't change this loop unless you verify the change with a scope.
|
||||
b <<= 1;
|
||||
sclDelay(16);
|
||||
writeScl(HIGH);
|
||||
sclDelay(12);
|
||||
if (readSda()) b |= 1;
|
||||
writeScl(LOW);
|
||||
}
|
||||
// send ACK or NACK
|
||||
writeSda(last);
|
||||
sclDelay(12);
|
||||
writeScl(HIGH);
|
||||
sclDelay(18);
|
||||
writeScl(LOW);
|
||||
writeSda(LOW);
|
||||
return b;
|
||||
// Set sda to high Z mode for read.
|
||||
writeSda(HIGH);
|
||||
// Read a byte.
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
// Don't change this loop unless you verify the change with a scope.
|
||||
b <<= 1;
|
||||
sclDelay(16);
|
||||
writeScl(HIGH);
|
||||
sclDelay(12);
|
||||
if (readSda()) {
|
||||
b |= 1;
|
||||
}
|
||||
writeScl(LOW);
|
||||
}
|
||||
// send ACK or NACK
|
||||
writeSda(last);
|
||||
sclDelay(12);
|
||||
writeScl(HIGH);
|
||||
sclDelay(18);
|
||||
writeScl(LOW);
|
||||
writeSda(LOW);
|
||||
return b;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* Issue a start condition. */
|
||||
void SoftI2cMaster::start() {
|
||||
if (!readSda()) {
|
||||
writeSda(HIGH);
|
||||
writeScl(HIGH);
|
||||
sclDelay(20);
|
||||
}
|
||||
writeSda(LOW);
|
||||
sclDelay(20);
|
||||
writeScl(LOW);
|
||||
void SoftI2cMaster::start()
|
||||
{
|
||||
if (!readSda()) {
|
||||
writeSda(HIGH);
|
||||
writeScl(HIGH);
|
||||
sclDelay(20);
|
||||
}
|
||||
writeSda(LOW);
|
||||
sclDelay(20);
|
||||
writeScl(LOW);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* Issue a stop condition. */
|
||||
void SoftI2cMaster::stop(void) {
|
||||
writeSda(LOW);
|
||||
sclDelay(20);
|
||||
writeScl(HIGH);
|
||||
sclDelay(20);
|
||||
writeSda(HIGH);
|
||||
sclDelay(20);
|
||||
/* Issue a stop condition. */
|
||||
void SoftI2cMaster::stop(void)
|
||||
{
|
||||
writeSda(LOW);
|
||||
sclDelay(20);
|
||||
writeScl(HIGH);
|
||||
sclDelay(20);
|
||||
writeSda(HIGH);
|
||||
sclDelay(20);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
@@ -210,30 +219,31 @@ void SoftI2cMaster::stop(void) {
|
||||
*
|
||||
* @return The value true, 1, if the slave returned an ACK or false for NACK.
|
||||
*/
|
||||
bool SoftI2cMaster::write(uint8_t data) {
|
||||
// write byte
|
||||
for (uint8_t m = 0X80; m != 0; m >>= 1) {
|
||||
// don't change this loop unless you verify the change with a scope
|
||||
writeSda(m & data);
|
||||
sclDelay(8);
|
||||
writeScl(HIGH);
|
||||
sclDelay(18);
|
||||
writeScl(LOW);
|
||||
}
|
||||
sclDelay(8);
|
||||
// Go to sda high Z mode for input.
|
||||
writeSda(HIGH);
|
||||
writeScl(HIGH);
|
||||
sclDelay(16);
|
||||
bool SoftI2cMaster::write(uint8_t data)
|
||||
{
|
||||
// write byte
|
||||
for (uint8_t m = 0X80; m != 0; m >>= 1) {
|
||||
// don't change this loop unless you verify the change with a scope
|
||||
writeSda(m & data);
|
||||
sclDelay(8);
|
||||
writeScl(HIGH);
|
||||
sclDelay(18);
|
||||
writeScl(LOW);
|
||||
}
|
||||
sclDelay(8);
|
||||
// Go to sda high Z mode for input.
|
||||
writeSda(HIGH);
|
||||
writeScl(HIGH);
|
||||
sclDelay(16);
|
||||
|
||||
// Get ACK or NACK.
|
||||
uint8_t rtn = readSda();
|
||||
// Get ACK or NACK.
|
||||
uint8_t rtn = readSda();
|
||||
|
||||
// pull scl low.
|
||||
writeScl(LOW);
|
||||
// pull scl low.
|
||||
writeScl(LOW);
|
||||
|
||||
// Pull sda low.
|
||||
writeSda(LOW);
|
||||
return rtn == 0;
|
||||
// Pull sda low.
|
||||
writeSda(LOW);
|
||||
return rtn == 0;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -63,151 +63,161 @@ const uint8_t STATE_TX_DATA_NACK = 6;
|
||||
* @class I2cMasterBase
|
||||
* @brief Base class for FastI2cMaster, SoftI2cMaster
|
||||
*/
|
||||
class I2cMasterBase {
|
||||
public:
|
||||
I2cMasterBase() : _state(STATE_STOP) {}
|
||||
/** Read a byte
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*
|
||||
* @param[in] last send a NACK to terminate read if last is true else
|
||||
* send an ACK to continue the read.
|
||||
*
|
||||
* @return byte read from I2C bus
|
||||
*/
|
||||
virtual uint8_t read(uint8_t last) = 0;
|
||||
class I2cMasterBase
|
||||
{
|
||||
public:
|
||||
I2cMasterBase() : _state(STATE_STOP) {}
|
||||
/** Read a byte
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*
|
||||
* @param[in] last send a NACK to terminate read if last is true else
|
||||
* send an ACK to continue the read.
|
||||
*
|
||||
* @return byte read from I2C bus
|
||||
*/
|
||||
virtual uint8_t read(uint8_t last) = 0;
|
||||
|
||||
/** Issue a start condition
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*/
|
||||
virtual void start() = 0;
|
||||
/** Issue a stop condition.
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
/** Issue a start condition
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*/
|
||||
virtual void start() = 0;
|
||||
/** Issue a stop condition.
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/**
|
||||
* Start an I2C transfer with possible continuation.
|
||||
*
|
||||
* @param[in] addressRW I2C slave address plus R/W bit.
|
||||
* The I2C slave address is in the high seven bits
|
||||
* and is ORed with on of the following:
|
||||
* - I2C_READ for a read transfer.
|
||||
* - I2C_WRITE for a write transfer.
|
||||
* .
|
||||
* @param[in,out] buf Source or destination for transfer.
|
||||
* @param[in] nbyte Number of bytes to transfer (may be zero).
|
||||
* @param[in] option Option for ending the transfer, one of:
|
||||
* - I2C_STOP end the transfer with an I2C stop
|
||||
* condition.
|
||||
* - I2C_REP_START end the transfer with an I2C
|
||||
* repeated start condition.
|
||||
* - I2C_CONTINUE allow additional transferContinue()
|
||||
* calls.
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool transfer(uint8_t addressRW, void *buf,
|
||||
size_t nbyte, uint8_t option = I2C_STOP);
|
||||
/**
|
||||
* Start an I2C transfer with possible continuation.
|
||||
*
|
||||
* @param[in] addressRW I2C slave address plus R/W bit.
|
||||
* The I2C slave address is in the high seven bits
|
||||
* and is ORed with on of the following:
|
||||
* - I2C_READ for a read transfer.
|
||||
* - I2C_WRITE for a write transfer.
|
||||
* .
|
||||
* @param[in,out] buf Source or destination for transfer.
|
||||
* @param[in] nbyte Number of bytes to transfer (may be zero).
|
||||
* @param[in] option Option for ending the transfer, one of:
|
||||
* - I2C_STOP end the transfer with an I2C stop
|
||||
* condition.
|
||||
* - I2C_REP_START end the transfer with an I2C
|
||||
* repeated start condition.
|
||||
* - I2C_CONTINUE allow additional transferContinue()
|
||||
* calls.
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool transfer(uint8_t addressRW, void *buf,
|
||||
size_t nbyte, uint8_t option = I2C_STOP);
|
||||
|
||||
/**
|
||||
* Continue an I2C transfer.
|
||||
*
|
||||
* @param[in,out] buf Source or destination for transfer.
|
||||
* @param[in] nbyte Number of bytes to transfer (may be zero).
|
||||
* @param[in] option Option for ending the transfer, one of:
|
||||
* - I2C_STOP end the transfer with an I2C stop
|
||||
* condition.
|
||||
* - I2C_REP_START end the transfer with an I2C
|
||||
* repeated start condition.
|
||||
* - I2C_CONTINUE allow additional transferContinue()
|
||||
* calls.
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool transferContinue(void *buf, size_t nbyte, uint8_t option = I2C_STOP);
|
||||
/** Write a byte
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*
|
||||
* @param[in] data byte to write
|
||||
* @return true for ACK or false for NACK */
|
||||
virtual bool write(uint8_t data) = 0;
|
||||
/**
|
||||
* Continue an I2C transfer.
|
||||
*
|
||||
* @param[in,out] buf Source or destination for transfer.
|
||||
* @param[in] nbyte Number of bytes to transfer (may be zero).
|
||||
* @param[in] option Option for ending the transfer, one of:
|
||||
* - I2C_STOP end the transfer with an I2C stop
|
||||
* condition.
|
||||
* - I2C_REP_START end the transfer with an I2C
|
||||
* repeated start condition.
|
||||
* - I2C_CONTINUE allow additional transferContinue()
|
||||
* calls.
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool transferContinue(void *buf, size_t nbyte, uint8_t option = I2C_STOP);
|
||||
/** Write a byte
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*
|
||||
* @param[in] data byte to write
|
||||
* @return true for ACK or false for NACK */
|
||||
virtual bool write(uint8_t data) = 0;
|
||||
|
||||
private:
|
||||
uint8_t _state;
|
||||
private:
|
||||
uint8_t _state;
|
||||
};
|
||||
//==============================================================================
|
||||
/**
|
||||
* @class SoftI2cMaster
|
||||
* @brief Software I2C master class
|
||||
*/
|
||||
class SoftI2cMaster : public I2cMasterBase {
|
||||
public:
|
||||
SoftI2cMaster() {}
|
||||
/**
|
||||
* Constructor, initialize SCL/SDA pins and set the bus high.
|
||||
*
|
||||
* @param[in] sdaPin The software SDA pin number.
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin);
|
||||
/**
|
||||
* Initialize SCL/SDA pins and set the bus high.
|
||||
*
|
||||
* @param[in] sdaPin The software SDA pin number.
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
void begin(uint8_t sclPin, uint8_t sdaPin);
|
||||
uint8_t read(uint8_t last);
|
||||
void start();
|
||||
void stop(void);
|
||||
bool write(uint8_t b);
|
||||
class SoftI2cMaster : public I2cMasterBase
|
||||
{
|
||||
public:
|
||||
SoftI2cMaster() {}
|
||||
/**
|
||||
* Constructor, initialize SCL/SDA pins and set the bus high.
|
||||
*
|
||||
* @param[in] sdaPin The software SDA pin number.
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin);
|
||||
/**
|
||||
* Initialize SCL/SDA pins and set the bus high.
|
||||
*
|
||||
* @param[in] sdaPin The software SDA pin number.
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
void begin(uint8_t sclPin, uint8_t sdaPin);
|
||||
uint8_t read(uint8_t last);
|
||||
void start();
|
||||
void stop(void);
|
||||
bool write(uint8_t b);
|
||||
|
||||
private:
|
||||
uint8_t _sclBit;
|
||||
uint8_t _sdaBit;
|
||||
volatile uint8_t* _sclDDR;
|
||||
volatile uint8_t* _sdaDDR;
|
||||
volatile uint8_t* _sdaInReg;
|
||||
//----------------------------------------------------------------------------
|
||||
bool readSda() {return *_sdaInReg & _sdaBit;}
|
||||
//----------------------------------------------------------------------------
|
||||
void sclDelay(uint8_t n) {_delay_loop_1(n);}
|
||||
//----------------------------------------------------------------------------
|
||||
void writeScl(bool value) {
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
if (value == LOW) {
|
||||
// Pull scl low.
|
||||
*_sclDDR |= _sclBit;
|
||||
} else {
|
||||
// Put scl in high Z input mode.
|
||||
*_sclDDR &= ~_sclBit;
|
||||
}
|
||||
SREG = s;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void writeSda(bool value) {
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
if (value == LOW) {
|
||||
// Pull sda low.
|
||||
*_sdaDDR |= _sdaBit;
|
||||
} else {
|
||||
// Put sda in high Z input mode.
|
||||
*_sdaDDR &= ~_sdaBit;
|
||||
}
|
||||
SREG = s;
|
||||
}
|
||||
private:
|
||||
uint8_t _sclBit;
|
||||
uint8_t _sdaBit;
|
||||
volatile uint8_t* _sclDDR;
|
||||
volatile uint8_t* _sdaDDR;
|
||||
volatile uint8_t* _sdaInReg;
|
||||
//----------------------------------------------------------------------------
|
||||
bool readSda()
|
||||
{
|
||||
return *_sdaInReg & _sdaBit;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void sclDelay(uint8_t n)
|
||||
{
|
||||
_delay_loop_1(n);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void writeScl(bool value)
|
||||
{
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
if (value == LOW) {
|
||||
// Pull scl low.
|
||||
*_sclDDR |= _sclBit;
|
||||
} else {
|
||||
// Put scl in high Z input mode.
|
||||
*_sclDDR &= ~_sclBit;
|
||||
}
|
||||
SREG = s;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void writeSda(bool value)
|
||||
{
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
if (value == LOW) {
|
||||
// Pull sda low.
|
||||
*_sdaDDR |= _sdaBit;
|
||||
} else {
|
||||
// Put sda in high Z input mode.
|
||||
*_sdaDDR &= ~_sdaBit;
|
||||
}
|
||||
SREG = s;
|
||||
}
|
||||
};
|
||||
//==============================================================================
|
||||
// Template based fast software I2C
|
||||
@@ -217,118 +227,140 @@ class SoftI2cMaster : public I2cMasterBase {
|
||||
* @brief Fast software I2C master class.
|
||||
*/
|
||||
template<uint8_t sclPin, uint8_t sdaPin>
|
||||
class FastI2cMaster : public I2cMasterBase {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
FastI2cMaster() {
|
||||
begin();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize I2C bus pins. */
|
||||
void begin() {
|
||||
fastDigitalWrite(sclPin, LOW);
|
||||
fastDigitalWrite(sdaPin, LOW);
|
||||
class FastI2cMaster : public I2cMasterBase
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
FastI2cMaster()
|
||||
{
|
||||
begin();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize I2C bus pins. */
|
||||
void begin()
|
||||
{
|
||||
fastDigitalWrite(sclPin, LOW);
|
||||
fastDigitalWrite(sdaPin, LOW);
|
||||
|
||||
sclWrite(HIGH);
|
||||
sdaWrite(HIGH);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t read(uint8_t last) {
|
||||
uint8_t data = 0;
|
||||
sdaWrite(HIGH);
|
||||
sclWrite(HIGH);
|
||||
sdaWrite(HIGH);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t read(uint8_t last)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
sdaWrite(HIGH);
|
||||
|
||||
readBit(7, &data);
|
||||
readBit(6, &data);
|
||||
readBit(5, &data);
|
||||
readBit(4, &data);
|
||||
readBit(3, &data);
|
||||
readBit(2, &data);
|
||||
readBit(1, &data);
|
||||
readBit(0, &data);
|
||||
readBit(7, &data);
|
||||
readBit(6, &data);
|
||||
readBit(5, &data);
|
||||
readBit(4, &data);
|
||||
readBit(3, &data);
|
||||
readBit(2, &data);
|
||||
readBit(1, &data);
|
||||
readBit(0, &data);
|
||||
|
||||
// send ACK or NACK
|
||||
sdaWrite(last);
|
||||
sclDelay(4);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(6);
|
||||
sclWrite(LOW);
|
||||
sdaWrite(LOW);
|
||||
return data;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void start() {
|
||||
if (!fastDigitalRead(sdaPin)) {
|
||||
// It's a repeat start.
|
||||
sdaWrite(HIGH);
|
||||
sclDelay(8);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(8);
|
||||
}
|
||||
sdaWrite(LOW);
|
||||
sclDelay(8);
|
||||
sclWrite(LOW);
|
||||
sclDelay(8);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void stop(void) {
|
||||
sdaWrite(LOW);
|
||||
sclDelay(8);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(8);
|
||||
sdaWrite(HIGH);
|
||||
sclDelay(8);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool write(uint8_t data) {
|
||||
// write byte
|
||||
writeBit(7, data);
|
||||
writeBit(6, data);
|
||||
writeBit(5, data);
|
||||
writeBit(4, data);
|
||||
writeBit(3, data);
|
||||
writeBit(2, data);
|
||||
writeBit(1, data);
|
||||
writeBit(0, data);
|
||||
// send ACK or NACK
|
||||
sdaWrite(last);
|
||||
sclDelay(4);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(6);
|
||||
sclWrite(LOW);
|
||||
sdaWrite(LOW);
|
||||
return data;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void start()
|
||||
{
|
||||
if (!fastDigitalRead(sdaPin)) {
|
||||
// It's a repeat start.
|
||||
sdaWrite(HIGH);
|
||||
sclDelay(8);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(8);
|
||||
}
|
||||
sdaWrite(LOW);
|
||||
sclDelay(8);
|
||||
sclWrite(LOW);
|
||||
sclDelay(8);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void stop(void)
|
||||
{
|
||||
sdaWrite(LOW);
|
||||
sclDelay(8);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(8);
|
||||
sdaWrite(HIGH);
|
||||
sclDelay(8);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool write(uint8_t data)
|
||||
{
|
||||
// write byte
|
||||
writeBit(7, data);
|
||||
writeBit(6, data);
|
||||
writeBit(5, data);
|
||||
writeBit(4, data);
|
||||
writeBit(3, data);
|
||||
writeBit(2, data);
|
||||
writeBit(1, data);
|
||||
writeBit(0, data);
|
||||
|
||||
// get ACK or NACK
|
||||
sdaWrite(HIGH);
|
||||
// get ACK or NACK
|
||||
sdaWrite(HIGH);
|
||||
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
bool rtn = fastDigitalRead(sdaPin);
|
||||
sclWrite(LOW);
|
||||
sdaWrite(LOW);
|
||||
return rtn == 0;
|
||||
}
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
bool rtn = fastDigitalRead(sdaPin);
|
||||
sclWrite(LOW);
|
||||
sdaWrite(LOW);
|
||||
return rtn == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sclWrite(bool value) {fastPinMode(sclPin, !value);}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sdaWrite(bool value) {fastPinMode(sdaPin, !value);}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint8_t bit, uint8_t* data) {
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
if (fastDigitalRead(sdaPin)) *data |= 1 << bit;
|
||||
sclWrite(LOW);
|
||||
if (bit) sclDelay(6);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void sclDelay(uint8_t n) {_delay_loop_1(n);}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(uint8_t bit, uint8_t data) {
|
||||
uint8_t mask = 1 << bit;
|
||||
sdaWrite(data & mask);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
sclWrite(LOW);
|
||||
sclDelay(5);
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sclWrite(bool value)
|
||||
{
|
||||
fastPinMode(sclPin, !value);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sdaWrite(bool value)
|
||||
{
|
||||
fastPinMode(sdaPin, !value);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint8_t bit, uint8_t* data)
|
||||
{
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
if (fastDigitalRead(sdaPin)) {
|
||||
*data |= 1 << bit;
|
||||
}
|
||||
sclWrite(LOW);
|
||||
if (bit) {
|
||||
sclDelay(6);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void sclDelay(uint8_t n)
|
||||
{
|
||||
_delay_loop_1(n);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(uint8_t bit, uint8_t data)
|
||||
{
|
||||
uint8_t mask = 1 << bit;
|
||||
sdaWrite(data & mask);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
sclWrite(LOW);
|
||||
sclDelay(5);
|
||||
}
|
||||
};
|
||||
#endif // SOFT_I2C_MASTER_H
|
||||
/** @} */
|
||||
|
||||
+120
-102
@@ -18,7 +18,7 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @file
|
||||
* @brief Software SPI.
|
||||
*
|
||||
* @defgroup softSPI Software SPI
|
||||
@@ -48,108 +48,126 @@ const bool SCK_MODE = true;
|
||||
* @brief Fast software SPI.
|
||||
*/
|
||||
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin, uint8_t Mode = 0>
|
||||
class SoftSPI {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize SoftSPI pins. */
|
||||
void begin() {
|
||||
fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL);
|
||||
fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode));
|
||||
fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI receive byte.
|
||||
* @return Data byte received.
|
||||
*/
|
||||
ALWAYS_INLINE uint8_t receive() {
|
||||
uint8_t data = 0;
|
||||
receiveBit(7, &data);
|
||||
receiveBit(6, &data);
|
||||
receiveBit(5, &data);
|
||||
receiveBit(4, &data);
|
||||
receiveBit(3, &data);
|
||||
receiveBit(2, &data);
|
||||
receiveBit(1, &data);
|
||||
receiveBit(0, &data);
|
||||
return data;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI send byte.
|
||||
* @param[in] data Data byte to send.
|
||||
*/
|
||||
ALWAYS_INLINE void send(uint8_t data) {
|
||||
sendBit(7, data);
|
||||
sendBit(6, data);
|
||||
sendBit(5, data);
|
||||
sendBit(4, data);
|
||||
sendBit(3, data);
|
||||
sendBit(2, data);
|
||||
sendBit(1, data);
|
||||
sendBit(0, data);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI transfer byte.
|
||||
* @param[in] txData Data byte to send.
|
||||
* @return Data byte received.
|
||||
*/
|
||||
ALWAYS_INLINE uint8_t transfer(uint8_t txData) {
|
||||
uint8_t rxData = 0;
|
||||
transferBit(7, &rxData, txData);
|
||||
transferBit(6, &rxData, txData);
|
||||
transferBit(5, &rxData, txData);
|
||||
transferBit(4, &rxData, txData);
|
||||
transferBit(3, &rxData, txData);
|
||||
transferBit(2, &rxData, txData);
|
||||
transferBit(1, &rxData, txData);
|
||||
transferBit(0, &rxData, txData);
|
||||
return rxData;
|
||||
}
|
||||
class SoftSPI
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize SoftSPI pins. */
|
||||
void begin()
|
||||
{
|
||||
fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL);
|
||||
fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode));
|
||||
fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI receive byte.
|
||||
* @return Data byte received.
|
||||
*/
|
||||
ALWAYS_INLINE uint8_t receive()
|
||||
{
|
||||
uint8_t data = 0;
|
||||
receiveBit(7, &data);
|
||||
receiveBit(6, &data);
|
||||
receiveBit(5, &data);
|
||||
receiveBit(4, &data);
|
||||
receiveBit(3, &data);
|
||||
receiveBit(2, &data);
|
||||
receiveBit(1, &data);
|
||||
receiveBit(0, &data);
|
||||
return data;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI send byte.
|
||||
* @param[in] data Data byte to send.
|
||||
*/
|
||||
ALWAYS_INLINE void send(uint8_t data)
|
||||
{
|
||||
sendBit(7, data);
|
||||
sendBit(6, data);
|
||||
sendBit(5, data);
|
||||
sendBit(4, data);
|
||||
sendBit(3, data);
|
||||
sendBit(2, data);
|
||||
sendBit(1, data);
|
||||
sendBit(0, data);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI transfer byte.
|
||||
* @param[in] txData Data byte to send.
|
||||
* @return Data byte received.
|
||||
*/
|
||||
ALWAYS_INLINE uint8_t transfer(uint8_t txData)
|
||||
{
|
||||
uint8_t rxData = 0;
|
||||
transferBit(7, &rxData, txData);
|
||||
transferBit(6, &rxData, txData);
|
||||
transferBit(5, &rxData, txData);
|
||||
transferBit(4, &rxData, txData);
|
||||
transferBit(3, &rxData, txData);
|
||||
transferBit(2, &rxData, txData);
|
||||
transferBit(1, &rxData, txData);
|
||||
transferBit(0, &rxData, txData);
|
||||
return rxData;
|
||||
}
|
||||
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
ALWAYS_INLINE bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;}
|
||||
ALWAYS_INLINE bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;}
|
||||
ALWAYS_INLINE void receiveBit(uint8_t bit, uint8_t* data) {
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
nop;
|
||||
nop;
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
if (fastDigitalRead(MisoPin)) *data |= 1 << bit;
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
ALWAYS_INLINE void sendBit(uint8_t bit, uint8_t data) {
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
fastDigitalWrite(MosiPin, data & (1 << bit));
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
nop;
|
||||
nop;
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
ALWAYS_INLINE void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) {
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
fastDigitalWrite(MosiPin, txData & (1 << bit));
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit;
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
ALWAYS_INLINE bool MODE_CPHA(uint8_t mode)
|
||||
{
|
||||
return (mode & 1) != 0;
|
||||
}
|
||||
ALWAYS_INLINE bool MODE_CPOL(uint8_t mode)
|
||||
{
|
||||
return (mode & 2) != 0;
|
||||
}
|
||||
ALWAYS_INLINE void receiveBit(uint8_t bit, uint8_t* data)
|
||||
{
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
nop;
|
||||
nop;
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
if (fastDigitalRead(MisoPin)) {
|
||||
*data |= 1 << bit;
|
||||
}
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
ALWAYS_INLINE void sendBit(uint8_t bit, uint8_t data)
|
||||
{
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
fastDigitalWrite(MosiPin, data & (1 << bit));
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
nop;
|
||||
nop;
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
ALWAYS_INLINE void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData)
|
||||
{
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
fastDigitalWrite(MosiPin, txData & (1 << bit));
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
if (fastDigitalRead(MisoPin)) {
|
||||
*rxData |= 1 << bit;
|
||||
}
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
};
|
||||
#endif // SoftSPI_h
|
||||
/** @} */
|
||||
|
||||
@@ -9,118 +9,132 @@
|
||||
//------------------------------------------------------------------------------
|
||||
template<uint8_t ClkPin, uint8_t ConvPin, uint8_t DataPin>
|
||||
/** ADS7818 class */
|
||||
class ADS7818 {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin() {
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(ConvPin, 1);
|
||||
fastDigitalWrite(ConvPin, 1);
|
||||
fastPinMode(DataPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read ADS7818 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read() {
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(ConvPin, 0);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastDigitalWrite(ConvPin, 1);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
class ADS7818
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin()
|
||||
{
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(ConvPin, 1);
|
||||
fastDigitalWrite(ConvPin, 1);
|
||||
fastPinMode(DataPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read ADS7818 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read()
|
||||
{
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(ConvPin, 0);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastDigitalWrite(ConvPin, 1);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
|
||||
readBitFast16(v, 11);
|
||||
readBitFast16(v, 10);
|
||||
readBitFast16(v, 9);
|
||||
readBitFast16(v, 8);
|
||||
readBitFast16(v, 7);
|
||||
readBitFast16(v, 6);
|
||||
readBitFast16(v, 5);
|
||||
readBitFast16(v, 4);
|
||||
readBitFast16(v, 3);
|
||||
readBitFast16(v, 2);
|
||||
readBitFast16(v, 1);
|
||||
readBitFast16(v, 0);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBitFast16(uint16_t &v, uint8_t b) {
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
if (fastDigitalRead(DataPin)) v |= (1 << b);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
readBitFast16(v, 11);
|
||||
readBitFast16(v, 10);
|
||||
readBitFast16(v, 9);
|
||||
readBitFast16(v, 8);
|
||||
readBitFast16(v, 7);
|
||||
readBitFast16(v, 6);
|
||||
readBitFast16(v, 5);
|
||||
readBitFast16(v, 4);
|
||||
readBitFast16(v, 3);
|
||||
readBitFast16(v, 2);
|
||||
readBitFast16(v, 1);
|
||||
readBitFast16(v, 0);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBitFast16(uint16_t &v, uint8_t b)
|
||||
{
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
if (fastDigitalRead(DataPin)) {
|
||||
v |= (1 << b);
|
||||
}
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
};
|
||||
#if 0
|
||||
/** initialize I/O ports */
|
||||
STATIC_ALWAYS_INLINE void adcBegin() {
|
||||
fastPinMode(ADC_CLK_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
fastPinMode(ADC_CONV_PIN, 1);
|
||||
fastDigitalWrite(ADC_CONV_PIN, 1);
|
||||
fastPinMode(ADC_DATA_PIN, 0);
|
||||
STATIC_ALWAYS_INLINE void adcBegin()
|
||||
{
|
||||
fastPinMode(ADC_CLK_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
fastPinMode(ADC_CONV_PIN, 1);
|
||||
fastDigitalWrite(ADC_CONV_PIN, 1);
|
||||
fastPinMode(ADC_DATA_PIN, 0);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
STATIC_ALWAYS_INLINE void fastDummy(bool first) {
|
||||
if (!first) nop;
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
nop;
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
STATIC_ALWAYS_INLINE void fastDummy(bool first)
|
||||
{
|
||||
if (!first) {
|
||||
nop;
|
||||
}
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
nop;
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** read next bit fast as possible
|
||||
* \param[in] v word to receive bit
|
||||
* \param[in] b bit number to be set. v |= (1 << b) if next bit is high.
|
||||
*/
|
||||
STATIC_ALWAYS_INLINE void readBitFast16(uint16_t &v, uint8_t b) {
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
if (fastDigitalRead(ADC_DATA_PIN)) v |= (1 << b);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
STATIC_ALWAYS_INLINE void readBitFast16(uint16_t &v, uint8_t b)
|
||||
{
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
if (fastDigitalRead(ADC_DATA_PIN)) {
|
||||
v |= (1 << b);
|
||||
}
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Read AD7680 16-bit ADC in less than 8 microseconds
|
||||
* cs is chip select pin
|
||||
*/
|
||||
STATIC_ALWAYS_INLINE uint16_t adcRead(bool centered = false) {
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(ADC_CONV_PIN, 0);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
fastDigitalWrite(ADC_CONV_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
// uint16_t v = 0;
|
||||
STATIC_ALWAYS_INLINE uint16_t adcRead(bool centered = false)
|
||||
{
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(ADC_CONV_PIN, 0);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
fastDigitalWrite(ADC_CONV_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 1);
|
||||
fastDigitalWrite(ADC_CLK_PIN, 0);
|
||||
// uint16_t v = 0;
|
||||
|
||||
// fastDummy(1);
|
||||
// fastDummy(0);
|
||||
// fastDummy(0);
|
||||
// fastDummy(0);
|
||||
|
||||
// readBitFast16(v, 15);
|
||||
// readBitFast16(v, 14);
|
||||
// readBitFast16(v, 13);
|
||||
// readBitFast16(v, 12);
|
||||
readBitFast16(v, 11);
|
||||
readBitFast16(v, 10);
|
||||
readBitFast16(v, 9);
|
||||
readBitFast16(v, 8);
|
||||
readBitFast16(v, 7);
|
||||
readBitFast16(v, 6);
|
||||
readBitFast16(v, 5);
|
||||
readBitFast16(v, 4);
|
||||
readBitFast16(v, 3);
|
||||
readBitFast16(v, 2);
|
||||
readBitFast16(v, 1);
|
||||
readBitFast16(v, 0);
|
||||
return centered ? v ^ 0X8000 : v;
|
||||
// fastDummy(1);
|
||||
// fastDummy(0);
|
||||
// fastDummy(0);
|
||||
// fastDummy(0);
|
||||
|
||||
// readBitFast16(v, 15);
|
||||
// readBitFast16(v, 14);
|
||||
// readBitFast16(v, 13);
|
||||
// readBitFast16(v, 12);
|
||||
readBitFast16(v, 11);
|
||||
readBitFast16(v, 10);
|
||||
readBitFast16(v, 9);
|
||||
readBitFast16(v, 8);
|
||||
readBitFast16(v, 7);
|
||||
readBitFast16(v, 6);
|
||||
readBitFast16(v, 5);
|
||||
readBitFast16(v, 4);
|
||||
readBitFast16(v, 3);
|
||||
readBitFast16(v, 2);
|
||||
readBitFast16(v, 1);
|
||||
readBitFast16(v, 0);
|
||||
return centered ? v ^ 0X8000 : v;
|
||||
}
|
||||
#endif // 0
|
||||
#endif // ADS7818_h
|
||||
@@ -4,259 +4,302 @@
|
||||
//==============================================================================
|
||||
template<uint8_t CsPin, uint8_t ClkPin, uint8_t DoutPin, uint8_t UsecDelay = 0>
|
||||
/** MCP3201 class */
|
||||
class MCP3201 {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin() {
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
fastPinMode(DoutPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP3201 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read() {
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Start sample.
|
||||
mcpAdcDummy(3);
|
||||
// Extra sample time.
|
||||
if (UsecDelay){
|
||||
delayMicroseconds(UsecDelay);
|
||||
}
|
||||
// End sample.
|
||||
mcpAdcDummy(3);
|
||||
// Null bit.
|
||||
mcpAdcDummy(3);
|
||||
uint16_t v = 0;
|
||||
readBit(v, 11);
|
||||
readBit(v, 10);
|
||||
readBit(v, 9);
|
||||
readBit(v, 8);
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n) {
|
||||
if (n & 1) asm volatile("nop\n\t");
|
||||
if (n & 2) asm volatile("nop\n\t" "nop\n\t");
|
||||
if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
inline __attribute__((always_inline))
|
||||
void mcpAdcDummy(uint8_t delayBefore) {
|
||||
delayCycles(delayBefore);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(3);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 2) {
|
||||
delayCycles(3);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(delayRead);
|
||||
if (fastDigitalRead(DoutPin)) v |= (1 << b);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
class MCP3201
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin()
|
||||
{
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
fastPinMode(DoutPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP3201 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read()
|
||||
{
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Start sample.
|
||||
mcpAdcDummy(3);
|
||||
// Extra sample time.
|
||||
if (UsecDelay) {
|
||||
delayMicroseconds(UsecDelay);
|
||||
}
|
||||
// End sample.
|
||||
mcpAdcDummy(3);
|
||||
// Null bit.
|
||||
mcpAdcDummy(3);
|
||||
uint16_t v = 0;
|
||||
readBit(v, 11);
|
||||
readBit(v, 10);
|
||||
readBit(v, 9);
|
||||
readBit(v, 8);
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n)
|
||||
{
|
||||
if (n & 1) {
|
||||
asm volatile("nop\n\t");
|
||||
}
|
||||
if (n & 2) {
|
||||
asm volatile("nop\n\t" "nop\n\t");
|
||||
}
|
||||
if (n & 4) {
|
||||
asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
inline __attribute__((always_inline))
|
||||
void mcpAdcDummy(uint8_t delayBefore)
|
||||
{
|
||||
delayCycles(delayBefore);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(3);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 2)
|
||||
{
|
||||
delayCycles(3);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(delayRead);
|
||||
if (fastDigitalRead(DoutPin)) {
|
||||
v |= (1 << b);
|
||||
}
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
};
|
||||
//==============================================================================
|
||||
template<uint8_t CsPin, uint8_t ClkPin,
|
||||
uint8_t DoutPin, uint8_t DinPin, uint8_t UsecDelay = 0>
|
||||
/** MCP3202 class */
|
||||
class MCP3202 {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin() {
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
fastPinMode(DoutPin, 0);
|
||||
fastPinMode(DinPin, 1);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP3202 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read(uint8_t config) {
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Start bit.
|
||||
writeBit(true);
|
||||
// Mode bit.
|
||||
writeBit(config & 2);
|
||||
// Channel Selection and start sample.
|
||||
writeBit(config & 1);
|
||||
// Extra sample time.
|
||||
if (UsecDelay){
|
||||
delayMicroseconds(UsecDelay);
|
||||
}
|
||||
// MSB first format and end sample.
|
||||
writeBit(true);
|
||||
// Null bit.
|
||||
writeBit(true);
|
||||
// Data bits.
|
||||
readBit(v, 11);
|
||||
readBit(v, 10);
|
||||
readBit(v, 9);
|
||||
readBit(v, 8);
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n) {
|
||||
if (n & 1) asm volatile("nop\n\t");
|
||||
if (n & 2) asm volatile("nop\n\t" "nop\n\t");
|
||||
if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(bool value) {
|
||||
fastDigitalWrite(DinPin, value);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1) {
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(delayRead);
|
||||
if (fastDigitalRead(DoutPin)) v |= (1 << b);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
class MCP3202
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin()
|
||||
{
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
fastPinMode(DoutPin, 0);
|
||||
fastPinMode(DinPin, 1);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP3202 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read(uint8_t config)
|
||||
{
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Start bit.
|
||||
writeBit(true);
|
||||
// Mode bit.
|
||||
writeBit(config & 2);
|
||||
// Channel Selection and start sample.
|
||||
writeBit(config & 1);
|
||||
// Extra sample time.
|
||||
if (UsecDelay) {
|
||||
delayMicroseconds(UsecDelay);
|
||||
}
|
||||
// MSB first format and end sample.
|
||||
writeBit(true);
|
||||
// Null bit.
|
||||
writeBit(true);
|
||||
// Data bits.
|
||||
readBit(v, 11);
|
||||
readBit(v, 10);
|
||||
readBit(v, 9);
|
||||
readBit(v, 8);
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n)
|
||||
{
|
||||
if (n & 1) {
|
||||
asm volatile("nop\n\t");
|
||||
}
|
||||
if (n & 2) {
|
||||
asm volatile("nop\n\t" "nop\n\t");
|
||||
}
|
||||
if (n & 4) {
|
||||
asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(bool value)
|
||||
{
|
||||
fastDigitalWrite(DinPin, value);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1)
|
||||
{
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(delayRead);
|
||||
if (fastDigitalRead(DoutPin)) {
|
||||
v |= (1 << b);
|
||||
}
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
};
|
||||
//==============================================================================
|
||||
template<uint8_t CsPin, uint8_t ClkPin,
|
||||
uint8_t DoutPin, uint8_t DinPin, uint8_t UsecDelay = 0>
|
||||
/** MCP3204 class */
|
||||
class MCP3204 {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin() {
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
fastPinMode(DoutPin, 0);
|
||||
fastPinMode(DinPin, 1);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP3204 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read(uint8_t config) {
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Start bit.
|
||||
writeBit(true);
|
||||
// Mode bit.
|
||||
writeBit(config & 8);
|
||||
// D2 channel bit.
|
||||
writeBit(config & 4);
|
||||
// D1 channel bit.
|
||||
writeBit(config & 2);
|
||||
// D0 channel bit and start sample.
|
||||
writeBit(config & 1);
|
||||
// Extra sample time.
|
||||
if (UsecDelay){
|
||||
delayMicroseconds(UsecDelay);
|
||||
}
|
||||
// End sample cycle.
|
||||
writeBit(true);
|
||||
// Null bit.
|
||||
writeBit(true);
|
||||
// Data bits.
|
||||
readBit(v, 11);
|
||||
readBit(v, 10);
|
||||
readBit(v, 9);
|
||||
readBit(v, 8);
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n) {
|
||||
if (n & 1) asm volatile("nop\n\t");
|
||||
if (n & 2) asm volatile("nop\n\t" "nop\n\t");
|
||||
if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(bool value) {
|
||||
fastDigitalWrite(DinPin, value);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1) {
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(delayRead);
|
||||
if (fastDigitalRead(DoutPin)) v |= (1 << b);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
class MCP3204
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin()
|
||||
{
|
||||
fastPinMode(ClkPin, 1);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
fastPinMode(DoutPin, 0);
|
||||
fastPinMode(DinPin, 1);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP3204 12-bit ADC
|
||||
* \return 16-bit value read.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint16_t read(uint8_t config)
|
||||
{
|
||||
uint16_t v = 0;
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Start bit.
|
||||
writeBit(true);
|
||||
// Mode bit.
|
||||
writeBit(config & 8);
|
||||
// D2 channel bit.
|
||||
writeBit(config & 4);
|
||||
// D1 channel bit.
|
||||
writeBit(config & 2);
|
||||
// D0 channel bit and start sample.
|
||||
writeBit(config & 1);
|
||||
// Extra sample time.
|
||||
if (UsecDelay) {
|
||||
delayMicroseconds(UsecDelay);
|
||||
}
|
||||
// End sample cycle.
|
||||
writeBit(true);
|
||||
// Null bit.
|
||||
writeBit(true);
|
||||
// Data bits.
|
||||
readBit(v, 11);
|
||||
readBit(v, 10);
|
||||
readBit(v, 9);
|
||||
readBit(v, 8);
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
return v;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n)
|
||||
{
|
||||
if (n & 1) {
|
||||
asm volatile("nop\n\t");
|
||||
}
|
||||
if (n & 2) {
|
||||
asm volatile("nop\n\t" "nop\n\t");
|
||||
}
|
||||
if (n & 4) {
|
||||
asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** clock for don't care bits
|
||||
*\param[in] delayBefore if true, delay before raising clock*/
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(bool value)
|
||||
{
|
||||
fastDigitalWrite(DinPin, value);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1)
|
||||
{
|
||||
delayCycles(2);
|
||||
fastDigitalWrite(ClkPin, 1);
|
||||
delayCycles(delayRead);
|
||||
if (fastDigitalRead(DoutPin)) {
|
||||
v |= (1 << b);
|
||||
}
|
||||
fastDigitalWrite(ClkPin, 0);
|
||||
}
|
||||
};
|
||||
//==============================================================================
|
||||
// MCP3204 and MCP3208 use the same code.
|
||||
template<uint8_t CsPin, uint8_t ClkPin,
|
||||
uint8_t DoutPin, uint8_t DinPin, uint8_t UsecDelay = 0>
|
||||
class MCP3208 : public MCP3204<CsPin, ClkPin, DoutPin, DinPin, UsecDelay> {
|
||||
class MCP3208 : public MCP3204<CsPin, ClkPin, DoutPin, DinPin, UsecDelay>
|
||||
{
|
||||
};
|
||||
#endif // MCP320X_h
|
||||
@@ -9,119 +9,145 @@ const uint8_t MCP355X_TO_MS = 100;
|
||||
//==============================================================================
|
||||
template<uint8_t CsPin, uint8_t SckPin, uint8_t SdoPin>
|
||||
/** MCP355X class */
|
||||
class MCP355X {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin(bool singleMode = true) {
|
||||
m_singleMode = singleMode;
|
||||
fastPinMode(SdoPin, 0);
|
||||
fastPinMode(SckPin, 1);
|
||||
fastDigitalWrite(SckPin, 1);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
if (!m_singleMode) {
|
||||
// Wait for conversion to complete.
|
||||
delay(100);
|
||||
// Start continuous conversion mode.
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP355X 22-bit ADC
|
||||
* \return 22-bit value.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
int32_t read() {
|
||||
uint8_t t = 0;
|
||||
uint8_t v3 = 0;
|
||||
if (m_singleMode) {
|
||||
// Start conversion.
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Delay at least 10 usec to avoid RDY glitch on exit from Shutdown.
|
||||
delay(1);
|
||||
// Toggle CsPin to indicate single conversion mode.
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
// Wait for conversion to complete.
|
||||
while (1) {
|
||||
delay(1);
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Delay while RDY settles.
|
||||
delayCycles(4);
|
||||
if (!fastDigitalRead(SdoPin)) break;
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
if (t++ > MCP355X_TO_MS) return MCP355X_ERR;
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
if (!fastDigitalRead(SdoPin)) break;
|
||||
delay(1);
|
||||
if (t++ > MCP355X_TO_MS) return MCP355X_ERR;
|
||||
}
|
||||
}
|
||||
uint8_t v2 = readByte();
|
||||
uint8_t v1 = readByte();
|
||||
uint8_t v0 = readByte();
|
||||
|
||||
// The 25th falling edge of SCK changes SDO/RDY from Data mode to RDY mode.
|
||||
uint8_t dummy = 0;
|
||||
readBit(dummy, 0);
|
||||
class MCP355X
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin modes and initial levels. */
|
||||
void begin(bool singleMode = true)
|
||||
{
|
||||
m_singleMode = singleMode;
|
||||
fastPinMode(SdoPin, 0);
|
||||
fastPinMode(SckPin, 1);
|
||||
fastDigitalWrite(SckPin, 1);
|
||||
fastPinMode(CsPin, 1);
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
if (!m_singleMode) {
|
||||
// Wait for conversion to complete.
|
||||
delay(100);
|
||||
// Start continuous conversion mode.
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Read MCP355X 22-bit ADC
|
||||
* \return 22-bit value.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
int32_t read()
|
||||
{
|
||||
uint8_t t = 0;
|
||||
uint8_t v3 = 0;
|
||||
if (m_singleMode) {
|
||||
// Start conversion.
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Delay at least 10 usec to avoid RDY glitch on exit from Shutdown.
|
||||
delay(1);
|
||||
// Toggle CsPin to indicate single conversion mode.
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
// Wait for conversion to complete.
|
||||
while (1) {
|
||||
delay(1);
|
||||
fastDigitalWrite(CsPin, 0);
|
||||
// Delay while RDY settles.
|
||||
delayCycles(4);
|
||||
if (!fastDigitalRead(SdoPin)) {
|
||||
break;
|
||||
}
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
if (t++ > MCP355X_TO_MS) {
|
||||
return MCP355X_ERR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
if (!fastDigitalRead(SdoPin)) {
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
if (t++ > MCP355X_TO_MS) {
|
||||
return MCP355X_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t v2 = readByte();
|
||||
uint8_t v1 = readByte();
|
||||
uint8_t v0 = readByte();
|
||||
|
||||
if (m_singleMode) {
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
}
|
||||
if ((v2 & 0XE0) == 0X20) {
|
||||
// Negative in range so extend sign bit.
|
||||
v2 |= 0XC0;
|
||||
v3 = 0XFF;
|
||||
} else if (v2 & 0X40) {
|
||||
// Overflow high. Cause value to be >= MCP355X_OVH.
|
||||
if (v2 & 0X20) v2 &= 0X3F;
|
||||
} else if (v2 & 0X80) {
|
||||
// Overflow low. Cause value to be <= MCP355X_OVH.
|
||||
if ((v2 & 0X20) == 0) v2 |= 0X40;
|
||||
v3 = 0XFF;
|
||||
}
|
||||
uint16_t v_high = (v3 << 8) | v2;
|
||||
uint16_t v_low = (v1 << 8) | v0;
|
||||
return ((uint32_t)v_high << 16) | v_low;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n) {
|
||||
if (n & 1) asm volatile("nop\n\t");
|
||||
if (n & 2) asm volatile("nop\n\t" "nop\n\t");
|
||||
if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
// Default delay yields about 2 MHz clock.
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint8_t &v, uint8_t b, uint8_t delayRead = 0) {
|
||||
fastDigitalWrite(SckPin, 0);
|
||||
delayCycles(2 + delayRead);
|
||||
fastDigitalWrite(SckPin, 1);
|
||||
if (fastDigitalRead(SdoPin)) v |= (1 << b);
|
||||
delayCycles(delayRead);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
uint8_t readByte() {
|
||||
uint8_t v = 0;
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
return v;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool m_singleMode;
|
||||
// The 25th falling edge of SCK changes SDO/RDY from Data mode to RDY mode.
|
||||
uint8_t dummy = 0;
|
||||
readBit(dummy, 0);
|
||||
|
||||
if (m_singleMode) {
|
||||
fastDigitalWrite(CsPin, 1);
|
||||
}
|
||||
if ((v2 & 0XE0) == 0X20) {
|
||||
// Negative in range so extend sign bit.
|
||||
v2 |= 0XC0;
|
||||
v3 = 0XFF;
|
||||
} else if (v2 & 0X40) {
|
||||
// Overflow high. Cause value to be >= MCP355X_OVH.
|
||||
if (v2 & 0X20) {
|
||||
v2 &= 0X3F;
|
||||
}
|
||||
} else if (v2 & 0X80) {
|
||||
// Overflow low. Cause value to be <= MCP355X_OVH.
|
||||
if ((v2 & 0X20) == 0) {
|
||||
v2 |= 0X40;
|
||||
}
|
||||
v3 = 0XFF;
|
||||
}
|
||||
uint16_t v_high = (v3 << 8) | v2;
|
||||
uint16_t v_low = (v1 << 8) | v0;
|
||||
return ((uint32_t)v_high << 16) | v_low;
|
||||
}
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
/** delay n nops
|
||||
* \param[in] n nops to delay, must be a constant so compiler optimizes if().
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delayCycles(uint8_t n)
|
||||
{
|
||||
if (n & 1) {
|
||||
asm volatile("nop\n\t");
|
||||
}
|
||||
if (n & 2) {
|
||||
asm volatile("nop\n\t" "nop\n\t");
|
||||
}
|
||||
if (n & 4) {
|
||||
asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
// Default delay yields about 2 MHz clock.
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint8_t &v, uint8_t b, uint8_t delayRead = 0)
|
||||
{
|
||||
fastDigitalWrite(SckPin, 0);
|
||||
delayCycles(2 + delayRead);
|
||||
fastDigitalWrite(SckPin, 1);
|
||||
if (fastDigitalRead(SdoPin)) {
|
||||
v |= (1 << b);
|
||||
}
|
||||
delayCycles(delayRead);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
uint8_t readByte()
|
||||
{
|
||||
uint8_t v = 0;
|
||||
readBit(v, 7);
|
||||
readBit(v, 6);
|
||||
readBit(v, 5);
|
||||
readBit(v, 4);
|
||||
readBit(v, 3);
|
||||
readBit(v, 2);
|
||||
readBit(v, 1);
|
||||
readBit(v, 0);
|
||||
return v;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool m_singleMode;
|
||||
};
|
||||
#endif // MCP355X_h
|
||||
@@ -4,9 +4,10 @@ DigitalPin<13> pin13(OUTPUT);
|
||||
|
||||
void setup() {}
|
||||
|
||||
void loop() {
|
||||
// toggle is a two byte instruction that executes
|
||||
// in two cycles or 125 ns on a 16 MHz CPU
|
||||
pin13.toggle();
|
||||
delay(250);
|
||||
void loop()
|
||||
{
|
||||
// toggle is a two byte instruction that executes
|
||||
// in two cycles or 125 ns on a 16 MHz CPU
|
||||
pin13.toggle();
|
||||
delay(250);
|
||||
}
|
||||
@@ -4,15 +4,17 @@
|
||||
// Class with compile time pin number.
|
||||
DigitalPin<13> pin13;
|
||||
|
||||
void setup() {
|
||||
// Set mode to OUTPUT and level LOW.
|
||||
pin13.config(OUTPUT, LOW);
|
||||
void setup()
|
||||
{
|
||||
// Set mode to OUTPUT and level LOW.
|
||||
pin13.config(OUTPUT, LOW);
|
||||
}
|
||||
void loop() {
|
||||
// toggle is a two byte instruction that executes
|
||||
// in two cycles or 125 ns on a 16 MHz CPU
|
||||
pin13.toggle();
|
||||
delay(100);
|
||||
pin13.toggle();
|
||||
delay(400);
|
||||
void loop()
|
||||
{
|
||||
// toggle is a two byte instruction that executes
|
||||
// in two cycles or 125 ns on a 16 MHz CPU
|
||||
pin13.toggle();
|
||||
delay(100);
|
||||
pin13.toggle();
|
||||
delay(400);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ DigitalPin<13> pin13(OUTPUT);
|
||||
|
||||
void setup() {}
|
||||
|
||||
void loop() {
|
||||
pin13 = pin12;
|
||||
void loop()
|
||||
{
|
||||
pin13 = pin12;
|
||||
}
|
||||
@@ -10,30 +10,34 @@ DigitalPin<13> dataPin(OUTPUT, HIGH);
|
||||
//------------------------------------------------------------------------------
|
||||
// Time to send one bit is ten cycles or 625 ns for 16 MHz CPU.
|
||||
inline __attribute__((always_inline))
|
||||
void sendBit(uint8_t bit, uint8_t data) {
|
||||
dataPin = data & (1 << bit);
|
||||
clockPin = 1;
|
||||
// may want a nop here - clock pulse is 125 ns wide
|
||||
clockPin = 0;
|
||||
void sendBit(uint8_t bit, uint8_t data)
|
||||
{
|
||||
dataPin = data & (1 << bit);
|
||||
clockPin = 1;
|
||||
// may want a nop here - clock pulse is 125 ns wide
|
||||
clockPin = 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Time to send one byte is 5 usec.
|
||||
void shiftOut(uint8_t bits) {
|
||||
sendBit(7, bits);
|
||||
sendBit(6, bits);
|
||||
sendBit(5, bits);
|
||||
sendBit(4, bits);
|
||||
sendBit(3, bits);
|
||||
sendBit(2, bits);
|
||||
sendBit(1, bits);
|
||||
sendBit(0, bits);
|
||||
void shiftOut(uint8_t bits)
|
||||
{
|
||||
sendBit(7, bits);
|
||||
sendBit(6, bits);
|
||||
sendBit(5, bits);
|
||||
sendBit(4, bits);
|
||||
sendBit(3, bits);
|
||||
sendBit(2, bits);
|
||||
sendBit(1, bits);
|
||||
sendBit(0, bits);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
// Not used.
|
||||
void setup()
|
||||
{
|
||||
// Not used.
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
shiftOut(0X55);
|
||||
delay(2);
|
||||
void loop()
|
||||
{
|
||||
shiftOut(0X55);
|
||||
delay(2);
|
||||
}
|
||||
|
||||
@@ -6,19 +6,21 @@
|
||||
PinIO readPin;
|
||||
PinIO writePin;
|
||||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
// Assign pin 12 to readPin.
|
||||
readPin.begin(12);
|
||||
|
||||
// input mode with pull-ups disabled
|
||||
readPin.config(INPUT, LOW);
|
||||
void setup()
|
||||
{
|
||||
// Assign pin 12 to readPin.
|
||||
readPin.begin(12);
|
||||
|
||||
// Assign pin 13 to writePin and set mode to output.
|
||||
writePin.begin(13);
|
||||
writePin.mode(OUTPUT);
|
||||
// input mode with pull-ups disabled
|
||||
readPin.config(INPUT, LOW);
|
||||
|
||||
// Assign pin 13 to writePin and set mode to output.
|
||||
writePin.begin(13);
|
||||
writePin.mode(OUTPUT);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
// Copy the value read from readPin to writePin.
|
||||
writePin.write(readPin.read());
|
||||
void loop()
|
||||
{
|
||||
// Copy the value read from readPin to writePin.
|
||||
writePin.write(readPin.read());
|
||||
}
|
||||
@@ -4,13 +4,15 @@
|
||||
// Set runtime pin number.
|
||||
PinIO pin13(13);
|
||||
|
||||
void setup() {
|
||||
// set mode to OUTPUT and level LOW
|
||||
pin13.config(OUTPUT, LOW);
|
||||
void setup()
|
||||
{
|
||||
// set mode to OUTPUT and level LOW
|
||||
pin13.config(OUTPUT, LOW);
|
||||
}
|
||||
void loop() {
|
||||
pin13.toggle();
|
||||
delay(100);
|
||||
pin13.toggle();
|
||||
delay(400);
|
||||
void loop()
|
||||
{
|
||||
pin13.toggle();
|
||||
delay(100);
|
||||
pin13.toggle();
|
||||
delay(400);
|
||||
}
|
||||
@@ -4,13 +4,15 @@
|
||||
PinIO readPin(12);
|
||||
PinIO writePin(13);
|
||||
|
||||
void setup() {
|
||||
// Set input mode and disable pull-up.
|
||||
readPin.config(INPUT, LOW);
|
||||
void setup()
|
||||
{
|
||||
// Set input mode and disable pull-up.
|
||||
readPin.config(INPUT, LOW);
|
||||
|
||||
// set output mode
|
||||
writePin.mode(OUTPUT);
|
||||
// set output mode
|
||||
writePin.mode(OUTPUT);
|
||||
}
|
||||
void loop() {
|
||||
writePin.write(readPin.read());
|
||||
void loop()
|
||||
{
|
||||
writePin.write(readPin.read());
|
||||
}
|
||||
@@ -26,52 +26,59 @@ const uint8_t SCL_PIN = A5;
|
||||
SoftI2cMaster i2c(SCL_PIN, SDA_PIN);
|
||||
//FastI2cMaster<SCL_PIN, SDA_PIN> i2c;
|
||||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
|
||||
if (!digitalRead(SDA_PIN) && !digitalRead(SCL_PIN)) {
|
||||
Serial.println("External pull-up resistors appear to be missing.");
|
||||
Serial.println("Many false responses may be detected.");
|
||||
Serial.println("Type any character to continue.");
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
|
||||
while (!Serial.available());
|
||||
Serial.println();
|
||||
if (!digitalRead(SDA_PIN) && !digitalRead(SCL_PIN)) {
|
||||
Serial.println("External pull-up resistors appear to be missing.");
|
||||
Serial.println("Many false responses may be detected.");
|
||||
Serial.println("Type any character to continue.");
|
||||
|
||||
}
|
||||
uint8_t add = 0;
|
||||
bool found = false;
|
||||
do {
|
||||
bool wr = i2c.transfer(add | I2C_WRITE, 0, 0);
|
||||
bool rd = i2c.transfer(add | I2C_READ, 0, 0, I2C_CONTINUE);
|
||||
if (rd) {
|
||||
uint8_t dummy;
|
||||
// Must read byte, send NACK, and issue STOP.
|
||||
i2c.transferContinue(&dummy, 1);
|
||||
}
|
||||
if (rd || wr) {
|
||||
found = true;
|
||||
Serial.print("Device at address: 0X");
|
||||
Serial.print(add, HEX);
|
||||
Serial.print(" responds to ");
|
||||
if (rd) Serial.print("Read");
|
||||
if (rd && wr) Serial.print(" and ");
|
||||
if (wr) Serial.print("Write");
|
||||
Serial.println('.');
|
||||
}
|
||||
add += 2;
|
||||
}
|
||||
while (add);
|
||||
while (!Serial.available());
|
||||
Serial.println();
|
||||
|
||||
if (!found) {
|
||||
Serial.println("No devices found.");
|
||||
}
|
||||
Serial.println("Done");
|
||||
}
|
||||
uint8_t add = 0;
|
||||
bool found = false;
|
||||
do {
|
||||
bool wr = i2c.transfer(add | I2C_WRITE, 0, 0);
|
||||
bool rd = i2c.transfer(add | I2C_READ, 0, 0, I2C_CONTINUE);
|
||||
if (rd) {
|
||||
uint8_t dummy;
|
||||
// Must read byte, send NACK, and issue STOP.
|
||||
i2c.transferContinue(&dummy, 1);
|
||||
}
|
||||
if (rd || wr) {
|
||||
found = true;
|
||||
Serial.print("Device at address: 0X");
|
||||
Serial.print(add, HEX);
|
||||
Serial.print(" responds to ");
|
||||
if (rd) {
|
||||
Serial.print("Read");
|
||||
}
|
||||
if (rd && wr) {
|
||||
Serial.print(" and ");
|
||||
}
|
||||
if (wr) {
|
||||
Serial.print("Write");
|
||||
}
|
||||
Serial.println('.');
|
||||
}
|
||||
add += 2;
|
||||
} while (add);
|
||||
|
||||
if (!found) {
|
||||
Serial.println("No devices found.");
|
||||
}
|
||||
Serial.println("Done");
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
// Not used.
|
||||
void loop()
|
||||
{
|
||||
// Not used.
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,30 +16,35 @@ FastI2cMaster<SCL_PIN, SDA_PIN> rtc;
|
||||
/*
|
||||
* Read 'count' bytes from the DS1307 starting at 'address'.
|
||||
*/
|
||||
uint8_t readDS1307(uint8_t address, uint8_t *buf, uint8_t count) {
|
||||
uint8_t readDS1307(uint8_t address, uint8_t *buf, uint8_t count)
|
||||
{
|
||||
|
||||
// Send address of data.
|
||||
if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1)) return false;
|
||||
// Send address of data.
|
||||
if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read data.
|
||||
return rtc.transfer(DS1307ADDR | I2C_READ, buf, count);
|
||||
// Read data.
|
||||
return rtc.transfer(DS1307ADDR | I2C_READ, buf, count);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* write 'count' bytes to DS1307 starting at 'address'.
|
||||
*/
|
||||
uint8_t writeDS1307(uint8_t address, uint8_t *buf, uint8_t count) {
|
||||
uint8_t writeDS1307(uint8_t address, uint8_t *buf, uint8_t count)
|
||||
{
|
||||
|
||||
// Write address and continue transfer for write of data.
|
||||
if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1, I2C_CONTINUE)) {
|
||||
return false;
|
||||
}
|
||||
// Write data.
|
||||
return rtc.transferContinue(buf, count);
|
||||
// Write address and continue transfer for write of data.
|
||||
if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1, I2C_CONTINUE)) {
|
||||
return false;
|
||||
}
|
||||
// Write data.
|
||||
return rtc.transferContinue(buf, count);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Store and print a string in flash memory.*/
|
||||
@@ -50,134 +55,142 @@ void setup(void) {
|
||||
// Day of week U.S. convention.
|
||||
char *Ddd[] = {"Bad", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
//------------------------------------------------------------------------------
|
||||
void hexPrint(uint8_t v) {
|
||||
Serial.print(v >> 4, HEX);
|
||||
Serial.print(v & 0XF, HEX);
|
||||
void hexPrint(uint8_t v)
|
||||
{
|
||||
Serial.print(v >> 4, HEX);
|
||||
Serial.print(v & 0XF, HEX);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void hexPrintln(uint8_t v) {
|
||||
hexPrint(v);
|
||||
Serial.println();
|
||||
void hexPrintln(uint8_t v)
|
||||
{
|
||||
hexPrint(v);
|
||||
Serial.println();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// read hex input
|
||||
uint8_t hexRead(uint16_t* v) {
|
||||
bool valid = false;
|
||||
uint16_t n = 0;
|
||||
while (!Serial.available());
|
||||
while (Serial.available()) {
|
||||
uint8_t c = Serial.read();
|
||||
// Exit if end-of-line.
|
||||
if (c == '\n' || c == '\r') {
|
||||
delay(10);
|
||||
// If CR/LF.
|
||||
Serial.read();
|
||||
break;
|
||||
}
|
||||
n <<= 4;
|
||||
if ('a' <= c && c <= 'f') {
|
||||
n += c - ('a' - 10);
|
||||
}
|
||||
else if ('A' <= c && c <= 'F') {
|
||||
n += c - ('A' - 10);
|
||||
}
|
||||
else if ('0' <= c && c <= '9') {
|
||||
n += c - '0';
|
||||
}
|
||||
else {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
delay(10);
|
||||
valid = true;
|
||||
}
|
||||
if (!valid) {
|
||||
PgmPrintln("Invalid entry");
|
||||
return false;
|
||||
}
|
||||
*v = n;
|
||||
return true;
|
||||
uint8_t hexRead(uint16_t* v)
|
||||
{
|
||||
bool valid = false;
|
||||
uint16_t n = 0;
|
||||
while (!Serial.available());
|
||||
while (Serial.available()) {
|
||||
uint8_t c = Serial.read();
|
||||
// Exit if end-of-line.
|
||||
if (c == '\n' || c == '\r') {
|
||||
delay(10);
|
||||
// If CR/LF.
|
||||
Serial.read();
|
||||
break;
|
||||
}
|
||||
n <<= 4;
|
||||
if ('a' <= c && c <= 'f') {
|
||||
n += c - ('a' - 10);
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
n += c - ('A' - 10);
|
||||
} else if ('0' <= c && c <= '9') {
|
||||
n += c - '0';
|
||||
} else {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
delay(10);
|
||||
valid = true;
|
||||
}
|
||||
if (!valid) {
|
||||
PgmPrintln("Invalid entry");
|
||||
return false;
|
||||
}
|
||||
*v = n;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t bcdRead(uint8_t min, uint8_t max, uint8_t* n) {
|
||||
uint16_t v;
|
||||
if (!hexRead(&v)) return false;
|
||||
uint8_t d = 10 * (v >> 4) + (v & 0XF);
|
||||
if ((v >> 4) > 9 || (v & 0XF) > 9 || d < min || d > max) {
|
||||
PgmPrintln("Invalid");
|
||||
return false;
|
||||
}
|
||||
*n = v;
|
||||
return true;
|
||||
uint8_t bcdRead(uint8_t min, uint8_t max, uint8_t* n)
|
||||
{
|
||||
uint16_t v;
|
||||
if (!hexRead(&v)) {
|
||||
return false;
|
||||
}
|
||||
uint8_t d = 10 * (v >> 4) + (v & 0XF);
|
||||
if ((v >> 4) > 9 || (v & 0XF) > 9 || d < min || d > max) {
|
||||
PgmPrintln("Invalid");
|
||||
return false;
|
||||
}
|
||||
*n = v;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void displayTime(void) {
|
||||
uint8_t r[8];
|
||||
if (!readDS1307(0, r, 8)) {
|
||||
PgmPrintln("Read Failed for display time");
|
||||
return;
|
||||
}
|
||||
PgmPrint("The current time is 20");
|
||||
// year
|
||||
hexPrint(r[6]);
|
||||
Serial.write('-');
|
||||
void displayTime(void)
|
||||
{
|
||||
uint8_t r[8];
|
||||
if (!readDS1307(0, r, 8)) {
|
||||
PgmPrintln("Read Failed for display time");
|
||||
return;
|
||||
}
|
||||
PgmPrint("The current time is 20");
|
||||
// year
|
||||
hexPrint(r[6]);
|
||||
Serial.write('-');
|
||||
|
||||
// month
|
||||
hexPrint(r[5]);
|
||||
Serial.write('-');
|
||||
// month
|
||||
hexPrint(r[5]);
|
||||
Serial.write('-');
|
||||
|
||||
// day
|
||||
hexPrint(r[4]);
|
||||
Serial.write(' ');
|
||||
// day
|
||||
hexPrint(r[4]);
|
||||
Serial.write(' ');
|
||||
|
||||
Serial.print(Ddd[r[3] < 8 ? r[3] : 0]);
|
||||
Serial.write(' ');
|
||||
Serial.print(Ddd[r[3] < 8 ? r[3] : 0]);
|
||||
Serial.write(' ');
|
||||
|
||||
// hour
|
||||
hexPrint(r[2]);
|
||||
Serial.write(':');
|
||||
// hour
|
||||
hexPrint(r[2]);
|
||||
Serial.write(':');
|
||||
|
||||
// minute
|
||||
hexPrint(r[1]);
|
||||
Serial.write(':');
|
||||
// minute
|
||||
hexPrint(r[1]);
|
||||
Serial.write(':');
|
||||
|
||||
// second
|
||||
hexPrintln(r[0]);
|
||||
// second
|
||||
hexPrintln(r[0]);
|
||||
|
||||
// Control register.
|
||||
PgmPrint("Control Register: ");
|
||||
hexPrintln(r[7]);
|
||||
// Control register.
|
||||
PgmPrint("Control Register: ");
|
||||
hexPrintln(r[7]);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// dump registers and 56 bytes of RAM
|
||||
void dumpAll(void) {
|
||||
uint8_t buf[8];
|
||||
for (uint8_t a = 0; a < 64; a += 8) {
|
||||
hexPrint(a);
|
||||
Serial.write(' ');
|
||||
if (!readDS1307(a, buf, 8)) {
|
||||
PgmPrint("read failed for dumpAll");
|
||||
return;
|
||||
}
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
Serial.write(' ');
|
||||
hexPrint(buf[i]);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
void dumpAll(void)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
for (uint8_t a = 0; a < 64; a += 8) {
|
||||
hexPrint(a);
|
||||
Serial.write(' ');
|
||||
if (!readDS1307(a, buf, 8)) {
|
||||
PgmPrint("read failed for dumpAll");
|
||||
return;
|
||||
}
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
Serial.write(' ');
|
||||
hexPrint(buf[i]);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void fillNvRam(void) {
|
||||
uint8_t buf[8];
|
||||
PgmPrint("Enter HEX value for all NV RAM locations (00-FF): ");
|
||||
uint16_t v;
|
||||
if (!hexRead(&v)) return;
|
||||
hexPrint(v);
|
||||
for (uint8_t a = 8; a < 64; a ++) {
|
||||
if (!writeDS1307(a, (uint8_t *)&v, 1)) {
|
||||
PgmPrintln("write failed for fillNvRam");
|
||||
}
|
||||
}
|
||||
void fillNvRam(void)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
PgmPrint("Enter HEX value for all NV RAM locations (00-FF): ");
|
||||
uint16_t v;
|
||||
if (!hexRead(&v)) {
|
||||
return;
|
||||
}
|
||||
hexPrint(v);
|
||||
for (uint8_t a = 8; a < 64; a ++) {
|
||||
if (!writeDS1307(a, (uint8_t *)&v, 1)) {
|
||||
PgmPrintln("write failed for fillNvRam");
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// set control register
|
||||
@@ -205,120 +218,149 @@ RS1 RS0 FREQUENCY
|
||||
1 0 8.192kHz
|
||||
1 1 32.768kHz
|
||||
*/
|
||||
void setControl(void) {
|
||||
PgmPrintln("SQW/OUT pin: ");
|
||||
PgmPrintln("(00) Low");
|
||||
PgmPrintln("(10) 1Hz");
|
||||
PgmPrintln("(11) 4.096kHz");
|
||||
PgmPrintln("(12) 8.192kHz");
|
||||
PgmPrintln("(13) 32.768kHz");
|
||||
PgmPrintln("(80) High");
|
||||
PgmPrint("Enter control: ");
|
||||
uint16_t r;
|
||||
if (!hexRead(&r)) return;
|
||||
hexPrintln(r);
|
||||
if (!writeDS1307(7, (uint8_t *)&r, 1)) {
|
||||
PgmPrint("Write Failed for setControl");
|
||||
}
|
||||
void setControl(void)
|
||||
{
|
||||
PgmPrintln("SQW/OUT pin: ");
|
||||
PgmPrintln("(00) Low");
|
||||
PgmPrintln("(10) 1Hz");
|
||||
PgmPrintln("(11) 4.096kHz");
|
||||
PgmPrintln("(12) 8.192kHz");
|
||||
PgmPrintln("(13) 32.768kHz");
|
||||
PgmPrintln("(80) High");
|
||||
PgmPrint("Enter control: ");
|
||||
uint16_t r;
|
||||
if (!hexRead(&r)) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r);
|
||||
if (!writeDS1307(7, (uint8_t *)&r, 1)) {
|
||||
PgmPrint("Write Failed for setControl");
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setDate(void) {
|
||||
uint8_t r[4];
|
||||
PgmPrint("Enter year (00-99): ");
|
||||
if (!bcdRead(0, 99, &r[3])) return;
|
||||
hexPrintln(r[3]);
|
||||
PgmPrint("Enter month (01-12): ");
|
||||
if (!bcdRead(1, 12, &r[2])) return;
|
||||
hexPrintln(r[2]);
|
||||
PgmPrint("Enter day (01-31): ");
|
||||
if (!bcdRead(1, 31, &r[1])) return;
|
||||
hexPrintln(r[1]);
|
||||
PgmPrint("Enter day of week (01-07, Sun-Sat): ");
|
||||
if (!bcdRead(1, 7, &r[0])) return;
|
||||
hexPrintln(r[0]);
|
||||
void setDate(void)
|
||||
{
|
||||
uint8_t r[4];
|
||||
PgmPrint("Enter year (00-99): ");
|
||||
if (!bcdRead(0, 99, &r[3])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[3]);
|
||||
PgmPrint("Enter month (01-12): ");
|
||||
if (!bcdRead(1, 12, &r[2])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[2]);
|
||||
PgmPrint("Enter day (01-31): ");
|
||||
if (!bcdRead(1, 31, &r[1])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[1]);
|
||||
PgmPrint("Enter day of week (01-07, Sun-Sat): ");
|
||||
if (!bcdRead(1, 7, &r[0])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[0]);
|
||||
|
||||
if (!writeDS1307(3, r, 4)) {
|
||||
PgmPrintln("Write failed for setDate");
|
||||
}
|
||||
if (!writeDS1307(3, r, 4)) {
|
||||
PgmPrintln("Write failed for setDate");
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setNvRam() {
|
||||
uint8_t u;
|
||||
uint16_t a, v;
|
||||
while (true) {
|
||||
PgmPrint("Enter zero to quit or Hex address (8-3F):");
|
||||
if (!hexRead(&a) || a == 0) return;
|
||||
if (a < 8 || a > 0X3F) {
|
||||
PgmPrintln("Invalid address");
|
||||
return;
|
||||
}
|
||||
hexPrintln(a);
|
||||
if (!readDS1307(a, &u, 1)) {
|
||||
PgmPrintln("Read failed");
|
||||
return;
|
||||
}
|
||||
PgmPrint("Current value: ");
|
||||
hexPrintln(u);
|
||||
PgmPrint("Enter new HEX value (00-FF): ");
|
||||
if (!hexRead(&v)) return;
|
||||
hexPrintln(v);
|
||||
if (!writeDS1307(a, (uint8_t *)&v, 1)) {
|
||||
PgmPrint("Write Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
void setNvRam()
|
||||
{
|
||||
uint8_t u;
|
||||
uint16_t a, v;
|
||||
while (true) {
|
||||
PgmPrint("Enter zero to quit or Hex address (8-3F):");
|
||||
if (!hexRead(&a) || a == 0) {
|
||||
return;
|
||||
}
|
||||
if (a < 8 || a > 0X3F) {
|
||||
PgmPrintln("Invalid address");
|
||||
return;
|
||||
}
|
||||
hexPrintln(a);
|
||||
if (!readDS1307(a, &u, 1)) {
|
||||
PgmPrintln("Read failed");
|
||||
return;
|
||||
}
|
||||
PgmPrint("Current value: ");
|
||||
hexPrintln(u);
|
||||
PgmPrint("Enter new HEX value (00-FF): ");
|
||||
if (!hexRead(&v)) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(v);
|
||||
if (!writeDS1307(a, (uint8_t *)&v, 1)) {
|
||||
PgmPrint("Write Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setTime(void) {
|
||||
uint8_t r[3];
|
||||
PgmPrint("Enter hours (00-23): ");
|
||||
if (!bcdRead(0, 23, &r[2])) return;
|
||||
hexPrintln(r[2]);
|
||||
PgmPrint("Enter minutes (00-59): ");
|
||||
if (!bcdRead(0, 59, &r[1])) return;
|
||||
hexPrintln(r[1]);
|
||||
PgmPrint("Enter seconds (00-59): ");
|
||||
if (!bcdRead(0, 59, &r[0])) return;
|
||||
hexPrintln(r[0]);
|
||||
void setTime(void)
|
||||
{
|
||||
uint8_t r[3];
|
||||
PgmPrint("Enter hours (00-23): ");
|
||||
if (!bcdRead(0, 23, &r[2])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[2]);
|
||||
PgmPrint("Enter minutes (00-59): ");
|
||||
if (!bcdRead(0, 59, &r[1])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[1]);
|
||||
PgmPrint("Enter seconds (00-59): ");
|
||||
if (!bcdRead(0, 59, &r[0])) {
|
||||
return;
|
||||
}
|
||||
hexPrintln(r[0]);
|
||||
|
||||
if (!writeDS1307(0, r, 3)) {
|
||||
PgmPrintln("write failed in setTime");
|
||||
return;
|
||||
}
|
||||
if (!writeDS1307(0, r, 3)) {
|
||||
PgmPrintln("write failed in setTime");
|
||||
return;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop(void) {
|
||||
Serial.println();
|
||||
displayTime();
|
||||
while (Serial.read() >= 0) {}
|
||||
PgmPrintln("\nOptions are:");
|
||||
PgmPrintln("(0) Display date and time");
|
||||
PgmPrintln("(1) Set time");
|
||||
PgmPrintln("(2) Set date");
|
||||
PgmPrintln("(3) Set Control");
|
||||
PgmPrintln("(4) Dump all");
|
||||
PgmPrintln("(5) Fill NV RAM");
|
||||
PgmPrintln("(6) Set NV RAM value");
|
||||
PgmPrint("Enter option: ");
|
||||
void loop(void)
|
||||
{
|
||||
Serial.println();
|
||||
displayTime();
|
||||
while (Serial.read() >= 0) {}
|
||||
PgmPrintln("\nOptions are:");
|
||||
PgmPrintln("(0) Display date and time");
|
||||
PgmPrintln("(1) Set time");
|
||||
PgmPrintln("(2) Set date");
|
||||
PgmPrintln("(3) Set Control");
|
||||
PgmPrintln("(4) Dump all");
|
||||
PgmPrintln("(5) Fill NV RAM");
|
||||
PgmPrintln("(6) Set NV RAM value");
|
||||
PgmPrint("Enter option: ");
|
||||
|
||||
uint16_t n;
|
||||
if (!hexRead(&n)) return;
|
||||
Serial.println(n, DEC);
|
||||
if (n == 0) return;
|
||||
Serial.println();
|
||||
if (n == 1) {
|
||||
setTime();
|
||||
} else if (n == 2) {
|
||||
setDate();
|
||||
} else if (n == 3) {
|
||||
setControl();
|
||||
} else if (n == 4) {
|
||||
dumpAll();
|
||||
} else if (n == 5) {
|
||||
fillNvRam();
|
||||
} else if (n == 6) {
|
||||
setNvRam();
|
||||
} else {
|
||||
PgmPrintln("Invalid option");
|
||||
}
|
||||
uint16_t n;
|
||||
if (!hexRead(&n)) {
|
||||
return;
|
||||
}
|
||||
Serial.println(n, DEC);
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
Serial.println();
|
||||
if (n == 1) {
|
||||
setTime();
|
||||
} else if (n == 2) {
|
||||
setDate();
|
||||
} else if (n == 3) {
|
||||
setControl();
|
||||
} else if (n == 4) {
|
||||
dumpAll();
|
||||
} else if (n == 5) {
|
||||
fillNvRam();
|
||||
} else if (n == 6) {
|
||||
setNvRam();
|
||||
} else {
|
||||
PgmPrintln("Invalid option");
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
// Scope test for write timing with Arduino digitaWrite().
|
||||
const uint8_t PIN13 = 13;
|
||||
|
||||
void setup() {
|
||||
// Set mode to OUTPUT.
|
||||
pinMode(PIN13, OUTPUT);
|
||||
void setup()
|
||||
{
|
||||
// Set mode to OUTPUT.
|
||||
pinMode(PIN13, OUTPUT);
|
||||
}
|
||||
void loop() {
|
||||
digitalWrite(PIN13, HIGH);
|
||||
digitalWrite(PIN13, LOW);
|
||||
digitalWrite(PIN13, HIGH);
|
||||
digitalWrite(PIN13, LOW);
|
||||
delay(1);
|
||||
void loop()
|
||||
{
|
||||
digitalWrite(PIN13, HIGH);
|
||||
digitalWrite(PIN13, LOW);
|
||||
digitalWrite(PIN13, HIGH);
|
||||
digitalWrite(PIN13, LOW);
|
||||
delay(1);
|
||||
}
|
||||
@@ -4,16 +4,18 @@
|
||||
// Class with compile time pin number.
|
||||
DigitalPin<13> pin13;
|
||||
|
||||
void setup() {
|
||||
// set mode to OUTPUT
|
||||
pin13.mode(OUTPUT);
|
||||
void setup()
|
||||
{
|
||||
// set mode to OUTPUT
|
||||
pin13.mode(OUTPUT);
|
||||
}
|
||||
void loop() {
|
||||
pin13.high();
|
||||
pin13.low();
|
||||
pin13.write(1);
|
||||
pin13.write(0);
|
||||
pin13.toggle();
|
||||
pin13.toggle();
|
||||
delay(1);
|
||||
void loop()
|
||||
{
|
||||
pin13.high();
|
||||
pin13.low();
|
||||
pin13.write(1);
|
||||
pin13.write(0);
|
||||
pin13.toggle();
|
||||
pin13.toggle();
|
||||
delay(1);
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
// Test fastDigital function timing with a scope.
|
||||
#include <DigitalIO.h>
|
||||
const uint8_t PIN = 13;
|
||||
void setup() {
|
||||
fastPinMode(PIN, OUTPUT);
|
||||
void setup()
|
||||
{
|
||||
fastPinMode(PIN, OUTPUT);
|
||||
}
|
||||
void loop() {
|
||||
fastDigitalWrite(PIN, HIGH);
|
||||
fastDigitalWrite(PIN, LOW);
|
||||
fastDigitalToggle(PIN);
|
||||
fastDigitalToggle(PIN);
|
||||
delay(1);
|
||||
void loop()
|
||||
{
|
||||
fastDigitalWrite(PIN, HIGH);
|
||||
fastDigitalWrite(PIN, LOW);
|
||||
fastDigitalToggle(PIN);
|
||||
fastDigitalToggle(PIN);
|
||||
delay(1);
|
||||
}
|
||||
@@ -4,16 +4,18 @@
|
||||
// Class with runtime pin numbers.
|
||||
PinIO pin(13);
|
||||
|
||||
void setup() {
|
||||
// Set mode to OUTPUT.
|
||||
pin.mode(OUTPUT);
|
||||
void setup()
|
||||
{
|
||||
// Set mode to OUTPUT.
|
||||
pin.mode(OUTPUT);
|
||||
}
|
||||
void loop() {
|
||||
pin.high();
|
||||
pin.low();
|
||||
pin.write(1);
|
||||
pin.write(0);
|
||||
pin.toggle();
|
||||
pin.toggle();
|
||||
delay(1);
|
||||
void loop()
|
||||
{
|
||||
pin.high();
|
||||
pin.low();
|
||||
pin.write(1);
|
||||
pin.write(0);
|
||||
pin.toggle();
|
||||
pin.toggle();
|
||||
delay(1);
|
||||
}
|
||||
@@ -9,29 +9,35 @@ const uint8_t SPI_MODE = 0;
|
||||
SoftSPI<SOFT_SPI_MISO_PIN, SOFT_SPI_MOSI_PIN, SOFT_SPI_SCK_PIN, SPI_MODE> spi;
|
||||
|
||||
int test;
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
spi.begin();
|
||||
while(1) {
|
||||
Serial.println("Enter:");
|
||||
Serial.println("R - Receive");
|
||||
Serial.println("S - Send");
|
||||
Serial.println("T - Transfer");
|
||||
while ((test = Serial.read()) <= 0) {}
|
||||
test = toupper(test);
|
||||
if (strchr("RST", test)) break;
|
||||
Serial.println("Invalid entry");
|
||||
};
|
||||
Serial.print("Starting test ");
|
||||
Serial.println((char)test);
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
spi.begin();
|
||||
while(1) {
|
||||
Serial.println("Enter:");
|
||||
Serial.println("R - Receive");
|
||||
Serial.println("S - Send");
|
||||
Serial.println("T - Transfer");
|
||||
while ((test = Serial.read()) <= 0) {}
|
||||
test = toupper(test);
|
||||
if (strchr("RST", test)) {
|
||||
break;
|
||||
}
|
||||
Serial.println("Invalid entry");
|
||||
};
|
||||
Serial.print("Starting test ");
|
||||
Serial.println((char)test);
|
||||
}
|
||||
void loop() {
|
||||
if (test == 'S') spi.send(0X55);
|
||||
if (test == 'R') {
|
||||
Serial.println(spi.receive(), HEX);
|
||||
}
|
||||
if (test == 'T') {
|
||||
Serial.println(spi.transfer(0XAA), HEX);
|
||||
}
|
||||
delay(10);
|
||||
void loop()
|
||||
{
|
||||
if (test == 'S') {
|
||||
spi.send(0X55);
|
||||
}
|
||||
if (test == 'R') {
|
||||
Serial.println(spi.receive(), HEX);
|
||||
}
|
||||
if (test == 'T') {
|
||||
Serial.println(spi.transfer(0XAA), HEX);
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
@@ -7,92 +7,92 @@
|
||||
#define __digitalWriteFast_h_
|
||||
|
||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA1280) || defined(ARDUINO_AVR_MEGA2560) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
|
||||
#define __digitalPinToPortReg(__pin) \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? &PORTA : \
|
||||
((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &PORTB : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? &PORTC : \
|
||||
((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &PORTD : \
|
||||
((((__pin) <= 3) || (__pin) == 5) ? &PORTE : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? &PORTF : \
|
||||
((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &PORTG : \
|
||||
((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &PORTH : \
|
||||
(((__pin) == 14 || (__pin) == 15) ? &PORTJ : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? &PORTK : &PORTL))))))))))
|
||||
#define __digitalPinToDDRReg(__pin) \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? &DDRA : \
|
||||
((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &DDRB : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? &DDRC : \
|
||||
((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &DDRD : \
|
||||
((((__pin) <= 3) || (__pin) == 5) ? &DDRE : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? &DDRF : \
|
||||
((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &DDRG : \
|
||||
((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &DDRH : \
|
||||
(((__pin) == 14 || (__pin) == 15) ? &DDRJ : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? &DDRK : &DDRL))))))))))
|
||||
#define __digitalPinToPINReg(__pin) \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? &PINA : \
|
||||
((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &PINB : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? &PINC : \
|
||||
((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &PIND : \
|
||||
((((__pin) <= 3) || (__pin) == 5) ? &PINE : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? &PINF : \
|
||||
((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &PING : \
|
||||
((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &PINH : \
|
||||
(((__pin) == 14 || (__pin) == 15) ? &PINJ : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? &PINK : &PINL))))))))))
|
||||
#define __digitalPinToBit(__pin) \
|
||||
(((__pin) >= 7 && (__pin) <= 9) ? (__pin) - 3 : \
|
||||
(((__pin) >= 10 && (__pin) <= 13) ? (__pin) - 6 : \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? (__pin) - 22 : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? 37 - (__pin) : \
|
||||
(((__pin) >= 39 && (__pin) <= 41) ? 41 - (__pin) : \
|
||||
(((__pin) >= 42 && (__pin) <= 49) ? 49 - (__pin) : \
|
||||
(((__pin) >= 50 && (__pin) <= 53) ? 53 - (__pin) : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? (__pin) - 54 : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? (__pin) - 62 : \
|
||||
(((__pin) == 0 || (__pin) == 15 || (__pin) == 17 || (__pin) == 21) ? 0 : \
|
||||
(((__pin) == 1 || (__pin) == 14 || (__pin) == 16 || (__pin) == 20) ? 1 : \
|
||||
(((__pin) == 19) ? 2 : \
|
||||
(((__pin) == 5 || (__pin) == 6 || (__pin) == 18) ? 3 : \
|
||||
(((__pin) == 2) ? 4 : \
|
||||
(((__pin) == 3 || (__pin) == 4) ? 5 : 7)))))))))))))))
|
||||
#define __digitalPinToPortReg(__pin) \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? &PORTA : \
|
||||
((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &PORTB : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? &PORTC : \
|
||||
((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &PORTD : \
|
||||
((((__pin) <= 3) || (__pin) == 5) ? &PORTE : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? &PORTF : \
|
||||
((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &PORTG : \
|
||||
((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &PORTH : \
|
||||
(((__pin) == 14 || (__pin) == 15) ? &PORTJ : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? &PORTK : &PORTL))))))))))
|
||||
#define __digitalPinToDDRReg(__pin) \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? &DDRA : \
|
||||
((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &DDRB : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? &DDRC : \
|
||||
((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &DDRD : \
|
||||
((((__pin) <= 3) || (__pin) == 5) ? &DDRE : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? &DDRF : \
|
||||
((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &DDRG : \
|
||||
((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &DDRH : \
|
||||
(((__pin) == 14 || (__pin) == 15) ? &DDRJ : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? &DDRK : &DDRL))))))))))
|
||||
#define __digitalPinToPINReg(__pin) \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? &PINA : \
|
||||
((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &PINB : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? &PINC : \
|
||||
((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &PIND : \
|
||||
((((__pin) <= 3) || (__pin) == 5) ? &PINE : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? &PINF : \
|
||||
((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &PING : \
|
||||
((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &PINH : \
|
||||
(((__pin) == 14 || (__pin) == 15) ? &PINJ : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? &PINK : &PINL))))))))))
|
||||
#define __digitalPinToBit(__pin) \
|
||||
(((__pin) >= 7 && (__pin) <= 9) ? (__pin) - 3 : \
|
||||
(((__pin) >= 10 && (__pin) <= 13) ? (__pin) - 6 : \
|
||||
(((__pin) >= 22 && (__pin) <= 29) ? (__pin) - 22 : \
|
||||
(((__pin) >= 30 && (__pin) <= 37) ? 37 - (__pin) : \
|
||||
(((__pin) >= 39 && (__pin) <= 41) ? 41 - (__pin) : \
|
||||
(((__pin) >= 42 && (__pin) <= 49) ? 49 - (__pin) : \
|
||||
(((__pin) >= 50 && (__pin) <= 53) ? 53 - (__pin) : \
|
||||
(((__pin) >= 54 && (__pin) <= 61) ? (__pin) - 54 : \
|
||||
(((__pin) >= 62 && (__pin) <= 69) ? (__pin) - 62 : \
|
||||
(((__pin) == 0 || (__pin) == 15 || (__pin) == 17 || (__pin) == 21) ? 0 : \
|
||||
(((__pin) == 1 || (__pin) == 14 || (__pin) == 16 || (__pin) == 20) ? 1 : \
|
||||
(((__pin) == 19) ? 2 : \
|
||||
(((__pin) == 5 || (__pin) == 6 || (__pin) == 18) ? 3 : \
|
||||
(((__pin) == 2) ? 4 : \
|
||||
(((__pin) == 3 || (__pin) == 4) ? 5 : 7)))))))))))))))
|
||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTB : (((__pin) >= 8 && (__pin) <= 15) ? &PORTD : (((__pin) >= 16 && (__pin) <= 23) ? &PORTC : &PORTA)))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRB : (((__pin) >= 8 && (__pin) <= 15) ? &DDRD : (((__pin) >= 8 && (__pin) <= 15) ? &DDRC : &DDRA)))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PINB : (((__pin) >= 8 && (__pin) <= 15) ? &PIND : (((__pin) >= 8 && (__pin) <= 15) ? &PINC : &PINA)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 15) ? (__pin) - 8 : (((__pin) >= 16 && (__pin) <= 23) ? (__pin) - 16 : (__pin) - 24)))
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTB : (((__pin) >= 8 && (__pin) <= 15) ? &PORTD : (((__pin) >= 16 && (__pin) <= 23) ? &PORTC : &PORTA)))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRB : (((__pin) >= 8 && (__pin) <= 15) ? &DDRD : (((__pin) >= 8 && (__pin) <= 15) ? &DDRC : &DDRA)))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PINB : (((__pin) >= 8 && (__pin) <= 15) ? &PIND : (((__pin) >= 8 && (__pin) <= 15) ? &PINC : &PINA)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 15) ? (__pin) - 8 : (((__pin) >= 16 && (__pin) <= 23) ? (__pin) - 16 : (__pin) - 24)))
|
||||
#elif defined(ARDUINO_AVR_LEONARDO) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
|
||||
#define __digitalPinToPortReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &PORTD : (((__pin) == 5 || (__pin) == 13) ? &PORTC : (((__pin) >= 18 && (__pin) <= 23)) ? &PORTF : (((__pin) == 7) ? &PORTE : &PORTB)))
|
||||
#define __digitalPinToDDRReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &DDRD : (((__pin) == 5 || (__pin) == 13) ? &DDRC : (((__pin) >= 18 && (__pin) <= 23)) ? &DDRF : (((__pin) == 7) ? &DDRE : &DDRB)))
|
||||
#define __digitalPinToPINReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &PIND : (((__pin) == 5 || (__pin) == 13) ? &PINC : (((__pin) >= 18 && (__pin) <= 23)) ? &PINF : (((__pin) == 7) ? &PINE : &PINB)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) >= 8 && (__pin) <= 11) ? (__pin) - 4 : (((__pin) >= 18 && (__pin) <= 21) ? 25 - (__pin) : (((__pin) == 0) ? 2 : (((__pin) == 1) ? 3 : (((__pin) == 2) ? 1 : (((__pin) == 3) ? 0 : (((__pin) == 4) ? 4 : (((__pin) == 6) ? 7 : (((__pin) == 13) ? 7 : (((__pin) == 14) ? 3 : (((__pin) == 15) ? 1 : (((__pin) == 16) ? 2 : (((__pin) == 17) ? 0 : (((__pin) == 22) ? 1 : (((__pin) == 23) ? 0 : (((__pin) == 24) ? 4 : (((__pin) == 25) ? 7 : (((__pin) == 26) ? 4 : (((__pin) == 27) ? 5 : 6 )))))))))))))))))))
|
||||
#define __digitalPinToPortReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &PORTD : (((__pin) == 5 || (__pin) == 13) ? &PORTC : (((__pin) >= 18 && (__pin) <= 23)) ? &PORTF : (((__pin) == 7) ? &PORTE : &PORTB)))
|
||||
#define __digitalPinToDDRReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &DDRD : (((__pin) == 5 || (__pin) == 13) ? &DDRC : (((__pin) >= 18 && (__pin) <= 23)) ? &DDRF : (((__pin) == 7) ? &DDRE : &DDRB)))
|
||||
#define __digitalPinToPINReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &PIND : (((__pin) == 5 || (__pin) == 13) ? &PINC : (((__pin) >= 18 && (__pin) <= 23)) ? &PINF : (((__pin) == 7) ? &PINE : &PINB)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) >= 8 && (__pin) <= 11) ? (__pin) - 4 : (((__pin) >= 18 && (__pin) <= 21) ? 25 - (__pin) : (((__pin) == 0) ? 2 : (((__pin) == 1) ? 3 : (((__pin) == 2) ? 1 : (((__pin) == 3) ? 0 : (((__pin) == 4) ? 4 : (((__pin) == 6) ? 7 : (((__pin) == 13) ? 7 : (((__pin) == 14) ? 3 : (((__pin) == 15) ? 1 : (((__pin) == 16) ? 2 : (((__pin) == 17) ? 0 : (((__pin) == 22) ? 1 : (((__pin) == 23) ? 0 : (((__pin) == 24) ? 4 : (((__pin) == 25) ? 7 : (((__pin) == 26) ? 4 : (((__pin) == 27) ? 5 : 6 )))))))))))))))))))
|
||||
#elif defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__)
|
||||
#if defined(__AVR_ATmega328PB__)
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : (((__pin) >= 14 && (__pin) <= 19) ? &PORTC : &PORTE)))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : (((__pin) >= 14 && (__pin) <= 19) ? &DDRC : &DDRE)))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : (((__pin) >= 14 && (__pin) <= 19) ? &PINC : &PINE)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (((__pin) >= 14 && (__pin) <= 19) ? (__pin) - 14 : (((__pin) >= 20 && (__pin) <= 21) ? (__pin) - 18 : (__pin) - 22))))
|
||||
#else
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : &PORTC))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : &DDRC))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : &PINC))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (__pin) - 14))
|
||||
#endif
|
||||
#if defined(__AVR_ATmega328PB__)
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : (((__pin) >= 14 && (__pin) <= 19) ? &PORTC : &PORTE)))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : (((__pin) >= 14 && (__pin) <= 19) ? &DDRC : &DDRE)))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : (((__pin) >= 14 && (__pin) <= 19) ? &PINC : &PINE)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (((__pin) >= 14 && (__pin) <= 19) ? (__pin) - 14 : (((__pin) >= 20 && (__pin) <= 21) ? (__pin) - 18 : (__pin) - 22))))
|
||||
#else
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : &PORTC))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : &DDRC))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : &PINC))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (__pin) - 14))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_AVR)
|
||||
#if !defined(__atomicWrite)
|
||||
#define __atomicWrite(A,P,V) do { if ((A) < 0x40) {bitWrite((A), (P), (V) );} else {uint8_t register saveSreg = SREG;cli();bitWrite((A), (P), (V));SREG = saveSreg;}} while(0)
|
||||
#endif
|
||||
#if !defined(digitalWriteFast)
|
||||
#define digitalWriteFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToPortReg(__pin), __digitalPinToBit(__pin), (__value)); } else { digitalWrite((__pin), (__value)); } } while (0)
|
||||
#endif
|
||||
#if !defined(pinModeFast)
|
||||
#define pinModeFast(__pin, __mode) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__mode) && (__mode!=INPUT_PULLUP)) { bitWrite(*__digitalPinToDDRReg(__pin), __digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0)
|
||||
#endif
|
||||
#if !defined(digitalReadFast)
|
||||
#define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), __digitalPinToBit(__pin))) ) : digitalRead((__pin)) )
|
||||
#endif
|
||||
#if !defined(__atomicWrite)
|
||||
#define __atomicWrite(A,P,V) do { if ((A) < 0x40) {bitWrite((A), (P), (V) );} else {uint8_t register saveSreg = SREG;cli();bitWrite((A), (P), (V));SREG = saveSreg;}} while(0)
|
||||
#endif
|
||||
#if !defined(digitalWriteFast)
|
||||
#define digitalWriteFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToPortReg(__pin), __digitalPinToBit(__pin), (__value)); } else { digitalWrite((__pin), (__value)); } } while (0)
|
||||
#endif
|
||||
#if !defined(pinModeFast)
|
||||
#define pinModeFast(__pin, __mode) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__mode) && (__mode!=INPUT_PULLUP)) { bitWrite(*__digitalPinToDDRReg(__pin), __digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0)
|
||||
#endif
|
||||
#if !defined(digitalReadFast)
|
||||
#define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), __digitalPinToBit(__pin))) ) : digitalRead((__pin)) )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* An Alternative Software Serial Library
|
||||
* http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
|
||||
* Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -44,28 +44,61 @@ class AltSoftSerial : public Stream
|
||||
{
|
||||
public:
|
||||
AltSoftSerial() { } //!< Constructor
|
||||
~AltSoftSerial() { end(); } //!< Destructor
|
||||
static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } //!< begin
|
||||
~AltSoftSerial()
|
||||
{
|
||||
end(); //!< Destructor
|
||||
}
|
||||
static void begin(uint32_t baud)
|
||||
{
|
||||
init((ALTSS_BASE_FREQ + baud / 2) / baud); //!< begin
|
||||
}
|
||||
static void end(); //!< end
|
||||
int peek(); //!< peek
|
||||
int read(); //!< read
|
||||
int available(); //!< available
|
||||
#if ARDUINO >= 100
|
||||
size_t write(uint8_t byte) { writeByte(byte); return 1; } //!< write
|
||||
void flush() { flushOutput(); } //!< flush
|
||||
size_t write(uint8_t byte)
|
||||
{
|
||||
writeByte(byte); //!< write
|
||||
return 1;
|
||||
}
|
||||
void flush()
|
||||
{
|
||||
flushOutput(); //!< flush
|
||||
}
|
||||
#else
|
||||
void write(uint8_t byte) { writeByte(byte); } //!< write
|
||||
void flush() { flushInput(); } //!< flush
|
||||
void write(uint8_t byte)
|
||||
{
|
||||
writeByte(byte); //!< write
|
||||
}
|
||||
void flush()
|
||||
{
|
||||
flushInput(); //!< flush
|
||||
}
|
||||
#endif
|
||||
using Print::write;
|
||||
static void flushInput(); //!< flushInput
|
||||
static void flushOutput(); //!< flushOutput
|
||||
// for drop-in compatibility with NewSoftSerial, rxPin & txPin ignored
|
||||
//AltSoftSerial(uint8_t rxPin, uint8_t txPin, bool inverse = false) { }
|
||||
bool listen() { return false; } //!< listen
|
||||
bool isListening() { return true; } //!< isListening
|
||||
bool overflow() { bool r = timing_error; timing_error = false; return r; } //!< overflow
|
||||
static int library_version() { return 1; } //!< library_version
|
||||
bool listen()
|
||||
{
|
||||
return false; //!< listen
|
||||
}
|
||||
bool isListening()
|
||||
{
|
||||
return true; //!< isListening
|
||||
}
|
||||
bool overflow()
|
||||
{
|
||||
bool r = timing_error; //!< overflow
|
||||
timing_error = false;
|
||||
return r;
|
||||
}
|
||||
static int library_version()
|
||||
{
|
||||
return 1; //!< library_version
|
||||
}
|
||||
static void enable_timer0(bool) { } //!< enable_timer0
|
||||
static bool timing_error; //!< timing_error
|
||||
private:
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* An Alternative Software Serial Library
|
||||
* http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
|
||||
* Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -26,15 +26,15 @@
|
||||
//
|
||||
#if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
|
||||
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 22 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 14 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 22 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 14 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM
|
||||
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 10 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 10 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
|
||||
|
||||
|
||||
@@ -42,41 +42,41 @@
|
||||
//
|
||||
#elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
|
||||
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 4 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 25 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 26 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 27 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 4 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 25 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 26 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 27 // unusable PWM
|
||||
|
||||
//#define ALTSS_USE_TIMER3
|
||||
//#define INPUT_CAPTURE_PIN 17 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 16 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER3
|
||||
//#define INPUT_CAPTURE_PIN 17 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 16 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM
|
||||
|
||||
|
||||
// Teensy 3.0 & 3.1
|
||||
//
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
|
||||
#define ALTSS_USE_FTM0
|
||||
#define INPUT_CAPTURE_PIN 20 // receive (FTM0_CH5)
|
||||
#define OUTPUT_COMPARE_A_PIN 21 // transmit (FTM0_CH6)
|
||||
#define OUTPUT_COMPARE_B_PIN 22 // unusable PWM (FTM0_CH0)
|
||||
#define OUTPUT_COMPARE_C_PIN 23 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_D_PIN 5 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_E_PIN 6 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_F_PIN 9 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_G_PIN 10 // PWM usable fixed freq
|
||||
#define ALTSS_USE_FTM0
|
||||
#define INPUT_CAPTURE_PIN 20 // receive (FTM0_CH5)
|
||||
#define OUTPUT_COMPARE_A_PIN 21 // transmit (FTM0_CH6)
|
||||
#define OUTPUT_COMPARE_B_PIN 22 // unusable PWM (FTM0_CH0)
|
||||
#define OUTPUT_COMPARE_C_PIN 23 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_D_PIN 5 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_E_PIN 6 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_F_PIN 9 // PWM usable fixed freq
|
||||
#define OUTPUT_COMPARE_G_PIN 10 // PWM usable fixed freq
|
||||
|
||||
|
||||
// Wiring-S
|
||||
//
|
||||
#elif defined(__AVR_ATmega644P__) && defined(WIRING)
|
||||
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 6 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 4 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 6 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 4 // unusable PWM
|
||||
|
||||
|
||||
|
||||
@@ -84,51 +84,51 @@
|
||||
//
|
||||
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 8 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 8 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
|
||||
|
||||
// Arduino Leonardo & Yun (from Cristian Maglie)
|
||||
//
|
||||
#elif defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_LEONARDO) || defined(__AVR_ATmega32U4__)
|
||||
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 4 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 4 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM
|
||||
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 13 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 13 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
|
||||
|
||||
// Arduino Mega
|
||||
//
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
|
||||
//#define ALTSS_USE_TIMER4
|
||||
//#define INPUT_CAPTURE_PIN 49 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 6 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER4
|
||||
//#define INPUT_CAPTURE_PIN 49 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 6 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM
|
||||
|
||||
#define ALTSS_USE_TIMER5
|
||||
#define INPUT_CAPTURE_PIN 48 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 46 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 45 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 44 // unusable PWM
|
||||
#define ALTSS_USE_TIMER5
|
||||
#define INPUT_CAPTURE_PIN 48 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 46 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 45 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 44 // unusable PWM
|
||||
|
||||
|
||||
|
||||
// Sanguino
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 14 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 13 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 12 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 14 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 13 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 12 // unusable PWM
|
||||
|
||||
|
||||
// Unknown board
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* An Alternative Software Serial Library
|
||||
* http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
|
||||
* Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -22,153 +22,153 @@
|
||||
*/
|
||||
|
||||
#if defined(ALTSS_USE_TIMER1)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS10))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS11))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR1A = TCCR1A & ~((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR1A = (TCCR1A | (1<<COM1A1)) & ~(1<<COM1A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR1A = TCCR1A | ((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR1B &= ~(1<<ICES1))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR1B |= (1<<ICES1))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR1 = (1<<ICF1), TIMSK1 = (1<<ICIE1))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR1 = (1<<OCF1A), TIMSK1 |= (1<<OCIE1A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR1 = (1<<OCF1B), TIMSK1 |= (1<<OCIE1B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK1 &= ~(1<<ICIE1))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK1 &= ~(1<<OCIE1A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK1 &= ~(1<<OCIE1B))
|
||||
#define GET_TIMER_COUNT() (TCNT1)
|
||||
#define GET_INPUT_CAPTURE() (ICR1)
|
||||
#define GET_COMPARE_A() (OCR1A)
|
||||
#define GET_COMPARE_B() (OCR1B)
|
||||
#define SET_COMPARE_A(val) (OCR1A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR1B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER1_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER1_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER1_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS10))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS11))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR1A = TCCR1A & ~((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR1A = (TCCR1A | (1<<COM1A1)) & ~(1<<COM1A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR1A = TCCR1A | ((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR1B &= ~(1<<ICES1))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR1B |= (1<<ICES1))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR1 = (1<<ICF1), TIMSK1 = (1<<ICIE1))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR1 = (1<<OCF1A), TIMSK1 |= (1<<OCIE1A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR1 = (1<<OCF1B), TIMSK1 |= (1<<OCIE1B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK1 &= ~(1<<ICIE1))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK1 &= ~(1<<OCIE1A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK1 &= ~(1<<OCIE1B))
|
||||
#define GET_TIMER_COUNT() (TCNT1)
|
||||
#define GET_INPUT_CAPTURE() (ICR1)
|
||||
#define GET_COMPARE_A() (OCR1A)
|
||||
#define GET_COMPARE_B() (OCR1B)
|
||||
#define SET_COMPARE_A(val) (OCR1A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR1B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER1_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER1_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER1_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_TIMER3)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS30))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS31))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR3A = TCCR3A & ~((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR3A = (TCCR3A & ~(1<<COM3A1)) | (1<<COM3A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR3A = (TCCR3A | (1<<COM3A1)) & ~(1<<COM3A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR3A = TCCR3A | ((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR3B &= ~(1<<ICES3))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR3B |= (1<<ICES3))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR3 = (1<<ICF3), TIMSK3 = (1<<ICIE3))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR3 = (1<<OCF3A), TIMSK3 |= (1<<OCIE3A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR3 = (1<<OCF3B), TIMSK3 |= (1<<OCIE3B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK3 &= ~(1<<ICIE3))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK3 &= ~(1<<OCIE3A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK3 &= ~(1<<OCIE3B))
|
||||
#define GET_TIMER_COUNT() (TCNT3)
|
||||
#define GET_INPUT_CAPTURE() (ICR3)
|
||||
#define GET_COMPARE_A() (OCR3A)
|
||||
#define GET_COMPARE_B() (OCR3B)
|
||||
#define SET_COMPARE_A(val) (OCR3A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR3B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER3_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER3_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER3_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS30))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS31))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR3A = TCCR3A & ~((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR3A = (TCCR3A & ~(1<<COM3A1)) | (1<<COM3A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR3A = (TCCR3A | (1<<COM3A1)) & ~(1<<COM3A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR3A = TCCR3A | ((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR3B &= ~(1<<ICES3))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR3B |= (1<<ICES3))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR3 = (1<<ICF3), TIMSK3 = (1<<ICIE3))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR3 = (1<<OCF3A), TIMSK3 |= (1<<OCIE3A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR3 = (1<<OCF3B), TIMSK3 |= (1<<OCIE3B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK3 &= ~(1<<ICIE3))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK3 &= ~(1<<OCIE3A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK3 &= ~(1<<OCIE3B))
|
||||
#define GET_TIMER_COUNT() (TCNT3)
|
||||
#define GET_INPUT_CAPTURE() (ICR3)
|
||||
#define GET_COMPARE_A() (OCR3A)
|
||||
#define GET_COMPARE_B() (OCR3B)
|
||||
#define SET_COMPARE_A(val) (OCR3A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR3B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER3_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER3_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER3_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_TIMER4)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS40))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS41))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR4A = TCCR4A & ~((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR4A = (TCCR4A & ~(1<<COM4A1)) | (1<<COM4A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR4A = (TCCR4A | (1<<COM4A1)) & ~(1<<COM4A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR4A = TCCR4A | ((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR4B &= ~(1<<ICES4))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR4B |= (1<<ICES4))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR4 = (1<<ICF4), TIMSK4 = (1<<ICIE4))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR4 = (1<<OCF4A), TIMSK4 |= (1<<OCIE4A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR4 = (1<<OCF4B), TIMSK4 |= (1<<OCIE4B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK4 &= ~(1<<ICIE4))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK4 &= ~(1<<OCIE4A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK4 &= ~(1<<OCIE4B))
|
||||
#define GET_TIMER_COUNT() (TCNT4)
|
||||
#define GET_INPUT_CAPTURE() (ICR4)
|
||||
#define GET_COMPARE_A() (OCR4A)
|
||||
#define GET_COMPARE_B() (OCR4B)
|
||||
#define SET_COMPARE_A(val) (OCR4A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR4B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER4_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER4_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER4_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS40))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS41))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR4A = TCCR4A & ~((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR4A = (TCCR4A & ~(1<<COM4A1)) | (1<<COM4A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR4A = (TCCR4A | (1<<COM4A1)) & ~(1<<COM4A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR4A = TCCR4A | ((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR4B &= ~(1<<ICES4))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR4B |= (1<<ICES4))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR4 = (1<<ICF4), TIMSK4 = (1<<ICIE4))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR4 = (1<<OCF4A), TIMSK4 |= (1<<OCIE4A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR4 = (1<<OCF4B), TIMSK4 |= (1<<OCIE4B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK4 &= ~(1<<ICIE4))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK4 &= ~(1<<OCIE4A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK4 &= ~(1<<OCIE4B))
|
||||
#define GET_TIMER_COUNT() (TCNT4)
|
||||
#define GET_INPUT_CAPTURE() (ICR4)
|
||||
#define GET_COMPARE_A() (OCR4A)
|
||||
#define GET_COMPARE_B() (OCR4B)
|
||||
#define SET_COMPARE_A(val) (OCR4A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR4B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER4_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER4_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER4_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_TIMER5)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS50))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS51))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR5A = TCCR5A & ~((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR5A = (TCCR5A & ~(1<<COM5A1)) | (1<<COM5A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR5A = (TCCR5A | (1<<COM5A1)) & ~(1<<COM5A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR5A = TCCR5A | ((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR5B &= ~(1<<ICES5))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR5B |= (1<<ICES5))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR5 = (1<<ICF5), TIMSK5 = (1<<ICIE5))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR5 = (1<<OCF5A), TIMSK5 |= (1<<OCIE5A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR5 = (1<<OCF5B), TIMSK5 |= (1<<OCIE5B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK5 &= ~(1<<ICIE5))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK5 &= ~(1<<OCIE5A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK5 &= ~(1<<OCIE5B))
|
||||
#define GET_TIMER_COUNT() (TCNT5)
|
||||
#define GET_INPUT_CAPTURE() (ICR5)
|
||||
#define GET_COMPARE_A() (OCR5A)
|
||||
#define GET_COMPARE_B() (OCR5B)
|
||||
#define SET_COMPARE_A(val) (OCR5A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR5B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER5_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER5_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER5_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS50))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS51))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR5A = TCCR5A & ~((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR5A = (TCCR5A & ~(1<<COM5A1)) | (1<<COM5A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR5A = (TCCR5A | (1<<COM5A1)) & ~(1<<COM5A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR5A = TCCR5A | ((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR5B &= ~(1<<ICES5))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR5B |= (1<<ICES5))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR5 = (1<<ICF5), TIMSK5 = (1<<ICIE5))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR5 = (1<<OCF5A), TIMSK5 |= (1<<OCIE5A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR5 = (1<<OCF5B), TIMSK5 |= (1<<OCIE5B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK5 &= ~(1<<ICIE5))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK5 &= ~(1<<OCIE5A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK5 &= ~(1<<OCIE5B))
|
||||
#define GET_TIMER_COUNT() (TCNT5)
|
||||
#define GET_INPUT_CAPTURE() (ICR5)
|
||||
#define GET_COMPARE_A() (OCR5A)
|
||||
#define GET_COMPARE_B() (OCR5B)
|
||||
#define SET_COMPARE_A(val) (OCR5A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR5B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER5_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER5_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER5_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_FTM0)
|
||||
// CH5 = input capture (input, pin 20)
|
||||
// CH6 = compare a (output, pin 21)
|
||||
// CH0 = compare b (input timeout)
|
||||
#define CONFIG_TIMER_NOPRESCALE() FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; \
|
||||
FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); \
|
||||
digitalWriteFast(21, HIGH); \
|
||||
NVIC_SET_PRIORITY(IRQ_FTM0, 48); \
|
||||
NVIC_ENABLE_IRQ(IRQ_FTM0);
|
||||
#define CONFIG_TIMER_PRESCALE_8() FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; \
|
||||
FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(3); \
|
||||
digitalWriteFast(21, HIGH); \
|
||||
NVIC_SET_PRIORITY(IRQ_FTM0, 48); \
|
||||
NVIC_ENABLE_IRQ(IRQ_FTM0);
|
||||
#define CONFIG_MATCH_NORMAL() (FTM0_C6SC = 0)
|
||||
#define CONFIG_MATCH_TOGGLE() (FTM0_C6SC = (FTM0_C6SC & 0xC3) | 0x14)
|
||||
#define CONFIG_MATCH_CLEAR() (FTM0_C6SC = (FTM0_C6SC & 0xC3) | 0x18)
|
||||
#define CONFIG_MATCH_SET() (FTM0_C6SC = (FTM0_C6SC & 0xC3) | 0x1C)
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (FTM0_C5SC = (FTM0_C5SC & 0xC3) | 0x08)
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (FTM0_C5SC = (FTM0_C5SC & 0xC3) | 0x04)
|
||||
#define ENABLE_INT_INPUT_CAPTURE() FTM0_C5SC = 0x48; \
|
||||
CORE_PIN20_CONFIG = PORT_PCR_MUX(4)|PORT_PCR_PE|PORT_PCR_PS
|
||||
#define ENABLE_INT_COMPARE_A() FTM0_C6SC |= 0x40; \
|
||||
CORE_PIN21_CONFIG = PORT_PCR_MUX(4)|PORT_PCR_DSE|PORT_PCR_SRE
|
||||
#define ENABLE_INT_COMPARE_B() (FTM0_C0SC |= 0x40)
|
||||
#define DISABLE_INT_INPUT_CAPTURE() FTM0_C5SC &= ~0x40; \
|
||||
CORE_PIN20_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_PE|PORT_PCR_PS
|
||||
#define DISABLE_INT_COMPARE_A() FTM0_C6SC &= ~0x40; \
|
||||
CORE_PIN21_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE; \
|
||||
digitalWriteFast(21, HIGH)
|
||||
#define DISABLE_INT_COMPARE_B() (FTM0_C0SC &= ~0x40)
|
||||
#define GET_TIMER_COUNT() (FTM0_CNT)
|
||||
#define GET_INPUT_CAPTURE() (FTM0_C5V)
|
||||
#define GET_COMPARE_A() (FTM0_C6V)
|
||||
#define GET_COMPARE_B() (FTM0_C0V)
|
||||
#define SET_COMPARE_A(val) (FTM0_C6V = val)
|
||||
#define SET_COMPARE_B(val) (FTM0_C0V = val)
|
||||
#define CAPTURE_INTERRUPT altss_capture_interrupt
|
||||
#define COMPARE_A_INTERRUPT altss_compare_a_interrupt
|
||||
#define COMPARE_B_INTERRUPT altss_compare_b_interrupt
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) static void f (void)
|
||||
// CH5 = input capture (input, pin 20)
|
||||
// CH6 = compare a (output, pin 21)
|
||||
// CH0 = compare b (input timeout)
|
||||
#define CONFIG_TIMER_NOPRESCALE() FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; \
|
||||
FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); \
|
||||
digitalWriteFast(21, HIGH); \
|
||||
NVIC_SET_PRIORITY(IRQ_FTM0, 48); \
|
||||
NVIC_ENABLE_IRQ(IRQ_FTM0);
|
||||
#define CONFIG_TIMER_PRESCALE_8() FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; \
|
||||
FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(3); \
|
||||
digitalWriteFast(21, HIGH); \
|
||||
NVIC_SET_PRIORITY(IRQ_FTM0, 48); \
|
||||
NVIC_ENABLE_IRQ(IRQ_FTM0);
|
||||
#define CONFIG_MATCH_NORMAL() (FTM0_C6SC = 0)
|
||||
#define CONFIG_MATCH_TOGGLE() (FTM0_C6SC = (FTM0_C6SC & 0xC3) | 0x14)
|
||||
#define CONFIG_MATCH_CLEAR() (FTM0_C6SC = (FTM0_C6SC & 0xC3) | 0x18)
|
||||
#define CONFIG_MATCH_SET() (FTM0_C6SC = (FTM0_C6SC & 0xC3) | 0x1C)
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (FTM0_C5SC = (FTM0_C5SC & 0xC3) | 0x08)
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (FTM0_C5SC = (FTM0_C5SC & 0xC3) | 0x04)
|
||||
#define ENABLE_INT_INPUT_CAPTURE() FTM0_C5SC = 0x48; \
|
||||
CORE_PIN20_CONFIG = PORT_PCR_MUX(4)|PORT_PCR_PE|PORT_PCR_PS
|
||||
#define ENABLE_INT_COMPARE_A() FTM0_C6SC |= 0x40; \
|
||||
CORE_PIN21_CONFIG = PORT_PCR_MUX(4)|PORT_PCR_DSE|PORT_PCR_SRE
|
||||
#define ENABLE_INT_COMPARE_B() (FTM0_C0SC |= 0x40)
|
||||
#define DISABLE_INT_INPUT_CAPTURE() FTM0_C5SC &= ~0x40; \
|
||||
CORE_PIN20_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_PE|PORT_PCR_PS
|
||||
#define DISABLE_INT_COMPARE_A() FTM0_C6SC &= ~0x40; \
|
||||
CORE_PIN21_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE; \
|
||||
digitalWriteFast(21, HIGH)
|
||||
#define DISABLE_INT_COMPARE_B() (FTM0_C0SC &= ~0x40)
|
||||
#define GET_TIMER_COUNT() (FTM0_CNT)
|
||||
#define GET_INPUT_CAPTURE() (FTM0_C5V)
|
||||
#define GET_COMPARE_A() (FTM0_C6V)
|
||||
#define GET_COMPARE_B() (FTM0_C0V)
|
||||
#define SET_COMPARE_A(val) (FTM0_C6V = val)
|
||||
#define SET_COMPARE_B(val) (FTM0_C0V = val)
|
||||
#define CAPTURE_INTERRUPT altss_capture_interrupt
|
||||
#define COMPARE_A_INTERRUPT altss_compare_a_interrupt
|
||||
#define COMPARE_B_INTERRUPT altss_compare_b_interrupt
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) static void f (void)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
//
|
||||
#if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
|
||||
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 22 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 14 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 22 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 14 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM
|
||||
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 10 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 10 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
|
||||
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
//
|
||||
#elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
|
||||
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 4 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 25 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 26 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 27 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 4 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 25 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 26 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 27 // unusable PWM
|
||||
|
||||
//#define ALTSS_USE_TIMER3
|
||||
//#define INPUT_CAPTURE_PIN 17 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 16 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER3
|
||||
//#define INPUT_CAPTURE_PIN 17 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 16 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM
|
||||
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
//
|
||||
#elif defined(__AVR_ATmega644P__) && defined(WIRING)
|
||||
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 6 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 4 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 6 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 4 // unusable PWM
|
||||
|
||||
|
||||
|
||||
@@ -49,51 +49,51 @@
|
||||
//
|
||||
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 8 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 8 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
|
||||
|
||||
// Arduino Leonardo & Yun (from Cristian Maglie)
|
||||
//
|
||||
#elif defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_LEONARDO)
|
||||
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 4 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER1
|
||||
//#define INPUT_CAPTURE_PIN 4 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 9 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM
|
||||
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 13 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
#define ALTSS_USE_TIMER3
|
||||
#define INPUT_CAPTURE_PIN 13 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 5 // transmit
|
||||
|
||||
|
||||
// Arduino Mega
|
||||
//
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
|
||||
//#define ALTSS_USE_TIMER4
|
||||
//#define INPUT_CAPTURE_PIN 49 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 6 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM
|
||||
//#define ALTSS_USE_TIMER4
|
||||
//#define INPUT_CAPTURE_PIN 49 // receive
|
||||
//#define OUTPUT_COMPARE_A_PIN 6 // transmit
|
||||
//#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM
|
||||
//#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM
|
||||
|
||||
#define ALTSS_USE_TIMER5
|
||||
#define INPUT_CAPTURE_PIN 48 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 46 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 45 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 44 // unusable PWM
|
||||
#define ALTSS_USE_TIMER5
|
||||
#define INPUT_CAPTURE_PIN 48 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 46 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 45 // unusable PWM
|
||||
#define OUTPUT_COMPARE_C_PIN 44 // unusable PWM
|
||||
|
||||
|
||||
|
||||
// Sanguino
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 14 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 13 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 12 // unusable PWM
|
||||
#define ALTSS_USE_TIMER1
|
||||
#define INPUT_CAPTURE_PIN 14 // receive
|
||||
#define OUTPUT_COMPARE_A_PIN 13 // transmit
|
||||
#define OUTPUT_COMPARE_B_PIN 12 // unusable PWM
|
||||
|
||||
|
||||
// Unknown board
|
||||
|
||||
@@ -1,106 +1,106 @@
|
||||
|
||||
#if defined(ALTSS_USE_TIMER1)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS10))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS11))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR1A = TCCR1A & ~((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR1A = (TCCR1A | (1<<COM1A1)) & ~(1<<COM1A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR1A = TCCR1A | ((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR1B &= ~(1<<ICES1))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR1B |= (1<<ICES1))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR1 = (1<<ICF1), TIMSK1 = (1<<ICIE1))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR1 = (1<<OCF1A), TIMSK1 |= (1<<OCIE1A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR1 = (1<<OCF1B), TIMSK1 |= (1<<OCIE1B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK1 &= ~(1<<ICIE1))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK1 &= ~(1<<OCIE1A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK1 &= ~(1<<OCIE1B))
|
||||
#define GET_TIMER_COUNT() (TCNT1)
|
||||
#define GET_INPUT_CAPTURE() (ICR1)
|
||||
#define GET_COMPARE_A() (OCR1A)
|
||||
#define GET_COMPARE_B() (OCR1B)
|
||||
#define SET_COMPARE_A(val) (OCR1A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR1B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER1_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER1_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER1_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS10))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<<ICNC1) | (1<<CS11))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR1A = TCCR1A & ~((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR1A = (TCCR1A | (1<<COM1A1)) & ~(1<<COM1A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR1A = TCCR1A | ((1<<COM1A1) | (1<<COM1A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR1B &= ~(1<<ICES1))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR1B |= (1<<ICES1))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR1 = (1<<ICF1), TIMSK1 = (1<<ICIE1))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR1 = (1<<OCF1A), TIMSK1 |= (1<<OCIE1A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR1 = (1<<OCF1B), TIMSK1 |= (1<<OCIE1B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK1 &= ~(1<<ICIE1))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK1 &= ~(1<<OCIE1A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK1 &= ~(1<<OCIE1B))
|
||||
#define GET_TIMER_COUNT() (TCNT1)
|
||||
#define GET_INPUT_CAPTURE() (ICR1)
|
||||
#define GET_COMPARE_A() (OCR1A)
|
||||
#define GET_COMPARE_B() (OCR1B)
|
||||
#define SET_COMPARE_A(val) (OCR1A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR1B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER1_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER1_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER1_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_TIMER3)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS30))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS31))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR3A = TCCR3A & ~((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR3A = (TCCR3A & ~(1<<COM3A1)) | (1<<COM3A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR3A = (TCCR3A | (1<<COM3A1)) & ~(1<<COM3A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR3A = TCCR3A | ((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR3B &= ~(1<<ICES3))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR3B |= (1<<ICES3))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR3 = (1<<ICF3), TIMSK3 = (1<<ICIE3))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR3 = (1<<OCF3A), TIMSK3 |= (1<<OCIE3A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR3 = (1<<OCF3B), TIMSK3 |= (1<<OCIE3B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK3 &= ~(1<<ICIE3))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK3 &= ~(1<<OCIE3A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK3 &= ~(1<<OCIE3B))
|
||||
#define GET_TIMER_COUNT() (TCNT3)
|
||||
#define GET_INPUT_CAPTURE() (ICR3)
|
||||
#define GET_COMPARE_A() (OCR3A)
|
||||
#define GET_COMPARE_B() (OCR3B)
|
||||
#define SET_COMPARE_A(val) (OCR3A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR3B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER3_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER3_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER3_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS30))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS31))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR3A = TCCR3A & ~((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR3A = (TCCR3A & ~(1<<COM3A1)) | (1<<COM3A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR3A = (TCCR3A | (1<<COM3A1)) & ~(1<<COM3A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR3A = TCCR3A | ((1<<COM3A1) | (1<<COM3A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR3B &= ~(1<<ICES3))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR3B |= (1<<ICES3))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR3 = (1<<ICF3), TIMSK3 = (1<<ICIE3))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR3 = (1<<OCF3A), TIMSK3 |= (1<<OCIE3A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR3 = (1<<OCF3B), TIMSK3 |= (1<<OCIE3B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK3 &= ~(1<<ICIE3))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK3 &= ~(1<<OCIE3A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK3 &= ~(1<<OCIE3B))
|
||||
#define GET_TIMER_COUNT() (TCNT3)
|
||||
#define GET_INPUT_CAPTURE() (ICR3)
|
||||
#define GET_COMPARE_A() (OCR3A)
|
||||
#define GET_COMPARE_B() (OCR3B)
|
||||
#define SET_COMPARE_A(val) (OCR3A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR3B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER3_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER3_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER3_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_TIMER4)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS40))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS41))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR4A = TCCR4A & ~((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR4A = (TCCR4A & ~(1<<COM4A1)) | (1<<COM4A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR4A = (TCCR4A | (1<<COM4A1)) & ~(1<<COM4A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR4A = TCCR4A | ((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR4B &= ~(1<<ICES4))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR4B |= (1<<ICES4))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR4 = (1<<ICF4), TIMSK4 = (1<<ICIE4))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR4 = (1<<OCF4A), TIMSK4 |= (1<<OCIE4A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR4 = (1<<OCF4B), TIMSK4 |= (1<<OCIE4B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK4 &= ~(1<<ICIE4))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK4 &= ~(1<<OCIE4A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK4 &= ~(1<<OCIE4B))
|
||||
#define GET_TIMER_COUNT() (TCNT4)
|
||||
#define GET_INPUT_CAPTURE() (ICR4)
|
||||
#define GET_COMPARE_A() (OCR4A)
|
||||
#define GET_COMPARE_B() (OCR4B)
|
||||
#define SET_COMPARE_A(val) (OCR4A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR4B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER4_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER4_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER4_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS40))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK4 = 0, TCCR4A = 0, TCCR4B = (1<<ICNC4) | (1<<CS41))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR4A = TCCR4A & ~((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR4A = (TCCR4A & ~(1<<COM4A1)) | (1<<COM4A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR4A = (TCCR4A | (1<<COM4A1)) & ~(1<<COM4A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR4A = TCCR4A | ((1<<COM4A1) | (1<<COM4A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR4B &= ~(1<<ICES4))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR4B |= (1<<ICES4))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR4 = (1<<ICF4), TIMSK4 = (1<<ICIE4))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR4 = (1<<OCF4A), TIMSK4 |= (1<<OCIE4A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR4 = (1<<OCF4B), TIMSK4 |= (1<<OCIE4B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK4 &= ~(1<<ICIE4))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK4 &= ~(1<<OCIE4A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK4 &= ~(1<<OCIE4B))
|
||||
#define GET_TIMER_COUNT() (TCNT4)
|
||||
#define GET_INPUT_CAPTURE() (ICR4)
|
||||
#define GET_COMPARE_A() (OCR4A)
|
||||
#define GET_COMPARE_B() (OCR4B)
|
||||
#define SET_COMPARE_A(val) (OCR4A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR4B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER4_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER4_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER4_COMPB_vect
|
||||
|
||||
|
||||
#elif defined(ALTSS_USE_TIMER5)
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS50))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS51))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR5A = TCCR5A & ~((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR5A = (TCCR5A & ~(1<<COM5A1)) | (1<<COM5A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR5A = (TCCR5A | (1<<COM5A1)) & ~(1<<COM5A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR5A = TCCR5A | ((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR5B &= ~(1<<ICES5))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR5B |= (1<<ICES5))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR5 = (1<<ICF5), TIMSK5 = (1<<ICIE5))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR5 = (1<<OCF5A), TIMSK5 |= (1<<OCIE5A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR5 = (1<<OCF5B), TIMSK5 |= (1<<OCIE5B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK5 &= ~(1<<ICIE5))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK5 &= ~(1<<OCIE5A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK5 &= ~(1<<OCIE5B))
|
||||
#define GET_TIMER_COUNT() (TCNT5)
|
||||
#define GET_INPUT_CAPTURE() (ICR5)
|
||||
#define GET_COMPARE_A() (OCR5A)
|
||||
#define GET_COMPARE_B() (OCR5B)
|
||||
#define SET_COMPARE_A(val) (OCR5A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR5B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER5_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER5_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER5_COMPB_vect
|
||||
#define CONFIG_TIMER_NOPRESCALE() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS50))
|
||||
#define CONFIG_TIMER_PRESCALE_8() (TIMSK5 = 0, TCCR5A = 0, TCCR5B = (1<<ICNC5) | (1<<CS51))
|
||||
#define CONFIG_MATCH_NORMAL() (TCCR5A = TCCR5A & ~((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_MATCH_TOGGLE() (TCCR5A = (TCCR5A & ~(1<<COM5A1)) | (1<<COM5A0))
|
||||
#define CONFIG_MATCH_CLEAR() (TCCR5A = (TCCR5A | (1<<COM5A1)) & ~(1<<COM5A0))
|
||||
#define CONFIG_MATCH_SET() (TCCR5A = TCCR5A | ((1<<COM5A1) | (1<<COM5A0)))
|
||||
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR5B &= ~(1<<ICES5))
|
||||
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR5B |= (1<<ICES5))
|
||||
#define ENABLE_INT_INPUT_CAPTURE() (TIFR5 = (1<<ICF5), TIMSK5 = (1<<ICIE5))
|
||||
#define ENABLE_INT_COMPARE_A() (TIFR5 = (1<<OCF5A), TIMSK5 |= (1<<OCIE5A))
|
||||
#define ENABLE_INT_COMPARE_B() (TIFR5 = (1<<OCF5B), TIMSK5 |= (1<<OCIE5B))
|
||||
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK5 &= ~(1<<ICIE5))
|
||||
#define DISABLE_INT_COMPARE_A() (TIMSK5 &= ~(1<<OCIE5A))
|
||||
#define DISABLE_INT_COMPARE_B() (TIMSK5 &= ~(1<<OCIE5B))
|
||||
#define GET_TIMER_COUNT() (TCNT5)
|
||||
#define GET_INPUT_CAPTURE() (ICR5)
|
||||
#define GET_COMPARE_A() (OCR5A)
|
||||
#define GET_COMPARE_B() (OCR5B)
|
||||
#define SET_COMPARE_A(val) (OCR5A = (val))
|
||||
#define SET_COMPARE_B(val) (OCR5B = (val))
|
||||
#define CAPTURE_INTERRUPT TIMER5_CAPT_vect
|
||||
#define COMPARE_A_INTERRUPT TIMER5_COMPA_vect
|
||||
#define COMPARE_B_INTERRUPT TIMER5_COMPB_vect
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file CircularBuffer.h
|
||||
*
|
||||
* Circular buffering for arbitrary types.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file CircularBuffer.h
|
||||
*
|
||||
* Circular buffering for arbitrary types.
|
||||
*/
|
||||
|
||||
#ifndef CircularBuffer_h
|
||||
#define CircularBuffer_h
|
||||
|
||||
@@ -33,164 +33,163 @@
|
||||
*/
|
||||
template <class T> class CircularBuffer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param buffer Preallocated buffer of at least size records.
|
||||
* @param size Number of records available in the buffer.
|
||||
*/
|
||||
CircularBuffer(T* buffer, const uint8_t size )
|
||||
: m_size(size), m_buff(buffer)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param buffer Preallocated buffer of at least size records.
|
||||
* @param size Number of records available in the buffer.
|
||||
*/
|
||||
CircularBuffer(T* buffer, const uint8_t size )
|
||||
: m_size(size), m_buff(buffer)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all entries in the circular buffer.
|
||||
*/
|
||||
void clear(void)
|
||||
{
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
m_front = 0;
|
||||
m_fill = 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Clear all entries in the circular buffer.
|
||||
*/
|
||||
void clear(void)
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
m_front = 0;
|
||||
m_fill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the circular buffer is empty.
|
||||
* @return True, when empty.
|
||||
*/
|
||||
inline bool empty(void) const
|
||||
{
|
||||
bool empty;
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
empty = !m_fill;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
/**
|
||||
* Test if the circular buffer is empty.
|
||||
* @return True, when empty.
|
||||
*/
|
||||
inline bool empty(void) const
|
||||
{
|
||||
bool empty;
|
||||
MY_CRITICAL_SECTION {
|
||||
empty = !m_fill;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the circular buffer is full.
|
||||
* @return True, when full.
|
||||
*/
|
||||
inline bool full(void) const
|
||||
{
|
||||
bool full;
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
full = m_fill == m_size;
|
||||
}
|
||||
return full;
|
||||
}
|
||||
/**
|
||||
* Test if the circular buffer is full.
|
||||
* @return True, when full.
|
||||
*/
|
||||
inline bool full(void) const
|
||||
{
|
||||
bool full;
|
||||
MY_CRITICAL_SECTION {
|
||||
full = m_fill == m_size;
|
||||
}
|
||||
return full;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of records stored in the buffer.
|
||||
* @return number of records.
|
||||
*/
|
||||
inline uint8_t available(void) const
|
||||
{
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
return m_fill;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aquire unused record on front of the buffer, for writing.
|
||||
* After filling the record, it has to be pushed to actually
|
||||
* add it to the buffer.
|
||||
* @return Pointer to record, or NULL when buffer is full.
|
||||
*/
|
||||
T* getFront(void) const
|
||||
{
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
if (!full()) return get(m_front);
|
||||
}
|
||||
return static_cast<T*>(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push record to front of the buffer.
|
||||
* @param record Record to push. If record was aquired previously (using getFront) its
|
||||
* data will not be copied as it is already present in the buffer.
|
||||
* @return True, when record was pushed successfully.
|
||||
*/
|
||||
bool pushFront(T* record)
|
||||
{
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
if (!full())
|
||||
{
|
||||
T* f = get(m_front);
|
||||
if (f != record)
|
||||
*f = *record;
|
||||
m_front = (m_front+1) % m_size;
|
||||
m_fill++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Return the number of records stored in the buffer.
|
||||
* @return number of records.
|
||||
*/
|
||||
inline uint8_t available(void) const
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
return m_fill;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aquire record on back of the buffer, for reading.
|
||||
* After reading the record, it has to be pop'ed to actually
|
||||
* remove it from the buffer.
|
||||
* @return Pointer to record, or NULL when buffer is empty.
|
||||
*/
|
||||
T* getBack(void) const
|
||||
{
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
if (!empty()) return get(back());
|
||||
}
|
||||
return static_cast<T*>(NULL);
|
||||
}
|
||||
/**
|
||||
* Aquire unused record on front of the buffer, for writing.
|
||||
* After filling the record, it has to be pushed to actually
|
||||
* add it to the buffer.
|
||||
* @return Pointer to record, or NULL when buffer is full.
|
||||
*/
|
||||
T* getFront(void) const
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
if (!full())
|
||||
{
|
||||
return get(m_front);
|
||||
}
|
||||
}
|
||||
return static_cast<T*>(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove record from back of the buffer.
|
||||
* @return True, when record was pop'ed successfully.
|
||||
*/
|
||||
bool popBack(void)
|
||||
{
|
||||
MY_CRITICAL_SECTION
|
||||
{
|
||||
if (!empty())
|
||||
{
|
||||
m_fill--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Internal getter for records.
|
||||
* @param idx Record index in buffer.
|
||||
* @return Ptr to record.
|
||||
*/
|
||||
inline T * get(const uint8_t idx) const
|
||||
{
|
||||
return &(m_buff[idx]);
|
||||
}
|
||||
/**
|
||||
* Push record to front of the buffer.
|
||||
* @param record Record to push. If record was aquired previously (using getFront) its
|
||||
* data will not be copied as it is already present in the buffer.
|
||||
* @return True, when record was pushed successfully.
|
||||
*/
|
||||
bool pushFront(T* record)
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
if (!full())
|
||||
{
|
||||
T* f = get(m_front);
|
||||
if (f != record) {
|
||||
*f = *record;
|
||||
}
|
||||
m_front = (m_front+1) % m_size;
|
||||
m_fill++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal getter for index of last used record in buffer.
|
||||
* @return Index of last record.
|
||||
*/
|
||||
inline uint8_t back(void) const
|
||||
{
|
||||
return (m_front - m_fill + m_size) % m_size;
|
||||
}
|
||||
/**
|
||||
* Aquire record on back of the buffer, for reading.
|
||||
* After reading the record, it has to be pop'ed to actually
|
||||
* remove it from the buffer.
|
||||
* @return Pointer to record, or NULL when buffer is empty.
|
||||
*/
|
||||
T* getBack(void) const
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
if (!empty())
|
||||
{
|
||||
return get(back());
|
||||
}
|
||||
}
|
||||
return static_cast<T*>(NULL);
|
||||
}
|
||||
|
||||
const uint8_t m_size; //!< Total number of records that can be stored in the buffer.
|
||||
T* const m_buff; //!< Ptr to buffer holding all records.
|
||||
volatile uint8_t m_front; //!< Index of front element (not pushed yet).
|
||||
volatile uint8_t m_fill; //!< Amount of records currently pushed.
|
||||
/**
|
||||
* Remove record from back of the buffer.
|
||||
* @return True, when record was pop'ed successfully.
|
||||
*/
|
||||
bool popBack(void)
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
if (!empty())
|
||||
{
|
||||
m_fill--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Internal getter for records.
|
||||
* @param idx Record index in buffer.
|
||||
* @return Ptr to record.
|
||||
*/
|
||||
inline T * get(const uint8_t idx) const
|
||||
{
|
||||
return &(m_buff[idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal getter for index of last used record in buffer.
|
||||
* @return Index of last record.
|
||||
*/
|
||||
inline uint8_t back(void) const
|
||||
{
|
||||
return (m_front - m_fill + m_size) % m_size;
|
||||
}
|
||||
|
||||
const uint8_t m_size; //!< Total number of records that can be stored in the buffer.
|
||||
T* const m_buff; //!< Ptr to buffer holding all records.
|
||||
volatile uint8_t m_front; //!< Index of front element (not pushed yet).
|
||||
volatile uint8_t m_fill; //!< Amount of records currently pushed.
|
||||
};
|
||||
|
||||
#endif // CircularBuffer_h
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||
#include "rpi_util.h"
|
||||
using namespace rpi_util;
|
||||
#include "rpi_util.h"
|
||||
using namespace rpi_util;
|
||||
#endif
|
||||
|
||||
#undef PSTR
|
||||
@@ -57,7 +57,7 @@
|
||||
#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__)
|
||||
|
||||
#ifndef delay
|
||||
#define delay _delay_ms
|
||||
#define delay _delay_ms
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#include "IPAddress.h"
|
||||
|
||||
#if !DOXYGEN
|
||||
class Client : public Stream {
|
||||
class Client : public Stream
|
||||
{
|
||||
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) = 0;
|
||||
@@ -43,7 +44,10 @@ public:
|
||||
virtual operator bool() = 0;
|
||||
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||
uint8_t* rawIPAddress(IPAddress& addr)
|
||||
{
|
||||
return addr.raw_address();
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -32,13 +32,16 @@
|
||||
#include "log.h"
|
||||
#include "EthernetClient.h"
|
||||
|
||||
EthernetClient::EthernetClient() : _sock(-1) {
|
||||
EthernetClient::EthernetClient() : _sock(-1)
|
||||
{
|
||||
}
|
||||
|
||||
EthernetClient::EthernetClient(int sock) : _sock(sock) {
|
||||
EthernetClient::EthernetClient(int sock) : _sock(sock)
|
||||
{
|
||||
}
|
||||
|
||||
int EthernetClient::connect(const char* host, uint16_t port) {
|
||||
int EthernetClient::connect(const char* host, uint16_t port)
|
||||
{
|
||||
int sockfd;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
int rv;
|
||||
@@ -51,14 +54,14 @@ int EthernetClient::connect(const char* host, uint16_t port) {
|
||||
|
||||
sprintf(port_str, "%hu", port);
|
||||
if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) {
|
||||
logError("getaddrinfo: %s\n", gai_strerror(rv));
|
||||
logError("getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// loop through all the results and connect to the first we can
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
if ((sockfd = socket(p->ai_family, p->ai_socktype,
|
||||
p->ai_protocol)) == -1) {
|
||||
p->ai_protocol)) == -1) {
|
||||
logError("socket: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
@@ -88,15 +91,18 @@ int EthernetClient::connect(const char* host, uint16_t port) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EthernetClient::connect(IPAddress ip, uint16_t port) {
|
||||
int EthernetClient::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
return connect(ip.toString().c_str(), port);
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(uint8_t b) {
|
||||
size_t EthernetClient::write(uint8_t b)
|
||||
{
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(const uint8_t *buf, size_t size) {
|
||||
size_t EthernetClient::write(const uint8_t *buf, size_t size)
|
||||
{
|
||||
int rc = 0;
|
||||
int bytes = 0;
|
||||
|
||||
@@ -119,17 +125,20 @@ size_t EthernetClient::write(const uint8_t *buf, size_t size) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(const char *str) {
|
||||
size_t EthernetClient::write(const char *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
size_t EthernetClient::write(const char *buffer, size_t size) {
|
||||
size_t EthernetClient::write(const char *buffer, size_t size)
|
||||
{
|
||||
return write((const uint8_t *)buffer, size);
|
||||
}
|
||||
|
||||
int EthernetClient::available() {
|
||||
int EthernetClient::available()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (_sock != -1) {
|
||||
@@ -139,10 +148,10 @@ int EthernetClient::available() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EthernetClient::read() {
|
||||
int EthernetClient::read()
|
||||
{
|
||||
uint8_t b;
|
||||
if ( recv(_sock, &b, 1, 0) > 0 )
|
||||
{
|
||||
if ( recv(_sock, &b, 1, 0) > 0 ) {
|
||||
// recv worked
|
||||
return b;
|
||||
} else {
|
||||
@@ -151,22 +160,26 @@ int EthernetClient::read() {
|
||||
}
|
||||
}
|
||||
|
||||
int EthernetClient::read(uint8_t *buf, size_t size) {
|
||||
int EthernetClient::read(uint8_t *buf, size_t size)
|
||||
{
|
||||
return recv(_sock, buf, size, 0);
|
||||
}
|
||||
|
||||
int EthernetClient::peek() {
|
||||
int EthernetClient::peek()
|
||||
{
|
||||
uint8_t b;
|
||||
|
||||
return recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
void EthernetClient::flush() {
|
||||
void EthernetClient::flush()
|
||||
{
|
||||
// There isn't much we can do here
|
||||
return;
|
||||
}
|
||||
|
||||
void EthernetClient::stop() {
|
||||
void EthernetClient::stop()
|
||||
{
|
||||
if (_sock == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -186,7 +199,8 @@ void EthernetClient::stop() {
|
||||
}
|
||||
usleep(1000);
|
||||
gettimeofday(&curTime, NULL);
|
||||
} while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) < 1000000);
|
||||
} while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) <
|
||||
1000000);
|
||||
|
||||
// if it hasn't closed, close it forcefully
|
||||
if (s != ETHERNETCLIENT_W5100_CLOSED) {
|
||||
@@ -195,7 +209,8 @@ void EthernetClient::stop() {
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::status() {
|
||||
uint8_t EthernetClient::status()
|
||||
{
|
||||
if (_sock == -1) {
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
}
|
||||
@@ -203,36 +218,38 @@ uint8_t EthernetClient::status() {
|
||||
struct tcp_info tcp_info;
|
||||
int tcp_info_length = sizeof(tcp_info);
|
||||
|
||||
if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) {
|
||||
if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info,
|
||||
(socklen_t *)&tcp_info_length ) == 0 ) {
|
||||
switch (tcp_info.tcpi_state) {
|
||||
case TCP_ESTABLISHED:
|
||||
return ETHERNETCLIENT_W5100_ESTABLISHED;
|
||||
case TCP_SYN_SENT:
|
||||
return ETHERNETCLIENT_W5100_SYNSENT;
|
||||
case TCP_SYN_RECV:
|
||||
return ETHERNETCLIENT_W5100_SYNRECV;
|
||||
case TCP_FIN_WAIT1:
|
||||
case TCP_FIN_WAIT2:
|
||||
return ETHERNETCLIENT_W5100_FIN_WAIT;
|
||||
case TCP_TIME_WAIT:
|
||||
return TCP_TIME_WAIT;
|
||||
case TCP_CLOSE:
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
case TCP_CLOSE_WAIT:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
case TCP_LAST_ACK:
|
||||
return ETHERNETCLIENT_W5100_LAST_ACK;
|
||||
case TCP_LISTEN:
|
||||
return ETHERNETCLIENT_W5100_LISTEN;
|
||||
case TCP_CLOSING:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
case TCP_ESTABLISHED:
|
||||
return ETHERNETCLIENT_W5100_ESTABLISHED;
|
||||
case TCP_SYN_SENT:
|
||||
return ETHERNETCLIENT_W5100_SYNSENT;
|
||||
case TCP_SYN_RECV:
|
||||
return ETHERNETCLIENT_W5100_SYNRECV;
|
||||
case TCP_FIN_WAIT1:
|
||||
case TCP_FIN_WAIT2:
|
||||
return ETHERNETCLIENT_W5100_FIN_WAIT;
|
||||
case TCP_TIME_WAIT:
|
||||
return TCP_TIME_WAIT;
|
||||
case TCP_CLOSE:
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
case TCP_CLOSE_WAIT:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
case TCP_LAST_ACK:
|
||||
return ETHERNETCLIENT_W5100_LAST_ACK;
|
||||
case TCP_LISTEN:
|
||||
return ETHERNETCLIENT_W5100_LISTEN;
|
||||
case TCP_CLOSING:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
}
|
||||
}
|
||||
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::connected() {
|
||||
uint8_t EthernetClient::connected()
|
||||
{
|
||||
if (_sock == -1) {
|
||||
return 0;
|
||||
}
|
||||
@@ -246,17 +263,20 @@ uint8_t EthernetClient::connected() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EthernetClient::getSocketNumber() {
|
||||
int EthernetClient::getSocketNumber()
|
||||
{
|
||||
return _sock;
|
||||
}
|
||||
|
||||
// the next function allows us to use the client returned by
|
||||
// EthernetServer::available() as the condition in an if-statement.
|
||||
|
||||
EthernetClient::operator bool() {
|
||||
EthernetClient::operator bool()
|
||||
{
|
||||
return _sock != -1;
|
||||
}
|
||||
|
||||
bool EthernetClient::operator==(const EthernetClient& rhs) {
|
||||
bool EthernetClient::operator==(const EthernetClient& rhs)
|
||||
{
|
||||
return _sock == rhs._sock && _sock != -1 && rhs._sock != -1;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
/**
|
||||
* EthernetClient class
|
||||
*/
|
||||
class EthernetClient : public Client {
|
||||
class EthernetClient : public Client
|
||||
{
|
||||
|
||||
private:
|
||||
int _sock; //!< @brief Network socket.
|
||||
@@ -168,12 +169,18 @@ public:
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator==(const bool value) { return bool() == value; }
|
||||
virtual bool operator==(const bool value)
|
||||
{
|
||||
return bool() == value;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator!=(const bool value) { return bool() != value; }
|
||||
virtual bool operator!=(const bool value)
|
||||
{
|
||||
return bool() != value;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
@@ -183,7 +190,10 @@ public:
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); };
|
||||
virtual bool operator!=(const EthernetClient& rhs)
|
||||
{
|
||||
return !this->operator==(rhs);
|
||||
};
|
||||
|
||||
friend class EthernetServer;
|
||||
};
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
#include "EthernetClient.h"
|
||||
#include "EthernetServer.h"
|
||||
|
||||
EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port), max_clients(max_clients)
|
||||
EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port),
|
||||
max_clients(max_clients)
|
||||
{
|
||||
clients.reserve(max_clients);
|
||||
}
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
#include "IPAddress.h"
|
||||
|
||||
#ifdef ETHERNETSERVER_MAX_CLIENTS
|
||||
#define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow.
|
||||
#define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow.
|
||||
#else
|
||||
#define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients.
|
||||
#define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow.
|
||||
#define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients.
|
||||
#define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow.
|
||||
#endif
|
||||
|
||||
class EthernetClient;
|
||||
@@ -39,7 +39,8 @@ class EthernetClient;
|
||||
/**
|
||||
* @brief EthernetServer class
|
||||
*/
|
||||
class EthernetServer : public Server {
|
||||
class EthernetServer : public Server
|
||||
{
|
||||
|
||||
private:
|
||||
uint16_t port; //!< @brief Port number for the network socket.
|
||||
|
||||
+23
-19
@@ -24,53 +24,53 @@
|
||||
#include <cstring>
|
||||
#include "IPAddress.h"
|
||||
|
||||
IPAddress::IPAddress() {
|
||||
IPAddress::IPAddress()
|
||||
{
|
||||
_address.dword = 0;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet,
|
||||
uint8_t fourth_octet)
|
||||
{
|
||||
_address.bytes[0] = first_octet;
|
||||
_address.bytes[1] = second_octet;
|
||||
_address.bytes[2] = third_octet;
|
||||
_address.bytes[3] = fourth_octet;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint32_t address) {
|
||||
IPAddress::IPAddress(uint32_t address)
|
||||
{
|
||||
_address.dword = address;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const uint8_t *address) {
|
||||
IPAddress::IPAddress(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
bool IPAddress::fromString(const char *address) {
|
||||
bool IPAddress::fromString(const char *address)
|
||||
{
|
||||
// TODO: add support for "a", "a.b", "a.b.c" formats
|
||||
|
||||
uint16_t acc = 0; // Accumulator
|
||||
uint8_t dots = 0;
|
||||
|
||||
while (*address)
|
||||
{
|
||||
while (*address) {
|
||||
char c = *address++;
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
if (c >= '0' && c <= '9') {
|
||||
acc = acc * 10 + (c - '0');
|
||||
if (acc > 255) {
|
||||
// Value out of [0..255] range
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
} else if (c == '.') {
|
||||
if (dots == 3) {
|
||||
// Too much dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
_address.bytes[dots++] = acc;
|
||||
acc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Invalid char
|
||||
return false;
|
||||
}
|
||||
@@ -84,23 +84,27 @@ bool IPAddress::fromString(const char *address) {
|
||||
return true;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address) {
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address) {
|
||||
IPAddress& IPAddress::operator=(uint32_t address)
|
||||
{
|
||||
_address.dword = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const {
|
||||
bool IPAddress::operator==(const uint8_t* addr) const
|
||||
{
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
std::string IPAddress::toString()
|
||||
{
|
||||
char szRet[16];
|
||||
sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]);
|
||||
sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2],
|
||||
_address.bytes[3]);
|
||||
return std::string(szRet);
|
||||
}
|
||||
|
||||
+128
-118
@@ -29,127 +29,137 @@
|
||||
/**
|
||||
* @brief A class to make it easier to handle and pass around IP addresses
|
||||
*/
|
||||
class IPAddress {
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[4]; //!< IPv4 address as an array
|
||||
uint32_t dword; //!< IPv4 address in 32 bits format
|
||||
} _address;
|
||||
class IPAddress
|
||||
{
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[4]; //!< IPv4 address as an array
|
||||
uint32_t dword; //!< IPv4 address in 32 bits format
|
||||
} _address;
|
||||
|
||||
/**
|
||||
* @brief Access the raw byte array containing the address.
|
||||
*
|
||||
* Because this returns a pointer to the internal structure rather than a copy of the address
|
||||
* this function should only be used when you know that the usage of the returned uint8_t* will
|
||||
* be transient and not stored.
|
||||
*
|
||||
* @return pointer to the internal structure.
|
||||
*/
|
||||
uint8_t* raw_address() {
|
||||
return _address.bytes;
|
||||
}
|
||||
/**
|
||||
* @brief Access the raw byte array containing the address.
|
||||
*
|
||||
* Because this returns a pointer to the internal structure rather than a copy of the address
|
||||
* this function should only be used when you know that the usage of the returned uint8_t* will
|
||||
* be transient and not stored.
|
||||
*
|
||||
* @return pointer to the internal structure.
|
||||
*/
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*/
|
||||
IPAddress();
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param first_octet first octet of the IPv4 address.
|
||||
* @param second_octet second octet of the IPv4 address.
|
||||
* @param third_octet third octet of the IPv4 address.
|
||||
* @param fourth_octet fourth octet of the IPv4 address.
|
||||
*/
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param address to be set from a 32 bits integer.
|
||||
*/
|
||||
IPAddress(uint32_t address);
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param address to be set from a byte array.
|
||||
*/
|
||||
IPAddress(const uint8_t *address);
|
||||
/**
|
||||
* @brief Set the IP from a array of characters.
|
||||
*
|
||||
* @param address to be set.
|
||||
*/
|
||||
bool fromString(const char *address);
|
||||
/**
|
||||
* @brief Set the IP from a string class type.
|
||||
*
|
||||
* @param address to be set.
|
||||
*/
|
||||
bool fromString(const std::string &address) { return fromString(address.c_str()); }
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
* Allow IPAddress objects to be used where a pointer to a four-byte uint8_t array is expected
|
||||
*/
|
||||
operator uint32_t() const {
|
||||
return _address.dword;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(const IPAddress& addr) const {
|
||||
return _address.dword == addr._address.dword;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(uint32_t addr) const {
|
||||
return _address.dword == addr;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
/**
|
||||
* @brief Overloaded index operator.
|
||||
*
|
||||
* Allow getting and setting individual octets of the address.
|
||||
*
|
||||
*/
|
||||
uint8_t operator[](int index) const {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded index operator
|
||||
*
|
||||
*/
|
||||
uint8_t& operator[](int index) {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded copy operators.
|
||||
*
|
||||
* Allow initialisation of IPAddress objects from byte array.
|
||||
*/
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
/**
|
||||
* @brief Overloaded copy operator.
|
||||
*
|
||||
* Allow initialisation of IPAddress objects from a 32 bits integer.
|
||||
*/
|
||||
IPAddress& operator=(uint32_t address);
|
||||
/**
|
||||
* @brief Convert the IP address to a string.
|
||||
*
|
||||
* @return A stringified IP address
|
||||
*/
|
||||
std::string toString();
|
||||
public:
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*/
|
||||
IPAddress();
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param first_octet first octet of the IPv4 address.
|
||||
* @param second_octet second octet of the IPv4 address.
|
||||
* @param third_octet third octet of the IPv4 address.
|
||||
* @param fourth_octet fourth octet of the IPv4 address.
|
||||
*/
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param address to be set from a 32 bits integer.
|
||||
*/
|
||||
IPAddress(uint32_t address);
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param address to be set from a byte array.
|
||||
*/
|
||||
IPAddress(const uint8_t *address);
|
||||
/**
|
||||
* @brief Set the IP from a array of characters.
|
||||
*
|
||||
* @param address to be set.
|
||||
*/
|
||||
bool fromString(const char *address);
|
||||
/**
|
||||
* @brief Set the IP from a string class type.
|
||||
*
|
||||
* @param address to be set.
|
||||
*/
|
||||
bool fromString(const std::string &address)
|
||||
{
|
||||
return fromString(address.c_str());
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
* Allow IPAddress objects to be used where a pointer to a four-byte uint8_t array is expected
|
||||
*/
|
||||
operator uint32_t() const
|
||||
{
|
||||
return _address.dword;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(const IPAddress& addr) const
|
||||
{
|
||||
return _address.dword == addr._address.dword;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(uint32_t addr) const
|
||||
{
|
||||
return _address.dword == addr;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
/**
|
||||
* @brief Overloaded index operator.
|
||||
*
|
||||
* Allow getting and setting individual octets of the address.
|
||||
*
|
||||
*/
|
||||
uint8_t operator[](int index) const
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded index operator
|
||||
*
|
||||
*/
|
||||
uint8_t& operator[](int index)
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded copy operators.
|
||||
*
|
||||
* Allow initialisation of IPAddress objects from byte array.
|
||||
*/
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
/**
|
||||
* @brief Overloaded copy operator.
|
||||
*
|
||||
* Allow initialisation of IPAddress objects from a 32 bits integer.
|
||||
*/
|
||||
IPAddress& operator=(uint32_t address);
|
||||
/**
|
||||
* @brief Convert the IP address to a string.
|
||||
*
|
||||
* @return A stringified IP address
|
||||
*/
|
||||
std::string toString();
|
||||
|
||||
friend class Client;
|
||||
friend class Client;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+47
-25
@@ -30,7 +30,8 @@
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::write(const uint8_t *buffer, size_t size) {
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t n = 0;
|
||||
while(size--) {
|
||||
n += write(*buffer++);
|
||||
@@ -42,7 +43,8 @@ size_t
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
Print::printf(const char *format, ...) {
|
||||
Print::printf(const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char temp[64];
|
||||
@@ -65,31 +67,38 @@ Print::printf(const char *format, ...) {
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t Print::print(const std::string &s) {
|
||||
size_t Print::print(const std::string &s)
|
||||
{
|
||||
return write(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
size_t Print::print(const char str[]) {
|
||||
size_t Print::print(const char str[])
|
||||
{
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::print(char c) {
|
||||
size_t Print::print(char c)
|
||||
{
|
||||
return write(c);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned char b, int base) {
|
||||
size_t Print::print(unsigned char b, int base)
|
||||
{
|
||||
return print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
size_t Print::print(int n, int base) {
|
||||
size_t Print::print(int n, int base)
|
||||
{
|
||||
return print((long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned int n, int base) {
|
||||
size_t Print::print(unsigned int n, int base)
|
||||
{
|
||||
return print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(long n, int base) {
|
||||
size_t Print::print(long n, int base)
|
||||
{
|
||||
if(base == 0) {
|
||||
return write(n);
|
||||
} else if(base == 10) {
|
||||
@@ -104,72 +113,83 @@ size_t Print::print(long n, int base) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base) {
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
{
|
||||
if(base == 0) {
|
||||
return write(n);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(double n, int digits) {
|
||||
size_t Print::print(double n, int digits)
|
||||
{
|
||||
return printFloat(n, digits);
|
||||
}
|
||||
|
||||
size_t Print::println(void) {
|
||||
size_t Print::println(void)
|
||||
{
|
||||
return print("\r\n");
|
||||
}
|
||||
|
||||
size_t Print::println(const std::string &s) {
|
||||
size_t Print::println(const std::string &s)
|
||||
{
|
||||
size_t n = print(s);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const char c[]) {
|
||||
size_t Print::println(const char c[])
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(char c) {
|
||||
size_t Print::println(char c)
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned char b, int base) {
|
||||
size_t Print::println(unsigned char b, int base)
|
||||
{
|
||||
size_t n = print(b, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(int num, int base) {
|
||||
size_t Print::println(int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned int num, int base) {
|
||||
size_t Print::println(unsigned int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long num, int base) {
|
||||
size_t Print::println(long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long num, int base) {
|
||||
size_t Print::println(unsigned long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(double num, int digits) {
|
||||
size_t Print::println(double num, int digits)
|
||||
{
|
||||
size_t n = print(num, digits);
|
||||
n += println();
|
||||
return n;
|
||||
@@ -177,7 +197,8 @@ size_t Print::println(double num, int digits) {
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base) {
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
|
||||
@@ -198,7 +219,8 @@ size_t Print::printNumber(unsigned long n, uint8_t base) {
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::printFloat(double number, uint8_t digits) {
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
if(std::isnan(number)) {
|
||||
|
||||
+54
-41
@@ -32,54 +32,67 @@
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
|
||||
class Print {
|
||||
private:
|
||||
int write_error;
|
||||
size_t printNumber(unsigned long n, uint8_t base);
|
||||
size_t printFloat(double number, uint8_t digits);
|
||||
class Print
|
||||
{
|
||||
private:
|
||||
int write_error;
|
||||
size_t printNumber(unsigned long n, uint8_t base);
|
||||
size_t printFloat(double number, uint8_t digits);
|
||||
|
||||
protected:
|
||||
void setWriteError(int err = 1) { write_error = err; }
|
||||
protected:
|
||||
void setWriteError(int err = 1)
|
||||
{
|
||||
write_error = err;
|
||||
}
|
||||
|
||||
public:
|
||||
Print() : write_error(0) {}
|
||||
public:
|
||||
Print() : write_error(0) {}
|
||||
|
||||
int getWriteError() { return write_error; }
|
||||
void clearWriteError() { setWriteError(0); }
|
||||
int getWriteError()
|
||||
{
|
||||
return write_error;
|
||||
}
|
||||
void clearWriteError()
|
||||
{
|
||||
setWriteError(0);
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
size_t write(const char *str) {
|
||||
if (str == NULL)
|
||||
return 0;
|
||||
return write((const uint8_t *) str, strlen(str));
|
||||
}
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
size_t write(const char *buffer, size_t size) {
|
||||
return write((const uint8_t *) buffer, size);
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
size_t write(const char *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return write((const uint8_t *) str, strlen(str));
|
||||
}
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
size_t write(const char *buffer, size_t size)
|
||||
{
|
||||
return write((const uint8_t *) buffer, size);
|
||||
}
|
||||
|
||||
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t print(const std::string &);
|
||||
size_t print(const char[]);
|
||||
size_t print(char);
|
||||
size_t print(unsigned char, int = DEC);
|
||||
size_t print(int, int = DEC);
|
||||
size_t print(unsigned int, int = DEC);
|
||||
size_t print(long, int = DEC);
|
||||
size_t print(unsigned long, int = DEC);
|
||||
size_t print(double, int = 2);
|
||||
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t print(const std::string &);
|
||||
size_t print(const char[]);
|
||||
size_t print(char);
|
||||
size_t print(unsigned char, int = DEC);
|
||||
size_t print(int, int = DEC);
|
||||
size_t print(unsigned int, int = DEC);
|
||||
size_t print(long, int = DEC);
|
||||
size_t print(unsigned long, int = DEC);
|
||||
size_t print(double, int = 2);
|
||||
|
||||
size_t println(const std::string &s);
|
||||
size_t println(const char[]);
|
||||
size_t println(char);
|
||||
size_t println(unsigned char, int = DEC);
|
||||
size_t println(int, int = DEC);
|
||||
size_t println(unsigned int, int = DEC);
|
||||
size_t println(long, int = DEC);
|
||||
size_t println(unsigned long, int = DEC);
|
||||
size_t println(double, int = 2);
|
||||
size_t println(void);
|
||||
};
|
||||
size_t println(const std::string &s);
|
||||
size_t println(const char[]);
|
||||
size_t println(char);
|
||||
size_t println(unsigned char, int = DEC);
|
||||
size_t println(int, int = DEC);
|
||||
size_t println(unsigned int, int = DEC);
|
||||
size_t println(long, int = DEC);
|
||||
size_t println(unsigned long, int = DEC);
|
||||
size_t println(double, int = 2);
|
||||
size_t println(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -69,7 +69,8 @@ bool SerialPort::open(int bauds)
|
||||
/* create a symlink with predictable name to the PTY device */
|
||||
unlink(serialPort.c_str()); // remove the symlink if it already exists
|
||||
if (symlink(ptsname(sd), serialPort.c_str()) != 0) {
|
||||
logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno));
|
||||
logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -83,23 +84,57 @@ bool SerialPort::open(int bauds)
|
||||
}
|
||||
|
||||
switch (bauds) {
|
||||
case 50: speed = B50 ; break ;
|
||||
case 75: speed = B75 ; break ;
|
||||
case 110: speed = B110 ; break ;
|
||||
case 134: speed = B134 ; break ;
|
||||
case 150: speed = B150 ; break ;
|
||||
case 200: speed = B200 ; break ;
|
||||
case 300: speed = B300 ; break ;
|
||||
case 600: speed = B600 ; break ;
|
||||
case 1200: speed = B1200 ; break ;
|
||||
case 1800: speed = B1800 ; break ;
|
||||
case 2400: speed = B2400 ; break ;
|
||||
case 9600: speed = B9600 ; break ;
|
||||
case 19200: speed = B19200 ; break ;
|
||||
case 38400: speed = B38400 ; break ;
|
||||
case 57600: speed = B57600 ; break ;
|
||||
case 115200: speed = B115200 ; break ;
|
||||
default: speed = B115200 ; break ;
|
||||
case 50:
|
||||
speed = B50 ;
|
||||
break ;
|
||||
case 75:
|
||||
speed = B75 ;
|
||||
break ;
|
||||
case 110:
|
||||
speed = B110 ;
|
||||
break ;
|
||||
case 134:
|
||||
speed = B134 ;
|
||||
break ;
|
||||
case 150:
|
||||
speed = B150 ;
|
||||
break ;
|
||||
case 200:
|
||||
speed = B200 ;
|
||||
break ;
|
||||
case 300:
|
||||
speed = B300 ;
|
||||
break ;
|
||||
case 600:
|
||||
speed = B600 ;
|
||||
break ;
|
||||
case 1200:
|
||||
speed = B1200 ;
|
||||
break ;
|
||||
case 1800:
|
||||
speed = B1800 ;
|
||||
break ;
|
||||
case 2400:
|
||||
speed = B2400 ;
|
||||
break ;
|
||||
case 9600:
|
||||
speed = B9600 ;
|
||||
break ;
|
||||
case 19200:
|
||||
speed = B19200 ;
|
||||
break ;
|
||||
case 38400:
|
||||
speed = B38400 ;
|
||||
break ;
|
||||
case 57600:
|
||||
speed = B57600 ;
|
||||
break ;
|
||||
case 115200:
|
||||
speed = B115200 ;
|
||||
break ;
|
||||
default:
|
||||
speed = B115200 ;
|
||||
break ;
|
||||
}
|
||||
|
||||
// Get the current options of the port
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
* SerialPort Class
|
||||
* Class that provides the functionality of arduino Serial library
|
||||
*/
|
||||
class SerialPort : public Stream {
|
||||
class SerialPort : public Stream
|
||||
{
|
||||
|
||||
private:
|
||||
int sd; //!< @brief file descriptor number.
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
#include "Print.h"
|
||||
|
||||
#if !DOXYGEN
|
||||
class Server : public Print {
|
||||
public:
|
||||
virtual void begin() =0;
|
||||
class Server : public Print
|
||||
{
|
||||
public:
|
||||
virtual void begin() =0;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ SoftEeprom::SoftEeprom(const char *fileName, size_t length)
|
||||
myFile.write((const char*)_values, _length);
|
||||
myFile.close();
|
||||
} else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) {
|
||||
logError("Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", _fileName, _length);
|
||||
logError("Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n",
|
||||
_fileName, _length);
|
||||
exit(1);
|
||||
} else {
|
||||
//Read config into local memory.
|
||||
@@ -98,10 +99,10 @@ void SoftEeprom::readBlock(void* buf, void* addr, size_t length)
|
||||
void SoftEeprom::writeBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
|
||||
|
||||
|
||||
if (length && offs + length <= _length) {
|
||||
memcpy(_values+offs, buf, length);
|
||||
|
||||
|
||||
std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary);
|
||||
if (!myFile) {
|
||||
logError("Unable to write config to file %s.\n", _fileName);
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
/**
|
||||
* SoftEeprom class
|
||||
*/
|
||||
class SoftEeprom {
|
||||
class SoftEeprom
|
||||
{
|
||||
|
||||
private:
|
||||
size_t _length; //!< @brief Eeprom max size.
|
||||
|
||||
+190
-180
@@ -28,50 +28,53 @@
|
||||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
||||
|
||||
// private method to read stream with timeout
|
||||
int Stream::timedRead() {
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = read();
|
||||
if(c >= 0) {
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
int Stream::timedRead()
|
||||
{
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = read();
|
||||
if(c >= 0) {
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// private method to peek stream with timeout
|
||||
int Stream::timedPeek() {
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = peek();
|
||||
if(c >= 0) {
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
int Stream::timedPeek()
|
||||
{
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = peek();
|
||||
if(c >= 0) {
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// returns peek of the next digit in the stream or -1 if timeout
|
||||
// discards non-numeric characters
|
||||
int Stream::peekNextDigit() {
|
||||
int c;
|
||||
while(1) {
|
||||
c = timedPeek();
|
||||
if(c < 0) {
|
||||
return c; // timeout
|
||||
}
|
||||
if(c == '-') {
|
||||
return c;
|
||||
}
|
||||
if(c >= '0' && c <= '9') {
|
||||
return c;
|
||||
}
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
int Stream::peekNextDigit()
|
||||
{
|
||||
int c;
|
||||
while(1) {
|
||||
c = timedPeek();
|
||||
if(c < 0) {
|
||||
return c; // timeout
|
||||
}
|
||||
if(c == '-') {
|
||||
return c;
|
||||
}
|
||||
if(c >= '0' && c <= '9') {
|
||||
return c;
|
||||
}
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
@@ -79,148 +82,151 @@ int Stream::peekNextDigit() {
|
||||
|
||||
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
|
||||
{
|
||||
_timeout = timeout;
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target) {
|
||||
return findUntil(target, (char*) "");
|
||||
bool Stream::find(const char *target)
|
||||
{
|
||||
return findUntil(target, (char*) "");
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of given length is found
|
||||
// returns true if target string is found, false if timed out
|
||||
bool Stream::find(const char *target, size_t length) {
|
||||
return findUntil(target, length, NULL, 0);
|
||||
bool Stream::find(const char *target, size_t length)
|
||||
{
|
||||
return findUntil(target, length, NULL, 0);
|
||||
}
|
||||
|
||||
// as find but search ends if the terminator string is found
|
||||
bool Stream::findUntil(const char *target, const char *terminator) {
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
bool Stream::findUntil(const char *target, const char *terminator)
|
||||
{
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of the given length is found
|
||||
// search terminated if the terminator string is found
|
||||
// returns true if target string is found, false if terminated or timed out
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) {
|
||||
size_t index = 0; // maximum target string length is 64k bytes!
|
||||
size_t termIndex = 0;
|
||||
int c;
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator,
|
||||
size_t termLen)
|
||||
{
|
||||
size_t index = 0; // maximum target string length is 64k bytes!
|
||||
size_t termIndex = 0;
|
||||
int c;
|
||||
|
||||
if(*target == 0) {
|
||||
return true; // return true if target is a null string
|
||||
}
|
||||
while((c = timedRead()) > 0) {
|
||||
if(*target == 0) {
|
||||
return true; // return true if target is a null string
|
||||
}
|
||||
while((c = timedRead()) > 0) {
|
||||
|
||||
if(c != target[index]) {
|
||||
index = 0; // reset index if any char does not match
|
||||
}
|
||||
if(c == target[index]) {
|
||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
|
||||
if(++index >= targetLen) { // return true if all chars in the target match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(c != target[index]) {
|
||||
index = 0; // reset index if any char does not match
|
||||
}
|
||||
if(c == target[index]) {
|
||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
|
||||
if(++index >= targetLen) { // return true if all chars in the target match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(termLen > 0 && c == terminator[termIndex]) {
|
||||
if(++termIndex >= termLen) {
|
||||
return false; // return false if terminate string found before target string
|
||||
}
|
||||
} else {
|
||||
termIndex = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if(termLen > 0 && c == terminator[termIndex]) {
|
||||
if(++termIndex >= termLen) {
|
||||
return false; // return false if terminate string found before target string
|
||||
}
|
||||
} else {
|
||||
termIndex = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// function is terminated by the first character that is not a digit.
|
||||
long Stream::parseInt() {
|
||||
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||
long Stream::parseInt()
|
||||
{
|
||||
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||
}
|
||||
|
||||
// as above but a given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
long Stream::parseInt(char skipChar) {
|
||||
boolean isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
long Stream::parseInt(char skipChar)
|
||||
{
|
||||
boolean isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if(c == skipChar) {
|
||||
// ignore this charactor
|
||||
}
|
||||
else if(c == '-') {
|
||||
isNegative = true;
|
||||
}
|
||||
else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == skipChar);
|
||||
do {
|
||||
if(c == skipChar) {
|
||||
// ignore this charactor
|
||||
} else if(c == '-') {
|
||||
isNegative = true;
|
||||
} else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == skipChar);
|
||||
|
||||
if(isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
if(isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat() {
|
||||
return parseFloat(NO_SKIP_CHAR);
|
||||
float Stream::parseFloat()
|
||||
{
|
||||
return parseFloat(NO_SKIP_CHAR);
|
||||
}
|
||||
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
float Stream::parseFloat(char skipChar) {
|
||||
boolean isNegative = false;
|
||||
boolean isFraction = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
float fraction = 1.0;
|
||||
float Stream::parseFloat(char skipChar)
|
||||
{
|
||||
boolean isNegative = false;
|
||||
boolean isFraction = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
float fraction = 1.0;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if(c == skipChar) {
|
||||
// ignore
|
||||
}
|
||||
else if(c == '-') {
|
||||
isNegative = true;
|
||||
}
|
||||
else if(c == '.') {
|
||||
isFraction = true;
|
||||
}
|
||||
else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
if(isFraction) {
|
||||
fraction *= 0.1;
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
||||
do {
|
||||
if(c == skipChar) {
|
||||
// ignore
|
||||
} else if(c == '-') {
|
||||
isNegative = true;
|
||||
} else if(c == '.') {
|
||||
isFraction = true;
|
||||
} else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
if(isFraction) {
|
||||
fraction *= 0.1;
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
||||
|
||||
if(isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
if(isFraction) {
|
||||
return value * fraction;
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
if(isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
if(isFraction) {
|
||||
return value * fraction;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
@@ -228,55 +234,59 @@ float Stream::parseFloat(char skipChar) {
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length) {
|
||||
size_t count = 0;
|
||||
while(count < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
size_t Stream::readBytes(char *buffer, size_t length)
|
||||
{
|
||||
size_t count = 0;
|
||||
while(count < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// as readBytes with terminator character
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) {
|
||||
if(length < 1) {
|
||||
return 0;
|
||||
}
|
||||
size_t index = 0;
|
||||
while(index < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0 || c == terminator) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
||||
{
|
||||
if(length < 1) {
|
||||
return 0;
|
||||
}
|
||||
size_t index = 0;
|
||||
while(index < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0 || c == terminator) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
std::string Stream::readString() {
|
||||
std::string ret;
|
||||
int c = timedRead();
|
||||
while(c >= 0) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
std::string Stream::readString()
|
||||
{
|
||||
std::string ret;
|
||||
int c = timedRead();
|
||||
while(c >= 0) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Stream::readStringUntil(char terminator) {
|
||||
std::string ret;
|
||||
int c = timedRead();
|
||||
while(c >= 0 && c != terminator) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
std::string Stream::readStringUntil(char terminator)
|
||||
{
|
||||
std::string ret;
|
||||
int c = timedRead();
|
||||
while(c >= 0 && c != terminator) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
+77
-60
@@ -38,82 +38,99 @@
|
||||
*/
|
||||
|
||||
#if !DOXYGEN
|
||||
class Stream: public Print {
|
||||
protected:
|
||||
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
||||
class Stream: public Print
|
||||
{
|
||||
protected:
|
||||
unsigned long
|
||||
_timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
||||
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
|
||||
Stream() {
|
||||
_timeout = 1000;
|
||||
}
|
||||
Stream()
|
||||
{
|
||||
_timeout = 1000;
|
||||
}
|
||||
|
||||
// parsing methods
|
||||
// parsing methods
|
||||
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
void setTimeout(unsigned long
|
||||
timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target) {
|
||||
return find((char *) target);
|
||||
}
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target)
|
||||
{
|
||||
return find((char *) target);
|
||||
}
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
|
||||
bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found
|
||||
bool find(const uint8_t *target, size_t length) {
|
||||
return find((char *) target, length);
|
||||
}
|
||||
// returns true if target string is found, false if timed out
|
||||
bool find(const char *target, size_t
|
||||
length); // reads data from the stream until the target string of given length is found
|
||||
bool find(const uint8_t *target, size_t length)
|
||||
{
|
||||
return find((char *) target, length);
|
||||
}
|
||||
// returns true if target string is found, false if timed out
|
||||
|
||||
bool find(char target) { return find (&target, 1); }
|
||||
bool find(char target)
|
||||
{
|
||||
return find (&target, 1);
|
||||
}
|
||||
|
||||
bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(const uint8_t *target, const char *terminator) {
|
||||
return findUntil((char *) target, terminator);
|
||||
}
|
||||
bool findUntil(const char *target,
|
||||
const char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(const uint8_t *target, const char *terminator)
|
||||
{
|
||||
return findUntil((char *) target, terminator);
|
||||
}
|
||||
|
||||
bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {
|
||||
return findUntil((char *) target, targetLen, terminate, termLen);
|
||||
}
|
||||
bool findUntil(const char *target, size_t targetLen, const char *terminate,
|
||||
size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen)
|
||||
{
|
||||
return findUntil((char *) target, targetLen, terminate, termLen);
|
||||
}
|
||||
|
||||
long parseInt(); // returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// integer is terminated by the first character that is not a digit.
|
||||
long parseInt(); // returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// integer is terminated by the first character that is not a digit.
|
||||
|
||||
float parseFloat(); // float version of parseInt
|
||||
float parseFloat(); // float version of parseInt
|
||||
|
||||
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length) {
|
||||
return readBytes((char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
return readBytes((char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character
|
||||
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) {
|
||||
return readBytesUntil(terminator, (char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
size_t readBytesUntil(char terminator, char *buffer,
|
||||
size_t length); // as readBytes with terminator character
|
||||
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length)
|
||||
{
|
||||
return readBytesUntil(terminator, (char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
// Arduino String functions to be added here
|
||||
std::string readString();
|
||||
std::string readStringUntil(char terminator);
|
||||
// Arduino String functions to be added here
|
||||
std::string readString();
|
||||
std::string readStringUntil(char terminator);
|
||||
|
||||
protected:
|
||||
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
protected:
|
||||
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
|
||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,46 +23,46 @@ unsigned long millis(void)
|
||||
|
||||
unsigned long micros()
|
||||
{
|
||||
timeval curTime;
|
||||
timeval curTime;
|
||||
|
||||
if (millis_at_start == 0) {
|
||||
gettimeofday(&curTime, NULL);
|
||||
millis_at_start = curTime.tv_sec;
|
||||
}
|
||||
if (millis_at_start == 0) {
|
||||
gettimeofday(&curTime, NULL);
|
||||
millis_at_start = curTime.tv_sec;
|
||||
}
|
||||
|
||||
gettimeofday(&curTime, NULL);
|
||||
return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec);
|
||||
gettimeofday(&curTime, NULL);
|
||||
return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec);
|
||||
}
|
||||
|
||||
void _delay_ms(unsigned int millis)
|
||||
{
|
||||
struct timespec sleeper;
|
||||
|
||||
sleeper.tv_sec = (time_t)(millis / 1000);
|
||||
sleeper.tv_nsec = (long)(millis % 1000) * 1000000;
|
||||
nanosleep(&sleeper, NULL);
|
||||
struct timespec sleeper;
|
||||
|
||||
sleeper.tv_sec = (time_t)(millis / 1000);
|
||||
sleeper.tv_nsec = (long)(millis % 1000) * 1000000;
|
||||
nanosleep(&sleeper, NULL);
|
||||
}
|
||||
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
if (seed != 0) {
|
||||
srand(seed);
|
||||
}
|
||||
if (seed != 0) {
|
||||
srand(seed);
|
||||
}
|
||||
}
|
||||
|
||||
long randMax(long howbig)
|
||||
{
|
||||
if (howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
return rand() % howbig;
|
||||
if (howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
return rand() % howbig;
|
||||
}
|
||||
|
||||
long randMinMax(long howsmall, long howbig)
|
||||
{
|
||||
if (howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return randMax(diff) + howsmall;
|
||||
if (howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return randMax(diff) + howsmall;
|
||||
}
|
||||
|
||||
+102
-93
@@ -23,127 +23,136 @@
|
||||
#include <math.h>
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
char* utoa(unsigned value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
char* utoa(unsigned value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
unsigned quotient = value;
|
||||
char* out = result;
|
||||
unsigned quotient = value;
|
||||
|
||||
do {
|
||||
const unsigned tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
do {
|
||||
const unsigned tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* itoa(int value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
char* itoa(int value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
int quotient = abs(value);
|
||||
char* out = result;
|
||||
int quotient = abs(value);
|
||||
|
||||
do {
|
||||
const int tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
do {
|
||||
const int tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
// Apply negative sign
|
||||
if(value < 0) {
|
||||
*out++ = '-';
|
||||
}
|
||||
// Apply negative sign
|
||||
if(value < 0) {
|
||||
*out++ = '-';
|
||||
}
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int atoi(const char* s) {
|
||||
return (int) atol(s);
|
||||
int atoi(const char* s)
|
||||
{
|
||||
return (int) atol(s);
|
||||
}
|
||||
|
||||
long atol(const char* s) {
|
||||
char * tmp;
|
||||
return strtol(s, &tmp, 10);
|
||||
long atol(const char* s)
|
||||
{
|
||||
char * tmp;
|
||||
return strtol(s, &tmp, 10);
|
||||
}
|
||||
|
||||
double atof(const char* s) {
|
||||
char * tmp;
|
||||
return strtod(s, &tmp);
|
||||
double atof(const char* s)
|
||||
{
|
||||
char * tmp;
|
||||
return strtod(s, &tmp);
|
||||
}
|
||||
|
||||
void reverse(char* begin, char* end) {
|
||||
char *is = begin;
|
||||
char *ie = end - 1;
|
||||
while(is < ie) {
|
||||
char tmp = *ie;
|
||||
*ie = *is;
|
||||
*is = tmp;
|
||||
++is;
|
||||
--ie;
|
||||
}
|
||||
void reverse(char* begin, char* end)
|
||||
{
|
||||
char *is = begin;
|
||||
char *ie = end - 1;
|
||||
while(is < ie) {
|
||||
char tmp = *ie;
|
||||
*ie = *is;
|
||||
*is = tmp;
|
||||
++is;
|
||||
--ie;
|
||||
}
|
||||
}
|
||||
|
||||
char* ltoa(long value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
char* ltoa(long value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
long quotient = abs(value);
|
||||
char* out = result;
|
||||
long quotient = abs(value);
|
||||
|
||||
do {
|
||||
const long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
do {
|
||||
const long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
// Apply negative sign
|
||||
if(value < 0) {
|
||||
*out++ = '-';
|
||||
}
|
||||
// Apply negative sign
|
||||
if(value < 0) {
|
||||
*out++ = '-';
|
||||
}
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* ultoa(unsigned long value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
char* ultoa(unsigned long value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
unsigned long quotient = value;
|
||||
char* out = result;
|
||||
unsigned long quotient = value;
|
||||
|
||||
do {
|
||||
const unsigned long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
do {
|
||||
const unsigned long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* dtostrf (double val, signed char width, unsigned char prec, char *s) {
|
||||
sprintf(s,"%*.*f", width, prec, val);
|
||||
return s;
|
||||
char* dtostrf (double val, signed char width, unsigned char prec, char *s)
|
||||
{
|
||||
sprintf(s,"%*.*f", width, prec, val);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
/*
|
||||
stdlib_noniso.h - nonstandard (but usefull) conversion functions
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
|
||||
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
|
||||
@@ -23,7 +23,7 @@
|
||||
#define STDLIB_NONISO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int atoi(const char *s);
|
||||
@@ -39,7 +39,7 @@ char* ltoa (long val, char *s, int radix);
|
||||
char* utoa (unsigned int val, char *s, int radix);
|
||||
|
||||
char* ultoa (unsigned long val, char *s, int radix);
|
||||
|
||||
|
||||
char* dtostrf (double val, signed char width, unsigned char prec, char *s);
|
||||
|
||||
void reverse(char* begin, char* end);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -81,64 +81,72 @@
|
||||
#endif
|
||||
|
||||
/** PubSubClient class */
|
||||
class PubSubClient {
|
||||
class PubSubClient
|
||||
{
|
||||
private:
|
||||
Client* _client;
|
||||
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
|
||||
uint16_t nextMsgId;
|
||||
unsigned long lastOutActivity;
|
||||
unsigned long lastInActivity;
|
||||
bool pingOutstanding;
|
||||
MQTT_CALLBACK_SIGNATURE;
|
||||
uint16_t readPacket(uint8_t*);
|
||||
boolean readByte(uint8_t * result);
|
||||
boolean readByte(uint8_t * result, uint16_t * index);
|
||||
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
||||
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
||||
IPAddress ip;
|
||||
const char* domain;
|
||||
uint16_t port;
|
||||
Stream* stream;
|
||||
int _state;
|
||||
Client* _client;
|
||||
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
|
||||
uint16_t nextMsgId;
|
||||
unsigned long lastOutActivity;
|
||||
unsigned long lastInActivity;
|
||||
bool pingOutstanding;
|
||||
MQTT_CALLBACK_SIGNATURE;
|
||||
uint16_t readPacket(uint8_t*);
|
||||
boolean readByte(uint8_t * result);
|
||||
boolean readByte(uint8_t * result, uint16_t * index);
|
||||
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
||||
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
||||
IPAddress ip;
|
||||
const char* domain;
|
||||
uint16_t port;
|
||||
Stream* stream;
|
||||
int _state;
|
||||
public:
|
||||
PubSubClient(); //!< PubSubClient
|
||||
PubSubClient(Client& client); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, Client& client); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, Client& client); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, Client& client); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(); //!< PubSubClient
|
||||
PubSubClient(Client& client); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, Client& client); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient
|
||||
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client,
|
||||
Stream&); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, Client& client); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient
|
||||
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client,
|
||||
Stream&); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, Client& client); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, Client& client, Stream&); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient
|
||||
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client,
|
||||
Stream&); //!< PubSubClient
|
||||
|
||||
PubSubClient& setServer(IPAddress ip, uint16_t port); //!< setServer
|
||||
PubSubClient& setServer(uint8_t * ip, uint16_t port); //!< setServer
|
||||
PubSubClient& setServer(const char * domain, uint16_t port); //!< setServer
|
||||
PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); //!< setCallback
|
||||
PubSubClient& setClient(Client& client); //!< setClient
|
||||
PubSubClient& setStream(Stream& stream); //!< setStream
|
||||
PubSubClient& setServer(IPAddress ip, uint16_t port); //!< setServer
|
||||
PubSubClient& setServer(uint8_t * ip, uint16_t port); //!< setServer
|
||||
PubSubClient& setServer(const char * domain, uint16_t port); //!< setServer
|
||||
PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); //!< setCallback
|
||||
PubSubClient& setClient(Client& client); //!< setClient
|
||||
PubSubClient& setStream(Stream& stream); //!< setStream
|
||||
|
||||
boolean connect(const char* id); //!< connect
|
||||
boolean connect(const char* id, const char* user, const char* pass); //!< connect
|
||||
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); //!< connect
|
||||
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); //!< connect
|
||||
void disconnect(); //!< disconnect
|
||||
boolean publish(const char* topic, const char* payload); //!< publish
|
||||
boolean publish(const char* topic, const char* payload, boolean retained); //!< publish
|
||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); //!< publish
|
||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); //!< publish
|
||||
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); //!< publish_P
|
||||
boolean subscribe(const char* topic); //!< subscribe
|
||||
boolean subscribe(const char* topic, uint8_t qos); //!< subscribe
|
||||
boolean unsubscribe(const char* topic); //!< unsubscribe
|
||||
boolean loop(); //!< loop
|
||||
boolean connected(); //!< connected
|
||||
int state(); //!< state
|
||||
boolean connect(const char* id); //!< connect
|
||||
boolean connect(const char* id, const char* user, const char* pass); //!< connect
|
||||
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain,
|
||||
const char* willMessage); //!< connect
|
||||
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic,
|
||||
uint8_t willQos, boolean willRetain, const char* willMessage); //!< connect
|
||||
void disconnect(); //!< disconnect
|
||||
boolean publish(const char* topic, const char* payload); //!< publish
|
||||
boolean publish(const char* topic, const char* payload, boolean retained); //!< publish
|
||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); //!< publish
|
||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength,
|
||||
boolean retained); //!< publish
|
||||
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength,
|
||||
boolean retained); //!< publish_P
|
||||
boolean subscribe(const char* topic); //!< subscribe
|
||||
boolean subscribe(const char* topic, uint8_t qos); //!< subscribe
|
||||
boolean unsubscribe(const char* topic); //!< unsubscribe
|
||||
boolean loop(); //!< loop
|
||||
boolean connected(); //!< connected
|
||||
int state(); //!< state
|
||||
};
|
||||
|
||||
|
||||
|
||||
+239
-234
@@ -36,405 +36,410 @@ uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte
|
||||
|
||||
LOCAL void RF24_csn(const bool level)
|
||||
{
|
||||
hwDigitalWrite(MY_RF24_CS_PIN, level);
|
||||
hwDigitalWrite(MY_RF24_CS_PIN, level);
|
||||
}
|
||||
|
||||
LOCAL void RF24_ce(const bool level)
|
||||
{
|
||||
hwDigitalWrite(MY_RF24_CE_PIN, level);
|
||||
hwDigitalWrite(MY_RF24_CE_PIN, level);
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode)
|
||||
LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len,
|
||||
const bool aReadMode)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t* current = buf;
|
||||
uint8_t status;
|
||||
uint8_t* current = buf;
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE));
|
||||
_SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER,
|
||||
MY_RF24_SPI_DATA_MODE));
|
||||
#endif
|
||||
RF24_csn(LOW);
|
||||
// timing
|
||||
delayMicroseconds(10);
|
||||
RF24_csn(LOW);
|
||||
// timing
|
||||
delayMicroseconds(10);
|
||||
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||
uint8_t * prx = spi_rxbuff;
|
||||
uint8_t * ptx = spi_txbuff;
|
||||
uint8_t size = len + 1; // Add register value to transmit buffer
|
||||
uint8_t * prx = spi_rxbuff;
|
||||
uint8_t * ptx = spi_txbuff;
|
||||
uint8_t size = len + 1; // Add register value to transmit buffer
|
||||
|
||||
*ptx++ = cmd;
|
||||
while ( len-- ) {
|
||||
if (aReadMode) {
|
||||
*ptx++ = RF24_NOP;
|
||||
} else {
|
||||
*ptx++ = *current++;
|
||||
}
|
||||
}
|
||||
_SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size);
|
||||
if (aReadMode) {
|
||||
if (size == 2) {
|
||||
status = *++prx; // result is 2nd byte of receive buffer
|
||||
} else {
|
||||
status = *prx++; // status is 1st byte of receive buffer
|
||||
// decrement before to skip status byte
|
||||
while (--size) {
|
||||
*buf++ = *prx++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = *prx; // status is 1st byte of receive buffer
|
||||
}
|
||||
*ptx++ = cmd;
|
||||
while ( len-- ) {
|
||||
if (aReadMode) {
|
||||
*ptx++ = RF24_NOP;
|
||||
} else {
|
||||
*ptx++ = *current++;
|
||||
}
|
||||
}
|
||||
_SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size);
|
||||
if (aReadMode) {
|
||||
if (size == 2) {
|
||||
status = *++prx; // result is 2nd byte of receive buffer
|
||||
} else {
|
||||
status = *prx++; // status is 1st byte of receive buffer
|
||||
// decrement before to skip status byte
|
||||
while (--size) {
|
||||
*buf++ = *prx++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = *prx; // status is 1st byte of receive buffer
|
||||
}
|
||||
#else
|
||||
status = _SPI.transfer(cmd);
|
||||
while ( len-- ) {
|
||||
if (aReadMode) {
|
||||
status = _SPI.transfer(RF24_NOP);
|
||||
if (buf != NULL) {
|
||||
*current++ = status;
|
||||
}
|
||||
} else {
|
||||
status = _SPI.transfer(*current++);
|
||||
}
|
||||
}
|
||||
status = _SPI.transfer(cmd);
|
||||
while ( len-- ) {
|
||||
if (aReadMode) {
|
||||
status = _SPI.transfer(RF24_NOP);
|
||||
if (buf != NULL) {
|
||||
*current++ = status;
|
||||
}
|
||||
} else {
|
||||
status = _SPI.transfer(*current++);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
RF24_csn(HIGH);
|
||||
RF24_csn(HIGH);
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_SPI.endTransaction();
|
||||
_SPI.endTransaction();
|
||||
#endif
|
||||
// timing
|
||||
delayMicroseconds(10);
|
||||
return status;
|
||||
// timing
|
||||
delayMicroseconds(10);
|
||||
return status;
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_spiByteTransfer(const uint8_t cmd)
|
||||
{
|
||||
return RF24_spiMultiByteTransfer(cmd, NULL, 0, false);
|
||||
return RF24_spiMultiByteTransfer(cmd, NULL, 0, false);
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_RAW_readByteRegister(const uint8_t cmd)
|
||||
{
|
||||
const uint8_t value = RF24_spiMultiByteTransfer(cmd, NULL, 1, true);
|
||||
RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value);
|
||||
return value;
|
||||
const uint8_t value = RF24_spiMultiByteTransfer(cmd, NULL, 1, true);
|
||||
RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, uint8_t value)
|
||||
{
|
||||
RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value);
|
||||
return RF24_spiMultiByteTransfer( cmd , &value, 1, false);
|
||||
RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value);
|
||||
return RF24_spiMultiByteTransfer( cmd , &value, 1, false);
|
||||
}
|
||||
|
||||
LOCAL void RF24_flushRX(void)
|
||||
{
|
||||
RF24_DEBUG(PSTR("RF24:flushRX\n"));
|
||||
RF24_spiByteTransfer(RF24_FLUSH_RX);
|
||||
RF24_DEBUG(PSTR("RF24:flushRX\n"));
|
||||
RF24_spiByteTransfer(RF24_FLUSH_RX);
|
||||
}
|
||||
|
||||
LOCAL void RF24_flushTX(void)
|
||||
{
|
||||
RF24_DEBUG(PSTR("RF24:flushTX\n"));
|
||||
RF24_spiByteTransfer(RF24_FLUSH_TX);
|
||||
RF24_DEBUG(PSTR("RF24:flushTX\n"));
|
||||
RF24_spiByteTransfer(RF24_FLUSH_TX);
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_getStatus(void)
|
||||
{
|
||||
return RF24_spiByteTransfer(RF24_NOP);
|
||||
return RF24_spiByteTransfer(RF24_NOP);
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_getFIFOStatus(void)
|
||||
{
|
||||
return RF24_readByteRegister(RF24_FIFO_STATUS);
|
||||
return RF24_readByteRegister(RF24_FIFO_STATUS);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setChannel(const uint8_t channel)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_RF_CH,channel);
|
||||
RF24_writeByteRegister(RF24_RF_CH,channel);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setRetries(const uint8_t retransmitDelay, const uint8_t retransmitCount)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_SETUP_RETR, retransmitDelay << RF24_ARD | retransmitCount << RF24_ARC);
|
||||
RF24_writeByteRegister(RF24_SETUP_RETR, retransmitDelay << RF24_ARD | retransmitCount << RF24_ARC);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setAddressWidth(const uint8_t width)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_SETUP_AW, width - 2);
|
||||
RF24_writeByteRegister(RF24_SETUP_AW, width - 2);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setRFSetup(const uint8_t RFsetup)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_RF_SETUP, RFsetup);
|
||||
RF24_writeByteRegister(RF24_RF_SETUP, RFsetup);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setFeature(const uint8_t feature)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_FEATURE, feature);
|
||||
RF24_writeByteRegister(RF24_FEATURE, feature);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setPipe(const uint8_t pipe)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_EN_RXADDR, pipe);
|
||||
RF24_writeByteRegister(RF24_EN_RXADDR, pipe);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setAutoACK(const uint8_t pipe)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_EN_AA, pipe);
|
||||
RF24_writeByteRegister(RF24_EN_AA, pipe);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setDynamicPayload(const uint8_t pipe)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_DYNPD, pipe);
|
||||
RF24_writeByteRegister(RF24_DYNPD, pipe);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setRFConfiguration(const uint8_t configuration)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_NRF_CONFIG, configuration);
|
||||
RF24_writeByteRegister(RF24_NRF_CONFIG, configuration);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t width)
|
||||
{
|
||||
RF24_writeMultiByteRegister(pipe, address, width);
|
||||
RF24_writeMultiByteRegister(pipe, address, width);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setPipeLSB(const uint8_t pipe, const uint8_t LSB)
|
||||
{
|
||||
RF24_writeByteRegister(pipe, LSB);
|
||||
RF24_writeByteRegister(pipe, LSB);
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_getObserveTX(void)
|
||||
{
|
||||
return RF24_readByteRegister(RF24_OBSERVE_TX);
|
||||
return RF24_readByteRegister(RF24_OBSERVE_TX);
|
||||
}
|
||||
|
||||
LOCAL void RF24_setStatus(const uint8_t status)
|
||||
{
|
||||
RF24_writeByteRegister(RF24_STATUS, status);
|
||||
RF24_writeByteRegister(RF24_STATUS, status);
|
||||
}
|
||||
LOCAL void RF24_enableFeatures(void)
|
||||
{
|
||||
RF24_RAW_writeByteRegister(RF24_ACTIVATE, 0x73);
|
||||
RF24_RAW_writeByteRegister(RF24_ACTIVATE, 0x73);
|
||||
}
|
||||
|
||||
LOCAL void RF24_openWritingPipe(const uint8_t recipient)
|
||||
{
|
||||
RF24_DEBUG(PSTR("RF24:OPEN WPIPE,RCPT=%d\n"), recipient); // open writing pipe
|
||||
// only write LSB of RX0 and TX pipe
|
||||
RF24_setPipeLSB(RF24_RX_ADDR_P0, recipient);
|
||||
RF24_setPipeLSB(RF24_TX_ADDR, recipient);
|
||||
RF24_DEBUG(PSTR("RF24:OPEN WPIPE,RCPT=%d\n"), recipient); // open writing pipe
|
||||
// only write LSB of RX0 and TX pipe
|
||||
RF24_setPipeLSB(RF24_RX_ADDR_P0, recipient);
|
||||
RF24_setPipeLSB(RF24_TX_ADDR, recipient);
|
||||
}
|
||||
|
||||
LOCAL void RF24_startListening(void)
|
||||
{
|
||||
RF24_DEBUG(PSTR("RF24:STRT LIS\n")); // start listening
|
||||
// toggle PRX
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) | _BV(RF24_PRIM_RX) );
|
||||
// all RX pipe addresses must be unique, therefore skip if node ID is AUTO
|
||||
if(MY_RF24_NODE_ADDRESS!=AUTO) {
|
||||
RF24_setPipeLSB(RF24_RX_ADDR_P0, MY_RF24_NODE_ADDRESS);
|
||||
}
|
||||
// start listening
|
||||
RF24_ce(HIGH);
|
||||
RF24_DEBUG(PSTR("RF24:STRT LIS\n")); // start listening
|
||||
// toggle PRX
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) | _BV(RF24_PRIM_RX) );
|
||||
// all RX pipe addresses must be unique, therefore skip if node ID is AUTO
|
||||
if(MY_RF24_NODE_ADDRESS!=AUTO) {
|
||||
RF24_setPipeLSB(RF24_RX_ADDR_P0, MY_RF24_NODE_ADDRESS);
|
||||
}
|
||||
// start listening
|
||||
RF24_ce(HIGH);
|
||||
}
|
||||
|
||||
LOCAL void RF24_stopListening(void)
|
||||
{
|
||||
RF24_DEBUG(PSTR("RF24:STP LIS\n")); // stop listening
|
||||
RF24_ce(LOW);
|
||||
// timing
|
||||
delayMicroseconds(130);
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) );
|
||||
// timing
|
||||
delayMicroseconds(100);
|
||||
RF24_DEBUG(PSTR("RF24:STP LIS\n")); // stop listening
|
||||
RF24_ce(LOW);
|
||||
// timing
|
||||
delayMicroseconds(130);
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) );
|
||||
// timing
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
LOCAL void RF24_powerDown(void)
|
||||
{
|
||||
RF24_ce(LOW);
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION);
|
||||
RF24_DEBUG(PSTR("RF24:PD\n")); // power down
|
||||
RF24_ce(LOW);
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION);
|
||||
RF24_DEBUG(PSTR("RF24:PD\n")); // power down
|
||||
}
|
||||
|
||||
LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len)
|
||||
{
|
||||
uint8_t RF24_status;
|
||||
RF24_stopListening();
|
||||
RF24_openWritingPipe( recipient );
|
||||
RF24_DEBUG(PSTR("RF24:SND:TO=%d,LEN=%d\n"),recipient,len); // send message
|
||||
// flush TX FIFO
|
||||
RF24_flushTX();
|
||||
// this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD
|
||||
// AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending
|
||||
RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? RF24_WRITE_TX_PAYLOAD_NO_ACK : RF24_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false );
|
||||
// go, TX starts after ~10us
|
||||
RF24_ce(HIGH);
|
||||
// timeout counter to detect HW issues
|
||||
uint16_t timeout = 0xFFFF;
|
||||
do {
|
||||
RF24_status = RF24_getStatus();
|
||||
} while (!(RF24_status & ( _BV(RF24_MAX_RT) | _BV(RF24_TX_DS) )) && timeout--);
|
||||
// timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles
|
||||
RF24_ce(LOW);
|
||||
// reset interrupts
|
||||
RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) );
|
||||
// Max retries exceeded
|
||||
if(RF24_status & _BV(RF24_MAX_RT)) {
|
||||
// flush packet
|
||||
RF24_DEBUG(PSTR("!RF24:SND:MAX_RT\n")); // max retries, no ACK
|
||||
RF24_flushTX();
|
||||
}
|
||||
RF24_startListening();
|
||||
// true if message sent
|
||||
return (RF24_status & _BV(RF24_TX_DS));
|
||||
uint8_t RF24_status;
|
||||
RF24_stopListening();
|
||||
RF24_openWritingPipe( recipient );
|
||||
RF24_DEBUG(PSTR("RF24:SND:TO=%d,LEN=%d\n"),recipient,len); // send message
|
||||
// flush TX FIFO
|
||||
RF24_flushTX();
|
||||
// this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD
|
||||
// AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending
|
||||
RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? RF24_WRITE_TX_PAYLOAD_NO_ACK :
|
||||
RF24_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false );
|
||||
// go, TX starts after ~10us
|
||||
RF24_ce(HIGH);
|
||||
// timeout counter to detect HW issues
|
||||
uint16_t timeout = 0xFFFF;
|
||||
do {
|
||||
RF24_status = RF24_getStatus();
|
||||
} while (!(RF24_status & ( _BV(RF24_MAX_RT) | _BV(RF24_TX_DS) )) && timeout--);
|
||||
// timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles
|
||||
RF24_ce(LOW);
|
||||
// reset interrupts
|
||||
RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) );
|
||||
// Max retries exceeded
|
||||
if(RF24_status & _BV(RF24_MAX_RT)) {
|
||||
// flush packet
|
||||
RF24_DEBUG(PSTR("!RF24:SND:MAX_RT\n")); // max retries, no ACK
|
||||
RF24_flushTX();
|
||||
}
|
||||
RF24_startListening();
|
||||
// true if message sent
|
||||
return (RF24_status & _BV(RF24_TX_DS));
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_getDynamicPayloadSize(void)
|
||||
{
|
||||
uint8_t result = RF24_spiMultiByteTransfer(RF24_READ_RX_PL_WID, NULL, 1, true);
|
||||
// check if payload size invalid
|
||||
if(result > 32) {
|
||||
RF24_DEBUG(PSTR("!RF24:GDP:PAYL LEN INVALID=%d\n"),result); // payload len invalid
|
||||
RF24_flushRX();
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
uint8_t result = RF24_spiMultiByteTransfer(RF24_READ_RX_PL_WID, NULL, 1, true);
|
||||
// check if payload size invalid
|
||||
if(result > 32) {
|
||||
RF24_DEBUG(PSTR("!RF24:GDP:PAYL LEN INVALID=%d\n"),result); // payload len invalid
|
||||
RF24_flushRX();
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LOCAL bool RF24_isDataAvailable()
|
||||
{
|
||||
return (!(RF24_getFIFOStatus() & _BV(0)) );
|
||||
return (!(RF24_getFIFOStatus() & _BV(0)) );
|
||||
}
|
||||
|
||||
|
||||
LOCAL uint8_t RF24_readMessage(void* buf)
|
||||
{
|
||||
const uint8_t len = RF24_getDynamicPayloadSize();
|
||||
RF24_DEBUG(PSTR("RF24:RDM:MSG LEN=%d\n"), len); // read message
|
||||
RF24_spiMultiByteTransfer(RF24_READ_RX_PAYLOAD,(uint8_t*)buf,len,true);
|
||||
// clear RX interrupt
|
||||
RF24_setStatus(_BV(RF24_RX_DR));
|
||||
return len;
|
||||
const uint8_t len = RF24_getDynamicPayloadSize();
|
||||
RF24_DEBUG(PSTR("RF24:RDM:MSG LEN=%d\n"), len); // read message
|
||||
RF24_spiMultiByteTransfer(RF24_READ_RX_PAYLOAD,(uint8_t*)buf,len,true);
|
||||
// clear RX interrupt
|
||||
RF24_setStatus(_BV(RF24_RX_DR));
|
||||
return len;
|
||||
}
|
||||
|
||||
LOCAL void RF24_setNodeAddress(const uint8_t address)
|
||||
{
|
||||
if(address!=AUTO) {
|
||||
MY_RF24_NODE_ADDRESS = address;
|
||||
// enable node pipe
|
||||
RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_ERX_P0));
|
||||
// enable autoACK on pipe 0
|
||||
RF24_setAutoACK(_BV(RF24_ENAA_P0));
|
||||
}
|
||||
if(address!=AUTO) {
|
||||
MY_RF24_NODE_ADDRESS = address;
|
||||
// enable node pipe
|
||||
RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_ERX_P0));
|
||||
// enable autoACK on pipe 0
|
||||
RF24_setAutoACK(_BV(RF24_ENAA_P0));
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL uint8_t RF24_getNodeID(void)
|
||||
{
|
||||
return MY_RF24_NODE_ADDRESS;
|
||||
return MY_RF24_NODE_ADDRESS;
|
||||
}
|
||||
|
||||
LOCAL bool RF24_sanityCheck(void)
|
||||
{
|
||||
// detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected
|
||||
return (RF24_readByteRegister(RF24_RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister(RF24_RF_CH) == MY_RF24_CHANNEL);
|
||||
// detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected
|
||||
return (RF24_readByteRegister(RF24_RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister(
|
||||
RF24_RF_CH) == MY_RF24_CHANNEL);
|
||||
}
|
||||
|
||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
||||
LOCAL void RF24_irqHandler(void)
|
||||
{
|
||||
if (RF24_receiveCallback) {
|
||||
// Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial
|
||||
// rx coming in during our stay will not be handled and will cause characters to be lost.
|
||||
// As a workaround we re-enable interrupts to allow nested processing of other interrupts.
|
||||
// Our own handler is disconnected to prevent recursive calling of this handler.
|
||||
if (RF24_receiveCallback) {
|
||||
// Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial
|
||||
// rx coming in during our stay will not be handled and will cause characters to be lost.
|
||||
// As a workaround we re-enable interrupts to allow nested processing of other interrupts.
|
||||
// Our own handler is disconnected to prevent recursive calling of this handler.
|
||||
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
|
||||
detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||
interrupts();
|
||||
detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||
interrupts();
|
||||
#endif
|
||||
// Read FIFO until empty.
|
||||
// Procedure acc. to datasheet (pg. 63):
|
||||
// 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available.
|
||||
// Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS.
|
||||
// Read FIFO until empty.
|
||||
// Procedure acc. to datasheet (pg. 63):
|
||||
// 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available.
|
||||
// Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS.
|
||||
|
||||
// Start checking if RX-FIFO is not empty, as we might end up here from an interrupt
|
||||
// for a message we've already read.
|
||||
while (RF24_isDataAvailable()) {
|
||||
RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
|
||||
}
|
||||
// Restore our interrupt handler.
|
||||
// Start checking if RX-FIFO is not empty, as we might end up here from an interrupt
|
||||
// for a message we've already read.
|
||||
while (RF24_isDataAvailable()) {
|
||||
RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
|
||||
}
|
||||
// Restore our interrupt handler.
|
||||
#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__)
|
||||
noInterrupts();
|
||||
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
||||
noInterrupts();
|
||||
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
||||
#endif
|
||||
} else {
|
||||
// clear RX interrupt
|
||||
RF24_setStatus(_BV(RF24_RX_DR));
|
||||
}
|
||||
} else {
|
||||
// clear RX interrupt
|
||||
RF24_setStatus(_BV(RF24_RX_DR));
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb)
|
||||
{
|
||||
MY_CRITICAL_SECTION {
|
||||
RF24_receiveCallback = cb;
|
||||
}
|
||||
MY_CRITICAL_SECTION {
|
||||
RF24_receiveCallback = cb;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LOCAL bool RF24_initialize(void)
|
||||
{
|
||||
// prevent warning
|
||||
(void)RF24_getObserveTX;
|
||||
// prevent warning
|
||||
(void)RF24_getObserveTX;
|
||||
|
||||
// Initialize pins
|
||||
hwPinMode(MY_RF24_CE_PIN,OUTPUT);
|
||||
hwPinMode(MY_RF24_CS_PIN,OUTPUT);
|
||||
// Initialize pins
|
||||
hwPinMode(MY_RF24_CE_PIN,OUTPUT);
|
||||
hwPinMode(MY_RF24_CS_PIN,OUTPUT);
|
||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
||||
hwPinMode(MY_RF24_IRQ_PIN,INPUT);
|
||||
hwPinMode(MY_RF24_IRQ_PIN,INPUT);
|
||||
#endif
|
||||
// Initialize SPI
|
||||
_SPI.begin();
|
||||
RF24_ce(LOW);
|
||||
RF24_csn(HIGH);
|
||||
// Initialize SPI
|
||||
_SPI.begin();
|
||||
RF24_ce(LOW);
|
||||
RF24_csn(HIGH);
|
||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
||||
// assure SPI can be used from interrupt context
|
||||
// Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI,
|
||||
// therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI!
|
||||
_SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||
// attach interrupt
|
||||
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
||||
// assure SPI can be used from interrupt context
|
||||
// Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI,
|
||||
// therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI!
|
||||
_SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||
// attach interrupt
|
||||
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
|
||||
#endif
|
||||
// CRC and power up
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP)) ;
|
||||
// settle >2ms
|
||||
delay(5);
|
||||
// set address width
|
||||
RF24_setAddressWidth(MY_RF24_ADDR_WIDTH);
|
||||
// auto retransmit delay 1500us, auto retransmit count 15
|
||||
RF24_setRetries(RF24_SET_ARD, RF24_SET_ARC);
|
||||
// set channel
|
||||
RF24_setChannel(MY_RF24_CHANNEL);
|
||||
// set data rate and pa level
|
||||
RF24_setRFSetup(MY_RF24_RF_SETUP);
|
||||
// toggle features (necessary on some clones and non-P versions)
|
||||
RF24_enableFeatures();
|
||||
// enable ACK payload and dynamic payload
|
||||
RF24_setFeature(MY_RF24_FEATURE);
|
||||
// sanity check (this function is P/non-P independent)
|
||||
if (!RF24_sanityCheck()) {
|
||||
RF24_DEBUG(PSTR("!RF24:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module
|
||||
return false;
|
||||
}
|
||||
// enable broadcasting pipe
|
||||
RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE));
|
||||
// disable AA on all pipes, activate when node pipe set
|
||||
RF24_setAutoACK(0x00);
|
||||
// enable dynamic payloads on used pipes
|
||||
RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0));
|
||||
// listen to broadcast pipe
|
||||
MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS;
|
||||
RF24_setPipeAddress(RF24_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR, RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH);
|
||||
// pipe 0, set full address, later only LSB is updated
|
||||
RF24_setPipeAddress(RF24_RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH);
|
||||
RF24_setPipeAddress(RF24_TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH);
|
||||
// reset FIFO
|
||||
RF24_flushRX();
|
||||
RF24_flushTX();
|
||||
// reset interrupts
|
||||
RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) | _BV(RF24_RX_DR));
|
||||
return true;
|
||||
// CRC and power up
|
||||
RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP)) ;
|
||||
// settle >2ms
|
||||
delay(5);
|
||||
// set address width
|
||||
RF24_setAddressWidth(MY_RF24_ADDR_WIDTH);
|
||||
// auto retransmit delay 1500us, auto retransmit count 15
|
||||
RF24_setRetries(RF24_SET_ARD, RF24_SET_ARC);
|
||||
// set channel
|
||||
RF24_setChannel(MY_RF24_CHANNEL);
|
||||
// set data rate and pa level
|
||||
RF24_setRFSetup(MY_RF24_RF_SETUP);
|
||||
// toggle features (necessary on some clones and non-P versions)
|
||||
RF24_enableFeatures();
|
||||
// enable ACK payload and dynamic payload
|
||||
RF24_setFeature(MY_RF24_FEATURE);
|
||||
// sanity check (this function is P/non-P independent)
|
||||
if (!RF24_sanityCheck()) {
|
||||
RF24_DEBUG(PSTR("!RF24:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module
|
||||
return false;
|
||||
}
|
||||
// enable broadcasting pipe
|
||||
RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE));
|
||||
// disable AA on all pipes, activate when node pipe set
|
||||
RF24_setAutoACK(0x00);
|
||||
// enable dynamic payloads on used pipes
|
||||
RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0));
|
||||
// listen to broadcast pipe
|
||||
MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS;
|
||||
RF24_setPipeAddress(RF24_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR,
|
||||
RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH);
|
||||
// pipe 0, set full address, later only LSB is updated
|
||||
RF24_setPipeAddress(RF24_RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH);
|
||||
RF24_setPipeAddress(RF24_TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH);
|
||||
// reset FIFO
|
||||
RF24_flushRX();
|
||||
RF24_flushTX();
|
||||
// reset interrupts
|
||||
RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) | _BV(RF24_RX_DR));
|
||||
return true;
|
||||
}
|
||||
|
||||
+62
-60
@@ -27,65 +27,66 @@
|
||||
|
||||
// SPI settings
|
||||
#if !defined(MY_RF24_SPI_MAX_SPEED)
|
||||
// default 2Mhz - safe for nRF24L01+ clones
|
||||
#define MY_RF24_SPI_MAX_SPEED 2000000
|
||||
// default 2Mhz - safe for nRF24L01+ clones
|
||||
#define MY_RF24_SPI_MAX_SPEED 2000000
|
||||
#endif
|
||||
#define MY_RF24_SPI_DATA_ORDER MSBFIRST
|
||||
#define MY_RF24_SPI_DATA_MODE SPI_MODE0
|
||||
|
||||
#if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI)
|
||||
#include <SPI.h>
|
||||
#if defined(MY_SOFTSPI)
|
||||
SoftSPI<MY_SOFT_SPI_MISO_PIN, MY_SOFT_SPI_MOSI_PIN, MY_SOFT_SPI_SCK_PIN, MY_RF24_SPI_DATA_MODE> _SPI;
|
||||
#else
|
||||
#define _SPI SPI
|
||||
#endif
|
||||
#include <SPI.h>
|
||||
#if defined(MY_SOFTSPI)
|
||||
SoftSPI<MY_SOFT_SPI_MISO_PIN, MY_SOFT_SPI_MOSI_PIN, MY_SOFT_SPI_SCK_PIN, MY_RF24_SPI_DATA_MODE>
|
||||
_SPI;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define _BV(x) (1<<(x))
|
||||
|
||||
#if defined(__arm__)
|
||||
#include <SPI.h>
|
||||
#else
|
||||
extern HardwareSPI SPI;
|
||||
#endif
|
||||
|
||||
#if !defined(_SPI)
|
||||
#define _SPI SPI
|
||||
#endif
|
||||
#define _SPI SPI
|
||||
#endif
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define _BV(x) (1<<(x))
|
||||
|
||||
#if defined(__arm__)
|
||||
#include <SPI.h>
|
||||
#else
|
||||
extern HardwareSPI SPI;
|
||||
#endif
|
||||
|
||||
#if !defined(_SPI)
|
||||
#define _SPI SPI
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// verify RF24 IRQ defs
|
||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
||||
#if !defined(MY_RF24_IRQ_PIN)
|
||||
#error Message buffering feature requires MY_RF24_IRQ_PIN to be defined!
|
||||
#endif
|
||||
// SoftSPI does not support usingInterrupt()
|
||||
#ifdef MY_SOFTSPI
|
||||
#error RF24 IRQ usage cannot be used with Soft SPI
|
||||
#endif
|
||||
// ESP8266 does not support usingInterrupt()
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#error RF24 IRQ usage cannot be used with ESP8266
|
||||
#endif
|
||||
#ifndef SPI_HAS_TRANSACTION
|
||||
#error RF24 IRQ usage requires transactional SPI support
|
||||
#endif
|
||||
#if !defined(MY_RF24_IRQ_PIN)
|
||||
#error Message buffering feature requires MY_RF24_IRQ_PIN to be defined!
|
||||
#endif
|
||||
// SoftSPI does not support usingInterrupt()
|
||||
#ifdef MY_SOFTSPI
|
||||
#error RF24 IRQ usage cannot be used with Soft SPI
|
||||
#endif
|
||||
// ESP8266 does not support usingInterrupt()
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#error RF24 IRQ usage cannot be used with ESP8266
|
||||
#endif
|
||||
#ifndef SPI_HAS_TRANSACTION
|
||||
#error RF24 IRQ usage requires transactional SPI support
|
||||
#endif
|
||||
#else
|
||||
#ifdef MY_RX_MESSAGE_BUFFER_SIZE
|
||||
#error Receive message buffering requires RF24 IRQ usage
|
||||
#endif
|
||||
#ifdef MY_RX_MESSAGE_BUFFER_SIZE
|
||||
#error Receive message buffering requires RF24 IRQ usage
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// RF24 settings
|
||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
||||
#define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << RF24_MASK_TX_DS) | (1 << RF24_MASK_MAX_RT))
|
||||
#define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << RF24_MASK_TX_DS) | (1 << RF24_MASK_MAX_RT))
|
||||
#else
|
||||
#define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2)
|
||||
#define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2)
|
||||
#endif
|
||||
#define MY_RF24_FEATURE (uint8_t)( _BV(RF24_EN_DPL) | _BV(RF24_EN_ACK_PAY) )
|
||||
#define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1
|
||||
@@ -94,11 +95,11 @@
|
||||
#define RF24_BROADCAST_PIPE (1)
|
||||
#define RF24_NODE_PIPE (0)
|
||||
|
||||
// debug
|
||||
// debug
|
||||
#if defined(MY_DEBUG_VERBOSE_RF24)
|
||||
#define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define RF24_DEBUG(x,...)
|
||||
#define RF24_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
// PA levels
|
||||
@@ -113,8 +114,8 @@
|
||||
#define RF24_250KBPS (2)
|
||||
|
||||
// CRC
|
||||
#define RF24_CRC_DISABLED (0)
|
||||
#define RF24_CRC_8 (2)
|
||||
#define RF24_CRC_DISABLED (0)
|
||||
#define RF24_CRC_8 (2)
|
||||
#define RF24_CRC_16 (3)
|
||||
|
||||
// ARD, auto retry delay
|
||||
@@ -232,9 +233,10 @@
|
||||
|
||||
// functions
|
||||
|
||||
LOCAL void RF24_csn(const bool level);
|
||||
LOCAL void RF24_ce(const bool level);
|
||||
LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len, const bool aReadMode);
|
||||
LOCAL void RF24_csn(const bool level);
|
||||
LOCAL void RF24_ce(const bool level);
|
||||
LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len,
|
||||
const bool aReadMode);
|
||||
LOCAL uint8_t RF24_spiByteTransfer(const uint8_t cmd);
|
||||
LOCAL uint8_t RF24_RAW_readByteRegister(const uint8_t cmd);
|
||||
LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, const uint8_t value);
|
||||
@@ -250,11 +252,11 @@ LOCAL uint8_t RF24_getFIFOStatus(void);
|
||||
LOCAL void RF24_openWritingPipe(uint8_t recipient);
|
||||
LOCAL void RF24_startListening(void);
|
||||
LOCAL void RF24_stopListening(void);
|
||||
LOCAL void RF24_powerDown(void);
|
||||
LOCAL void RF24_powerDown(void);
|
||||
LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len);
|
||||
LOCAL uint8_t RF24_getDynamicPayloadSize(void);
|
||||
LOCAL bool RF24_isDataAvailable();
|
||||
LOCAL uint8_t RF24_readMessage(void* buf);
|
||||
LOCAL uint8_t RF24_readMessage(void* buf);
|
||||
LOCAL void RF24_setNodeAddress(const uint8_t address);
|
||||
LOCAL uint8_t RF24_getNodeID(void);
|
||||
LOCAL bool RF24_sanityCheck(void);
|
||||
@@ -275,14 +277,14 @@ LOCAL void RF24_setStatus(const uint8_t status);
|
||||
LOCAL void RF24_enableFeatures(void);
|
||||
|
||||
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
|
||||
typedef void (*RF24_receiveCallbackType)(void);
|
||||
/**
|
||||
* Register a callback, which will be called (from interrupt context) for every message received.
|
||||
* @note When a callback is registered, it _must_ retrieve the message from the nRF24
|
||||
* by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted
|
||||
* and message reception will stop.
|
||||
*/
|
||||
LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb);
|
||||
typedef void (*RF24_receiveCallbackType)(void);
|
||||
/**
|
||||
* Register a callback, which will be called (from interrupt context) for every message received.
|
||||
* @note When a callback is registered, it _must_ retrieve the message from the nRF24
|
||||
* by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted
|
||||
* and message reception will stop.
|
||||
*/
|
||||
LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb);
|
||||
#endif
|
||||
|
||||
#endif // __RF24_H__
|
||||
+610
-587
File diff suppressed because it is too large
Load Diff
+108
-91
@@ -6,23 +6,23 @@
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
@@ -37,20 +37,20 @@
|
||||
|
||||
// INT0 on AVRs should be connected to RFM69's DIO0 (ex on ATmega328 it's D2, on ATmega644/1284 it's D2)
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 0
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 0
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 2
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 2
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define RF69_IRQ_PIN 3
|
||||
#define RF69_IRQ_NUM 0
|
||||
#define RF69_IRQ_PIN 3
|
||||
#define RF69_IRQ_NUM 0
|
||||
#elif defined(__arm__)//Use pin 10 or any pin you want
|
||||
#define RF69_IRQ_PIN 10
|
||||
#define RF69_IRQ_NUM 10
|
||||
#else
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 0
|
||||
#define RF69_IRQ_PIN 10
|
||||
#define RF69_IRQ_NUM 10
|
||||
#else
|
||||
#define RF69_IRQ_PIN 2
|
||||
#define RF69_IRQ_NUM 0
|
||||
#endif
|
||||
|
||||
|
||||
@@ -79,79 +79,96 @@
|
||||
#define RFM69_CTL_REQACK 0x40
|
||||
|
||||
/** RFM69 class */
|
||||
class RFM69 {
|
||||
public:
|
||||
static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; //!< recv/xmit buf, including hdr & crc bytes
|
||||
static volatile uint8_t DATALEN; //!< DATALEN
|
||||
static volatile uint8_t SENDERID; //!< SENDERID
|
||||
static volatile uint8_t TARGETID; //!< should match _address
|
||||
static volatile uint8_t PAYLOADLEN; //!< PAYLOADLEN
|
||||
static volatile uint8_t ACK_REQUESTED; //!< ACK_REQUESTED
|
||||
static volatile uint8_t ACK_RECEIVED; //!< Should be polled immediately after sending a packet with ACK requestwith ACK request
|
||||
static volatile int16_t RSSI; //!< most accurate RSSI during reception (closest to the reception)
|
||||
static volatile uint8_t _mode; //!< should be protected?
|
||||
class RFM69
|
||||
{
|
||||
public:
|
||||
static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; //!< recv/xmit buf, including hdr & crc bytes
|
||||
static volatile uint8_t DATALEN; //!< DATALEN
|
||||
static volatile uint8_t SENDERID; //!< SENDERID
|
||||
static volatile uint8_t TARGETID; //!< should match _address
|
||||
static volatile uint8_t PAYLOADLEN; //!< PAYLOADLEN
|
||||
static volatile uint8_t ACK_REQUESTED; //!< ACK_REQUESTED
|
||||
static volatile uint8_t
|
||||
ACK_RECEIVED; //!< Should be polled immediately after sending a packet with ACK requestwith ACK request
|
||||
static volatile int16_t RSSI; //!< most accurate RSSI during reception (closest to the reception)
|
||||
static volatile uint8_t _mode; //!< should be protected?
|
||||
|
||||
RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM) { //!< Constructor
|
||||
_slaveSelectPin = slaveSelectPin;
|
||||
_interruptPin = interruptPin;
|
||||
_interruptNum = interruptNum;
|
||||
_mode = RF69_MODE_STANDBY;
|
||||
_promiscuousMode = false;
|
||||
_powerLevel = 31;
|
||||
_isRFM69HW = isRFM69HW;
|
||||
}
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param slaveSelectPin ChipSelect pin.
|
||||
* @param interruptPin Interrupt pin.
|
||||
* @param isRFM69HW Set to @c true to indicate RFM69HW variant.
|
||||
* @param interruptNum Interrupt number.
|
||||
*/
|
||||
RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false,
|
||||
uint8_t interruptNum=RF69_IRQ_NUM)
|
||||
{
|
||||
_slaveSelectPin = slaveSelectPin;
|
||||
_interruptPin = interruptPin;
|
||||
_interruptNum = interruptNum;
|
||||
_mode = RF69_MODE_STANDBY;
|
||||
_promiscuousMode = false;
|
||||
_powerLevel = 31;
|
||||
_isRFM69HW = isRFM69HW;
|
||||
}
|
||||
|
||||
bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); //!< initialize
|
||||
void setAddress(uint8_t addr); //!< setAddress
|
||||
void setNetwork(uint8_t networkID); //!< setNetwork
|
||||
bool canSend(); //!< canSend
|
||||
virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK=false); //!< send
|
||||
virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); //!< sendWithRetry (40ms roundtrip req for 61byte packets)
|
||||
virtual bool receiveDone(); //!< receiveDone
|
||||
bool ACKReceived(uint8_t fromNodeID); //!< ACKReceived
|
||||
bool ACKRequested(); //!< ACKRequested
|
||||
virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); //!< sendACK
|
||||
uint32_t getFrequency(); //!< getFrequency
|
||||
void setFrequency(uint32_t freqHz); //!< setFrequency
|
||||
void encrypt(const char* key); //!< encrypt
|
||||
void setCS(uint8_t newSPISlaveSelect); //!< setCS
|
||||
int16_t readRSSI(bool forceTrigger=false); //!< readRSSI
|
||||
void promiscuous(bool onOff=true); //!< promiscuous
|
||||
virtual void setHighPower(bool onOFF=true); //!< setHighPower (have to call it after initialize for RFM69HW)
|
||||
virtual void setPowerLevel(uint8_t level); //!< setPowerLevel (reduce/increase transmit power level)
|
||||
void sleep(); //!< sleep
|
||||
uint8_t readTemperature(uint8_t calFactor=0); //!< readTemperature (get CMOS temperature (8bit))
|
||||
void rcCalibration(); //!< rcCalibration (calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy])
|
||||
bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); //!< initialize
|
||||
void setAddress(uint8_t addr); //!< setAddress
|
||||
void setNetwork(uint8_t networkID); //!< setNetwork
|
||||
bool canSend(); //!< canSend
|
||||
virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize,
|
||||
bool requestACK=false); //!< send
|
||||
virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize,
|
||||
uint8_t retries=2, uint8_t retryWaitTime=
|
||||
40); //!< sendWithRetry (40ms roundtrip req for 61byte packets)
|
||||
virtual bool receiveDone(); //!< receiveDone
|
||||
bool ACKReceived(uint8_t fromNodeID); //!< ACKReceived
|
||||
bool ACKRequested(); //!< ACKRequested
|
||||
virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); //!< sendACK
|
||||
uint32_t getFrequency(); //!< getFrequency
|
||||
void setFrequency(uint32_t freqHz); //!< setFrequency
|
||||
void encrypt(const char* key); //!< encrypt
|
||||
void setCS(uint8_t newSPISlaveSelect); //!< setCS
|
||||
int16_t readRSSI(bool forceTrigger=false); //!< readRSSI
|
||||
void promiscuous(bool onOff=true); //!< promiscuous
|
||||
virtual void setHighPower(bool onOFF=
|
||||
true); //!< setHighPower (have to call it after initialize for RFM69HW)
|
||||
virtual void setPowerLevel(uint8_t level); //!< setPowerLevel (reduce/increase transmit power level)
|
||||
void sleep(); //!< sleep
|
||||
uint8_t readTemperature(uint8_t calFactor=0); //!< readTemperature (get CMOS temperature (8bit))
|
||||
void rcCalibration(); //!< rcCalibration (calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy])
|
||||
|
||||
// allow hacking registers by making these public
|
||||
uint8_t readReg(uint8_t addr); //!< readReg
|
||||
void writeReg(uint8_t addr, uint8_t val); //!< writeReg
|
||||
void readAllRegs(); //!< readAllRegs
|
||||
// allow hacking registers by making these public
|
||||
uint8_t readReg(uint8_t addr); //!< readReg
|
||||
void writeReg(uint8_t addr, uint8_t val); //!< writeReg
|
||||
void readAllRegs(); //!< readAllRegs
|
||||
|
||||
protected:
|
||||
static void isr0(); //!< isr0
|
||||
void virtual interruptHandler(); //!< interruptHandler
|
||||
virtual void interruptHook(uint8_t CTLbyte); //!< interruptHook
|
||||
virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false); //!< sendFrame
|
||||
protected:
|
||||
static void isr0(); //!< isr0
|
||||
void virtual interruptHandler(); //!< interruptHandler
|
||||
virtual void interruptHook(uint8_t CTLbyte); //!< interruptHook
|
||||
virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false,
|
||||
bool sendACK=false); //!< sendFrame
|
||||
|
||||
static RFM69* selfPointer; //!< selfPointer
|
||||
uint8_t _slaveSelectPin; //!< _slaveSelectPin
|
||||
uint8_t _interruptPin; //!< _interruptPin
|
||||
uint8_t _interruptNum; //!< _interruptNum
|
||||
uint8_t _address; //!< _address
|
||||
bool _promiscuousMode; //!< _promiscuousMode
|
||||
uint8_t _powerLevel; //!< _powerLevel
|
||||
bool _isRFM69HW; //!< _isRFM69HW
|
||||
static RFM69* selfPointer; //!< selfPointer
|
||||
uint8_t _slaveSelectPin; //!< _slaveSelectPin
|
||||
uint8_t _interruptPin; //!< _interruptPin
|
||||
uint8_t _interruptNum; //!< _interruptNum
|
||||
uint8_t _address; //!< _address
|
||||
bool _promiscuousMode; //!< _promiscuousMode
|
||||
uint8_t _powerLevel; //!< _powerLevel
|
||||
bool _isRFM69HW; //!< _isRFM69HW
|
||||
#if defined (SPCR) && defined (SPSR)
|
||||
uint8_t _SPCR; //!< _SPCR
|
||||
uint8_t _SPSR; //!< _SPSR
|
||||
uint8_t _SPCR; //!< _SPCR
|
||||
uint8_t _SPSR; //!< _SPSR
|
||||
#endif
|
||||
|
||||
virtual void receiveBegin(); //!< receiveBegin
|
||||
virtual void setMode(uint8_t mode); //!< setMode
|
||||
virtual void setHighPowerRegs(bool onOff); //!< setHighPowerRegs
|
||||
virtual void select(); //!< select
|
||||
virtual void unselect(); //!< unselect
|
||||
virtual void receiveBegin(); //!< receiveBegin
|
||||
virtual void setMode(uint8_t mode); //!< setMode
|
||||
virtual void setHighPowerRegs(bool onOff); //!< setHighPowerRegs
|
||||
virtual void select(); //!< select
|
||||
virtual void unselect(); //!< unselect
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,25 +6,25 @@
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program; if not, write
|
||||
// to the Free Software Foundation, Inc.,
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program; if not, write
|
||||
// to the Free Software Foundation, Inc.,
|
||||
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.fsf.org/licenses/gpl.txt
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.fsf.org/licenses/gpl.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
// and copyright notices in any redistribution of this code
|
||||
|
||||
+125
-98
@@ -26,19 +26,24 @@
|
||||
|
||||
#if defined(LINUX_ARCH_RASPBERRYPI)
|
||||
uint8_t spi_rxbuff[32 + 1]; //SPI receive buffer (payload max 32 bytes, MYS protocol limitation)
|
||||
uint8_t spi_txbuff[32 + 1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command, MYS protocol limitation)
|
||||
uint8_t spi_txbuff[32 +
|
||||
1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command, MYS protocol limitation)
|
||||
#endif
|
||||
|
||||
LOCAL void RFM95_csn(const bool level) {
|
||||
LOCAL void RFM95_csn(const bool level)
|
||||
{
|
||||
hwDigitalWrite(MY_RFM95_SPI_CS, level);
|
||||
}
|
||||
|
||||
LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode) {
|
||||
LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len,
|
||||
const bool aReadMode)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t* current = buf;
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_SPI.beginTransaction(SPISettings(MY_RFM95_SPI_MAX_SPEED, MY_RFM95_SPI_DATA_ORDER, MY_RFM95_SPI_DATA_MODE));
|
||||
#endif
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_SPI.beginTransaction(SPISettings(MY_RFM95_SPI_MAX_SPEED, MY_RFM95_SPI_DATA_ORDER,
|
||||
MY_RFM95_SPI_DATA_MODE));
|
||||
#endif
|
||||
RFM95_csn(LOW);
|
||||
#if defined(LINUX_ARCH_RASPBERRYPI)
|
||||
uint8_t * prx = spi_rxbuff;
|
||||
@@ -49,8 +54,7 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_
|
||||
while (len--) {
|
||||
if (aReadMode) {
|
||||
*ptx++ = RF24_NOP;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
*ptx++ = *current++;
|
||||
}
|
||||
}
|
||||
@@ -58,16 +62,14 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_
|
||||
if (aReadMode) {
|
||||
if (size == 2) {
|
||||
status = *++prx; // result is 2nd byte of receive buffer
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
status = *prx++; // status is 1st byte of receive buffer
|
||||
// decrement before to skip status byte
|
||||
// decrement before to skip status byte
|
||||
while (--size) {
|
||||
*buf++ = *prx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
status = *prx; // status is 1st byte of receive buffer
|
||||
}
|
||||
#else
|
||||
@@ -78,24 +80,27 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_
|
||||
if (buf != NULL) {
|
||||
*current++ = status;
|
||||
}
|
||||
} else {
|
||||
status = _SPI.transfer(*current++);
|
||||
}
|
||||
else status = _SPI.transfer(*current++);
|
||||
}
|
||||
#endif
|
||||
RFM95_csn(HIGH);
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_SPI.endTransaction();
|
||||
#endif
|
||||
#if !defined(MY_SOFTSPI)
|
||||
_SPI.endTransaction();
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
// low level register access
|
||||
LOCAL uint8_t RFM95_RAW_readByteRegister(const uint8_t address) {
|
||||
LOCAL uint8_t RFM95_RAW_readByteRegister(const uint8_t address)
|
||||
{
|
||||
return RFM95_spiMultiByteTransfer(address, NULL, 1, true);
|
||||
}
|
||||
|
||||
// low level register access
|
||||
LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value) {
|
||||
LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value)
|
||||
{
|
||||
return RFM95_spiMultiByteTransfer(address, &value, 1, false);
|
||||
}
|
||||
|
||||
@@ -109,24 +114,25 @@ LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value)
|
||||
// check RegPktRssiValue (0x1A) vs. RegRssiValue (0x1B)
|
||||
|
||||
|
||||
LOCAL bool RFM95_initialise(const float frequency) {
|
||||
LOCAL bool RFM95_initialise(const float frequency)
|
||||
{
|
||||
RFM95_DEBUG(PSTR("RFM95:INIT\n"));
|
||||
// reset radio module if rst pin defined
|
||||
#if defined(MY_RFM95_RST_PIN)
|
||||
hwPinMode(MY_RFM95_RST_PIN, OUTPUT);
|
||||
hwDigitalWrite(MY_RFM95_RST_PIN, HIGH);
|
||||
// 100uS
|
||||
delayMicroseconds(100);
|
||||
hwDigitalWrite(MY_RFM95_RST_PIN, LOW);
|
||||
// wait until chip ready
|
||||
delay(5);
|
||||
#endif
|
||||
#if defined(MY_RFM95_RST_PIN)
|
||||
hwPinMode(MY_RFM95_RST_PIN, OUTPUT);
|
||||
hwDigitalWrite(MY_RFM95_RST_PIN, HIGH);
|
||||
// 100uS
|
||||
delayMicroseconds(100);
|
||||
hwDigitalWrite(MY_RFM95_RST_PIN, LOW);
|
||||
// wait until chip ready
|
||||
delay(5);
|
||||
#endif
|
||||
|
||||
// set variables
|
||||
RFM95.address = RFM95_BROADCAST_ADDRESS;
|
||||
RFM95.rxBufferValid = false;
|
||||
RFM95.txSequenceNumber = 0; // initialise TX sequence counter
|
||||
RFM95.powerLevel = 0;
|
||||
RFM95.powerLevel = 0;
|
||||
RFM95.ATCenabled = false;
|
||||
RFM95.ATCtargetRSSI = RFM95_TARGET_RSSI + RFM95_RSSI_OFFSET;
|
||||
|
||||
@@ -158,23 +164,24 @@ LOCAL bool RFM95_initialise(const float frequency) {
|
||||
|
||||
// IRQ
|
||||
hwPinMode(MY_RFM95_IRQ_PIN, INPUT);
|
||||
#if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266)
|
||||
_SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN));
|
||||
#endif
|
||||
#if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266)
|
||||
_SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN));
|
||||
#endif
|
||||
attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// RxDone, TxDone, CADDone is mapped to DI0
|
||||
LOCAL void RFM95_interruptHandler(void) {
|
||||
LOCAL void RFM95_interruptHandler(void)
|
||||
{
|
||||
// Read the interrupt register
|
||||
const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS);
|
||||
if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) {
|
||||
const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS);
|
||||
if (RFM95.radioMode == RFM95_RADIO_MODE_RX &&
|
||||
(irqFlags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) {
|
||||
// CRC error or timeout
|
||||
// RXcontinuous mode: radio stays in RX mode, clearing IRQ needed
|
||||
}
|
||||
else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) {
|
||||
} else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) {
|
||||
// set radio to STDBY (we are in RXcontinuous mode)
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
|
||||
// Have received a packet
|
||||
@@ -188,44 +195,46 @@ LOCAL void RFM95_interruptHandler(void) {
|
||||
RFM95.currentPacket.SNR = static_cast<rfm95_SNR_t>(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE));
|
||||
RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN;
|
||||
// Message for us
|
||||
if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) &&
|
||||
(RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address || RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) {
|
||||
if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) &&
|
||||
(RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address ||
|
||||
RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) {
|
||||
RFM95.rxBufferValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) {
|
||||
|
||||
} else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) {
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
|
||||
}
|
||||
else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) {
|
||||
} else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) {
|
||||
RFM95.cad = irqFlags & RFM95_CAD_DETECTED;
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all IRQ flags
|
||||
RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xFF);
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_available(void) {
|
||||
LOCAL bool RFM95_available(void)
|
||||
{
|
||||
if (RFM95.radioMode == RFM95_RADIO_MODE_TX) {
|
||||
return false;
|
||||
}
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX);
|
||||
return RFM95.rxBufferValid;
|
||||
return RFM95.rxBufferValid;
|
||||
}
|
||||
|
||||
LOCAL void RFM95_clearRxBuffer(void) {
|
||||
LOCAL void RFM95_clearRxBuffer(void)
|
||||
{
|
||||
noInterrupts();
|
||||
RFM95.rxBufferValid = false;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
LOCAL uint8_t RFM95_recv(uint8_t* buf) {
|
||||
LOCAL uint8_t RFM95_recv(uint8_t* buf)
|
||||
{
|
||||
if (!RFM95_available()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// atomic
|
||||
noInterrupts();
|
||||
const uint8_t payloadLen = RFM95.currentPacket.payloadLen;
|
||||
@@ -234,10 +243,10 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf) {
|
||||
const uint8_t controlFlags = RFM95.currentPacket.header.controlFlags;
|
||||
const rfm95_RSSI_t RSSI = RFM95.currentPacket.RSSI; // of incoming packet
|
||||
const rfm95_SNR_t SNR = RFM95.currentPacket.SNR;
|
||||
if (buf != NULL) {
|
||||
if (buf != NULL) {
|
||||
memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen);
|
||||
RFM95.rxBufferValid = false;
|
||||
}
|
||||
}
|
||||
interrupts();
|
||||
|
||||
// ACK handling
|
||||
@@ -249,29 +258,32 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf) {
|
||||
return payloadLen;
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_send(rfm95_packet_t &packet) {
|
||||
LOCAL bool RFM95_send(rfm95_packet_t &packet)
|
||||
{
|
||||
const uint8_t finalLen = packet.payloadLen + RFM95_HEADER_LEN;
|
||||
// Make sure we dont interrupt an outgoing message
|
||||
RFM95_waitPacketSent();
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY);
|
||||
|
||||
|
||||
// Check channel activity
|
||||
if (!RFM95_waitCAD()) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
packet.header.sequenceNumber = RFM95.txSequenceNumber++;
|
||||
// Position at the beginning of the TX FIFO
|
||||
packet.header.sequenceNumber = RFM95.txSequenceNumber++;
|
||||
// Position at the beginning of the TX FIFO
|
||||
RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_TX_FIFO_ADDR);
|
||||
// write packet
|
||||
// write packet
|
||||
RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet.data, finalLen);
|
||||
// total payload length
|
||||
// total payload length
|
||||
RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen);
|
||||
// send message, if sent, irq fires and radio returns to standby
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_TX);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, const rfm95_flag_t flags) {
|
||||
LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len,
|
||||
const rfm95_flag_t flags)
|
||||
{
|
||||
rfm95_packet_t packet;
|
||||
packet.header.version = RFM95_PACKET_HEADER_VERSION;
|
||||
packet.header.sender = RFM95.address;
|
||||
@@ -283,14 +295,16 @@ LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t
|
||||
return RFM95_send(packet);
|
||||
}
|
||||
|
||||
LOCAL void RFM95_setFrequency(const float centre) {
|
||||
const uint32_t freq = (centre * 1000000.0) / RFM95_FSTEP;
|
||||
LOCAL void RFM95_setFrequency(const float centre)
|
||||
{
|
||||
const uint32_t freq = (centre * 1000000.0) / RFM95_FSTEP;
|
||||
RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freq >> 16) & 0xff);
|
||||
RFM95_writeReg(RFM95_REG_07_FRF_MID, (freq >> 8) & 0xff);
|
||||
RFM95_writeReg(RFM95_REG_08_FRF_LSB, freq & 0xff);
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_setTxPower(uint8_t powerLevel) {
|
||||
LOCAL bool RFM95_setTxPower(uint8_t powerLevel)
|
||||
{
|
||||
// RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST
|
||||
powerLevel = max((uint8_t)RFM95_MIN_POWER_LEVEL_DBM, powerLevel);
|
||||
powerLevel = min((uint8_t)RFM95_MAX_POWER_LEVEL_DBM, powerLevel);
|
||||
@@ -304,8 +318,7 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) {
|
||||
// My measurements show 20dBm is correct
|
||||
RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE);
|
||||
val = powerLevel - 8;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE);
|
||||
val = powerLevel - 5;
|
||||
}
|
||||
@@ -318,27 +331,32 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) {
|
||||
}
|
||||
|
||||
// Sets registers from a canned modem configuration structure
|
||||
LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config) {
|
||||
LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config)
|
||||
{
|
||||
RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config.reg_1d);
|
||||
RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config.reg_1e);
|
||||
RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config.reg_26);
|
||||
}
|
||||
|
||||
LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength) {
|
||||
LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength)
|
||||
{
|
||||
RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, preambleLength >> 8);
|
||||
RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, preambleLength & 0xff);
|
||||
}
|
||||
|
||||
LOCAL void RFM95_setAddress(const uint8_t addr) {
|
||||
LOCAL void RFM95_setAddress(const uint8_t addr)
|
||||
{
|
||||
RFM95.address = addr;
|
||||
}
|
||||
|
||||
LOCAL uint8_t RFM95_getAddress(void) {
|
||||
LOCAL uint8_t RFM95_getAddress(void)
|
||||
{
|
||||
return RFM95.address;
|
||||
}
|
||||
|
||||
|
||||
LOCAL bool RFM95_isChannelActive(void) {
|
||||
LOCAL bool RFM95_isChannelActive(void)
|
||||
{
|
||||
(void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD);
|
||||
while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) {
|
||||
doYield();
|
||||
@@ -347,7 +365,8 @@ LOCAL bool RFM95_isChannelActive(void) {
|
||||
return RFM95.cad;
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) {
|
||||
LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode)
|
||||
{
|
||||
if (RFM95.radioMode == newRadioMode) {
|
||||
return false;
|
||||
}
|
||||
@@ -355,35 +374,35 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) {
|
||||
|
||||
if (newRadioMode == RFM95_RADIO_MODE_STDBY) {
|
||||
regMode = RFM95_MODE_STDBY;
|
||||
}
|
||||
else if (newRadioMode == RFM95_RADIO_MODE_SLEEP) {
|
||||
} else if (newRadioMode == RFM95_RADIO_MODE_SLEEP) {
|
||||
regMode = RFM95_MODE_SLEEP;
|
||||
}
|
||||
else if (newRadioMode == RFM95_RADIO_MODE_CAD) {
|
||||
} else if (newRadioMode == RFM95_RADIO_MODE_CAD) {
|
||||
regMode = RFM95_MODE_CAD;
|
||||
RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone, DIO0
|
||||
}
|
||||
else if (newRadioMode == RFM95_RADIO_MODE_RX) {
|
||||
} else if (newRadioMode == RFM95_RADIO_MODE_RX) {
|
||||
regMode = RFM95_MODE_RXCONTINUOUS;
|
||||
RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0
|
||||
}
|
||||
else if (newRadioMode == RFM95_RADIO_MODE_TX) {
|
||||
} else if (newRadioMode == RFM95_RADIO_MODE_TX) {
|
||||
regMode = RFM95_MODE_TX;
|
||||
RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
else return false;
|
||||
RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode);
|
||||
|
||||
RFM95.radioMode = newRadioMode;
|
||||
return true;
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_sleep(void) {
|
||||
LOCAL bool RFM95_sleep(void)
|
||||
{
|
||||
return RFM95_setRadioMode(RFM95_RADIO_MODE_SLEEP);
|
||||
}
|
||||
|
||||
// should be called immediately after reception in case sender wants ACK
|
||||
LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR) {
|
||||
LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber,
|
||||
const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR)
|
||||
{
|
||||
RFM95_DEBUG(PSTR("RFM95:SAC:SEND ACK to=%d,RSSI=%d\n"),recipient,RSSI);
|
||||
rfm95_ack_t ACK;
|
||||
ACK.sequenceNumber = sequenceNumber;
|
||||
@@ -395,25 +414,26 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s
|
||||
(void)RFM95_sendFrame(recipient, (uint8_t*)&ACK, sizeof(rfm95_ack_t), flags);
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI) {
|
||||
LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI)
|
||||
{
|
||||
// allow +-5%
|
||||
if (currentRSSI < (targetRSSI*1.05) && RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) {
|
||||
// increase transmitter power
|
||||
RFM95.powerLevel++;
|
||||
}
|
||||
else if (currentRSSI > (targetRSSI*0.95) && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) {
|
||||
} else if (currentRSSI > (targetRSSI*0.95) && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) {
|
||||
// decrease transmitter power
|
||||
RFM95.powerLevel--;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// nothing to adjust
|
||||
return false;
|
||||
}
|
||||
RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), currentRSSI - RFM95_RSSI_OFFSET, targetRSSI - RFM95_RSSI_OFFSET, RFM95.powerLevel);
|
||||
RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), currentRSSI - RFM95_RSSI_OFFSET,
|
||||
targetRSSI - RFM95_RSSI_OFFSET, RFM95.powerLevel);
|
||||
return RFM95_setTxPower(RFM95.powerLevel);;
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime)
|
||||
LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
|
||||
const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime)
|
||||
{
|
||||
for (uint8_t retry = 0; retry < retries; retry++) {
|
||||
RFM95_DEBUG(PSTR("RFM95:SWR:SEND TO=%d,RETRY=%d\n"), recipient, retry);
|
||||
@@ -431,10 +451,12 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons
|
||||
const uint8_t sender = RFM95.currentPacket.header.sender;
|
||||
const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber;
|
||||
const rfm95_flag_t flag = RFM95.currentPacket.header.controlFlags;
|
||||
if (sender == recipient && RFM95_getACKReceived(flag) && (ACKsequenceNumber == RFM95.txSequenceNumber - 1)) {
|
||||
RFM95_DEBUG(PSTR("RFM95:SWR:ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d\n"),sender,ACKsequenceNumber, RFM95.currentPacket.ACK.RSSI-RFM95_RSSI_OFFSET, (int8_t)RFM95.currentPacket.ACK.SNR / 4);
|
||||
if (sender == recipient && RFM95_getACKReceived(flag) &&
|
||||
(ACKsequenceNumber == RFM95.txSequenceNumber - 1)) {
|
||||
RFM95_DEBUG(PSTR("RFM95:SWR:ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d\n"),sender,ACKsequenceNumber,
|
||||
RFM95.currentPacket.ACK.RSSI-RFM95_RSSI_OFFSET, (int8_t)RFM95.currentPacket.ACK.SNR / 4);
|
||||
RFM95_clearRxBuffer();
|
||||
|
||||
|
||||
// ATC
|
||||
if (RFM95.ATCenabled && RFM95_getACKRSSIReport(flag)) {
|
||||
(void)RFM95_executeATC(RFM95.currentPacket.ACK.RSSI, RFM95.ATCtargetRSSI);
|
||||
@@ -455,7 +477,8 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons
|
||||
|
||||
|
||||
// Wait until no channel activity detected or timeout
|
||||
LOCAL bool RFM95_waitCAD(void) {
|
||||
LOCAL bool RFM95_waitCAD(void)
|
||||
{
|
||||
const uint32_t enterMS = hwMillis();
|
||||
while (RFM95_isChannelActive()) {
|
||||
if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) {
|
||||
@@ -467,23 +490,27 @@ LOCAL bool RFM95_waitCAD(void) {
|
||||
}
|
||||
|
||||
// Wait for any previous transmission to finish
|
||||
LOCAL bool RFM95_waitPacketSent(void) {
|
||||
LOCAL bool RFM95_waitPacketSent(void)
|
||||
{
|
||||
while (RFM95.radioMode == RFM95_RADIO_MODE_TX) {
|
||||
doYield();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
LOCAL int16_t RFM95_getRSSI(void) {
|
||||
LOCAL int16_t RFM95_getRSSI(void)
|
||||
{
|
||||
return (int16_t)(RFM95.currentPacket.RSSI - RFM95_RSSI_OFFSET);
|
||||
}
|
||||
|
||||
LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) {
|
||||
LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI)
|
||||
{
|
||||
RFM95.ATCenabled = OnOff;
|
||||
RFM95.ATCtargetRSSI = (uint8_t)(targetRSSI + RFM95_RSSI_OFFSET);
|
||||
}
|
||||
|
||||
LOCAL bool RFM95_sanityCheck(void) {
|
||||
LOCAL bool RFM95_sanityCheck(void)
|
||||
{
|
||||
// not implemented yet
|
||||
return true;
|
||||
}
|
||||
|
||||
+81
-76
@@ -23,73 +23,73 @@
|
||||
* Changelog:
|
||||
* - ACK with sequenceNumber
|
||||
* - ATC control
|
||||
*
|
||||
*
|
||||
* Definitions for HopeRF LoRa radios:
|
||||
* http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
|
||||
* http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file RFM95.h
|
||||
*
|
||||
* @defgroup RFM95grp RFM95
|
||||
* @ingroup internals
|
||||
* @{
|
||||
*
|
||||
* RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
|
||||
* - [!] Exclamation mark is prepended in case of error
|
||||
*
|
||||
* This section is WIP!
|
||||
*
|
||||
* |E| SYS | SUB | Message | Comment
|
||||
* |-|-------|----------|-----------------------------------|---------------------------------------------------------------------
|
||||
* | | RFM95 | INIT | | Initialise RFM95 radio
|
||||
* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back
|
||||
* | | RFM95 | PTC | LEVEL=%d | Set TX power level
|
||||
* | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI)
|
||||
* | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL)
|
||||
* | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY)
|
||||
* | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR)
|
||||
* |!| RFM95 | SWR | NACK | No ACK received
|
||||
/**
|
||||
* @file RFM95.h
|
||||
*
|
||||
* @defgroup RFM95grp RFM95
|
||||
* @ingroup internals
|
||||
* @{
|
||||
*
|
||||
* RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
|
||||
* - [!] Exclamation mark is prepended in case of error
|
||||
*
|
||||
* This section is WIP!
|
||||
*
|
||||
* |E| SYS | SUB | Message | Comment
|
||||
* |-|-------|----------|-----------------------------------|---------------------------------------------------------------------
|
||||
* | | RFM95 | INIT | | Initialise RFM95 radio
|
||||
* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back
|
||||
* | | RFM95 | PTC | LEVEL=%d | Set TX power level
|
||||
* | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI)
|
||||
* | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL)
|
||||
* | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY)
|
||||
* | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR)
|
||||
* |!| RFM95 | SWR | NACK | No ACK received
|
||||
|
||||
*
|
||||
*
|
||||
* RFM95 modem configuration
|
||||
*
|
||||
* BW = Bandwidth in kHz
|
||||
* CR = Error correction code
|
||||
* SF = Spreading factor, chips / symbol
|
||||
*
|
||||
* | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment
|
||||
* |------------------|--------|--------|--------|-------|-----|------|-----------------------------
|
||||
* | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range
|
||||
* | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range
|
||||
* | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range
|
||||
* | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range
|
||||
*
|
||||
* @brief API declaration for RFM95
|
||||
*
|
||||
*/
|
||||
*
|
||||
*
|
||||
* RFM95 modem configuration
|
||||
*
|
||||
* BW = Bandwidth in kHz
|
||||
* CR = Error correction code
|
||||
* SF = Spreading factor, chips / symbol
|
||||
*
|
||||
* | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment
|
||||
* |------------------|--------|--------|--------|-------|-----|------|-----------------------------
|
||||
* | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range
|
||||
* | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range
|
||||
* | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range
|
||||
* | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range
|
||||
*
|
||||
* @brief API declaration for RFM95
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RFM95_h
|
||||
#define _RFM95_h
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RFM95_IRQ_PIN (2)
|
||||
#define RFM95_RST_PIN (9)
|
||||
#define RFM95_IRQ_PIN (2)
|
||||
#define RFM95_RST_PIN (9)
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
#define RFM95_IRQ_PIN (2)
|
||||
#define RFM95_RST_PIN (9)
|
||||
#define RFM95_IRQ_PIN (2)
|
||||
#define RFM95_RST_PIN (9)
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define RFM95_IRQ_PIN (3)
|
||||
#define RFM95_RST_PIN (9)
|
||||
#define RFM95_IRQ_PIN (3)
|
||||
#define RFM95_RST_PIN (9)
|
||||
#elif defined(__arm__)
|
||||
#define RFM95_IRQ_PIN (10)
|
||||
#define RFM95_RST_PIN (27)
|
||||
#else
|
||||
#define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN
|
||||
#define RFM95_RST_PIN (9) //!< RFM95_IRQ_PIN
|
||||
#define RFM95_IRQ_PIN (10)
|
||||
#define RFM95_RST_PIN (27)
|
||||
#else
|
||||
#define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN
|
||||
#define RFM95_RST_PIN (9) //!< RFM95_IRQ_PIN
|
||||
#endif
|
||||
|
||||
// SPI settings
|
||||
@@ -97,36 +97,37 @@
|
||||
|
||||
|
||||
#if !defined(MY_RFM95_SPI_MAX_SPEED)
|
||||
#define MY_RFM95_SPI_MAX_SPEED 4000000 //!< SPI speed
|
||||
#define MY_RFM95_SPI_MAX_SPEED 4000000 //!< SPI speed
|
||||
#endif
|
||||
#define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order
|
||||
#define MY_RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode
|
||||
|
||||
|
||||
#if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI)
|
||||
#include <SPI.h>
|
||||
#if defined(MY_SOFTSPI)
|
||||
SoftSPI<MY_SOFT_SPI_MISO_PIN, MY_SOFT_SPI_MOSI_PIN, MY_SOFT_SPI_SCK_PIN, MY_RF24_SPI_DATA_MODE> _SPI;
|
||||
#else
|
||||
#define _SPI SPI
|
||||
#endif
|
||||
#include <SPI.h>
|
||||
#if defined(MY_SOFTSPI)
|
||||
SoftSPI<MY_SOFT_SPI_MISO_PIN, MY_SOFT_SPI_MOSI_PIN, MY_SOFT_SPI_SCK_PIN, MY_RF24_SPI_DATA_MODE>
|
||||
_SPI;
|
||||
#else
|
||||
#if defined(__arm__)
|
||||
#include <SPI.h>
|
||||
#else
|
||||
extern HardwareSPI SPI; //!< SPI
|
||||
#endif
|
||||
|
||||
#if !defined(_SPI)
|
||||
#define _SPI SPI //!< SPI
|
||||
#endif
|
||||
#define _SPI SPI
|
||||
#endif
|
||||
#else
|
||||
#if defined(__arm__)
|
||||
#include <SPI.h>
|
||||
#else
|
||||
extern HardwareSPI SPI; //!< SPI
|
||||
#endif
|
||||
|
||||
// debug
|
||||
#if !defined(_SPI)
|
||||
#define _SPI SPI //!< SPI
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// debug
|
||||
#if defined(MY_DEBUG_VERBOSE_RFM95)
|
||||
#define RFM95_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< Debug print
|
||||
#define RFM95_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< Debug print
|
||||
#else
|
||||
#define RFM95_DEBUG(x,...) //!< Debug null
|
||||
#define RFM95_DEBUG(x,...) //!< Debug null
|
||||
#endif
|
||||
|
||||
#define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold
|
||||
@@ -247,7 +248,7 @@ typedef struct {
|
||||
uint8_t payloadLen; //!< Length of payload (excluding header)
|
||||
rfm95_RSSI_t RSSI; //!< RSSI of current packet, RSSI = value - 137
|
||||
rfm95_SNR_t SNR; //!< SNR of current packet
|
||||
} __attribute__((packed)) rfm95_packet_t;
|
||||
} __attribute__((packed)) rfm95_packet_t;
|
||||
|
||||
|
||||
/**
|
||||
@@ -316,7 +317,8 @@ LOCAL bool RFM95_send(rfm95_packet_t &packet);
|
||||
* @param flags
|
||||
* @return True if frame sent
|
||||
*/
|
||||
LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, const rfm95_flag_t flags);
|
||||
LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len,
|
||||
const rfm95_flag_t flags);
|
||||
/**
|
||||
* @brief RFM95_setPreambleLength
|
||||
* @param preambleLength
|
||||
@@ -350,7 +352,8 @@ LOCAL bool RFM95_isChannelActive(void);
|
||||
* @param RSSI (rfm95_RSSI_t)
|
||||
* @param SNR (rfm95_RSSI_t)
|
||||
*/
|
||||
LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR);
|
||||
LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber,
|
||||
const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR);
|
||||
/**
|
||||
* @brief RFM95_sendWithRetry
|
||||
* @param recipient
|
||||
@@ -360,7 +363,9 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s
|
||||
* @param retryWaitTime
|
||||
* @return True if packet successfully sent
|
||||
*/
|
||||
LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES, const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS);
|
||||
LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer,
|
||||
const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES,
|
||||
const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS);
|
||||
/**
|
||||
* @brief RFM95_waitCAD
|
||||
* @return True if no channel activity detected
|
||||
@@ -476,7 +481,7 @@ volatile rfm95_internal_t RFM95; //!< internal variables
|
||||
#define RFM95_MODE_RXSINGLE 0x06 //!< MODE_RXSINGLE
|
||||
#define RFM95_MODE_CAD 0x07 //!< MODE_CAD
|
||||
|
||||
// RFM95_REG_09_PA_CONFIG 0x09
|
||||
// RFM95_REG_09_PA_CONFIG 0x09
|
||||
#define RFM95_OUTPUT_POWER 0x0F //!< OUTPUT_POWER
|
||||
#define RFM95_MAX_POWER 0x70 //!< MAX_POWER
|
||||
#define RFM95_PA_SELECT 0x80 //!< PA_SELECT
|
||||
|
||||
+24
-15
@@ -31,11 +31,13 @@ SPIClass SPI = SPIClass();
|
||||
|
||||
uint8_t SPIClass::initialized = 0;
|
||||
|
||||
uint8_t SPIClass::is_initialized() {
|
||||
uint8_t SPIClass::is_initialized()
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void SPIClass::begin() {
|
||||
void SPIClass::begin()
|
||||
{
|
||||
if (!initialized) {
|
||||
if (!bcm2835_spi_begin()) {
|
||||
logError("You need root privilege to use SPI.\n");
|
||||
@@ -46,7 +48,8 @@ void SPIClass::begin() {
|
||||
initialized++; // reference count
|
||||
}
|
||||
|
||||
void SPIClass::end() {
|
||||
void SPIClass::end()
|
||||
{
|
||||
if (initialized) {
|
||||
initialized--;
|
||||
}
|
||||
@@ -57,47 +60,53 @@ void SPIClass::end() {
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::setBitOrder(uint8_t bit_order) {
|
||||
void SPIClass::setBitOrder(uint8_t bit_order)
|
||||
{
|
||||
bcm2835_spi_setBitOrder(bit_order);
|
||||
}
|
||||
|
||||
void SPIClass::setDataMode(uint8_t data_mode) {
|
||||
void SPIClass::setDataMode(uint8_t data_mode)
|
||||
{
|
||||
bcm2835_spi_setDataMode(data_mode);
|
||||
}
|
||||
|
||||
void SPIClass::setClockDivider(uint16_t divider) {
|
||||
void SPIClass::setClockDivider(uint16_t divider)
|
||||
{
|
||||
bcm2835_spi_setClockDivider(divider);
|
||||
}
|
||||
|
||||
void SPIClass::chipSelect(int csn_pin) {
|
||||
void SPIClass::chipSelect(int csn_pin)
|
||||
{
|
||||
if (csn_pin == RPI_GPIO_P1_26) {
|
||||
csn_pin = BCM2835_SPI_CS1;
|
||||
}
|
||||
else if (csn_pin == RPI_GPIO_P1_24) {
|
||||
} else if (csn_pin == RPI_GPIO_P1_24) {
|
||||
csn_pin = BCM2835_SPI_CS0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
csn_pin = BCM2835_SPI_CS0;
|
||||
}
|
||||
bcm2835_spi_chipSelect(csn_pin);
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
|
||||
void SPIClass::beginTransaction(SPISettings settings) {
|
||||
void SPIClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
setBitOrder(settings.border);
|
||||
setDataMode(settings.dmode);
|
||||
setClockDivider(settings.cdiv);
|
||||
}
|
||||
|
||||
void SPIClass::endTransaction() {
|
||||
void SPIClass::endTransaction()
|
||||
{
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIClass::usingInterrupt(uint8_t interruptNumber) {
|
||||
void SPIClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
|
||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber) {
|
||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
|
||||
+38
-30
@@ -45,7 +45,8 @@
|
||||
/**
|
||||
* SPISettings class
|
||||
*/
|
||||
class SPISettings {
|
||||
class SPISettings
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -53,7 +54,8 @@ public:
|
||||
*
|
||||
* Default clock speed is 8Mhz.
|
||||
*/
|
||||
SPISettings() {
|
||||
SPISettings()
|
||||
{
|
||||
init(BCM2835_SPI_CLOCK_DIVIDER_32, BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_SPI_MODE0);
|
||||
}
|
||||
/**
|
||||
@@ -63,31 +65,32 @@ public:
|
||||
* @param bitOrder SPI bit order.
|
||||
* @param dataMode SPI data mode.
|
||||
*/
|
||||
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
|
||||
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
|
||||
{
|
||||
uint16_t divider;
|
||||
|
||||
switch (clock) {
|
||||
case 500000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_512;
|
||||
break;
|
||||
case 1000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_256;
|
||||
break;
|
||||
case 2000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_128;
|
||||
break;
|
||||
case 4000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_64;
|
||||
break;
|
||||
case 8000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_32;
|
||||
break;
|
||||
case 16000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_16;
|
||||
break;
|
||||
default:
|
||||
// 8Mhz
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_32;
|
||||
case 500000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_512;
|
||||
break;
|
||||
case 1000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_256;
|
||||
break;
|
||||
case 2000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_128;
|
||||
break;
|
||||
case 4000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_64;
|
||||
break;
|
||||
case 8000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_32;
|
||||
break;
|
||||
case 16000000:
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_16;
|
||||
break;
|
||||
default:
|
||||
// 8Mhz
|
||||
divider = BCM2835_SPI_CLOCK_DIVIDER_32;
|
||||
}
|
||||
|
||||
init(divider, bitOrder, dataMode);
|
||||
@@ -105,7 +108,8 @@ private:
|
||||
* @param bitOrder SPI bit order.
|
||||
* @param dataMode SPI data mode.
|
||||
*/
|
||||
void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode) {
|
||||
void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode)
|
||||
{
|
||||
cdiv = divider;
|
||||
border = bitOrder;
|
||||
dmode = dataMode;
|
||||
@@ -117,7 +121,8 @@ private:
|
||||
/**
|
||||
* SPIClass class
|
||||
*/
|
||||
class SPIClass {
|
||||
class SPIClass
|
||||
{
|
||||
|
||||
private:
|
||||
static uint8_t initialized; //!< @brief SPI initialized flag.
|
||||
@@ -150,7 +155,7 @@ public:
|
||||
* @param buf Buffer to read from and write to.
|
||||
* @param len Buffer length.
|
||||
*/
|
||||
inline static void transfern(char* buf, uint32_t len);
|
||||
inline static void transfern(char* buf, uint32_t len);
|
||||
/**
|
||||
* @brief Start SPI operations.
|
||||
*/
|
||||
@@ -207,15 +212,18 @@ public:
|
||||
static void notUsingInterrupt(uint8_t interruptNumber);
|
||||
};
|
||||
|
||||
uint8_t SPIClass::transfer(uint8_t data) {
|
||||
uint8_t SPIClass::transfer(uint8_t data)
|
||||
{
|
||||
return bcm2835_spi_transfer(data);
|
||||
}
|
||||
|
||||
void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len) {
|
||||
void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
|
||||
{
|
||||
bcm2835_spi_transfernb( tbuf, rbuf, len);
|
||||
}
|
||||
|
||||
void SPIClass::transfern(char* buf, uint32_t len) {
|
||||
void SPIClass::transfern(char* buf, uint32_t len)
|
||||
{
|
||||
transfernb(buf, buf, len);
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ size_t TwoWire::write(uint8_t data)
|
||||
// put byte in tx buffer
|
||||
txBuffer[txBufferIndex] = data;
|
||||
++txBufferIndex;
|
||||
// update amount in buffer
|
||||
// update amount in buffer
|
||||
txBufferLength = txBufferIndex;
|
||||
|
||||
return 1;
|
||||
|
||||
+18
-5
@@ -31,7 +31,8 @@
|
||||
|
||||
#define BUFFER_LENGTH 32
|
||||
|
||||
class TwoWire : public Stream {
|
||||
class TwoWire : public Stream
|
||||
{
|
||||
|
||||
private:
|
||||
static uint8_t rxBuffer[];
|
||||
@@ -67,10 +68,22 @@ public:
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
inline size_t write(unsigned long n) { return write((uint8_t)n); }
|
||||
inline size_t write(long n) { return write((uint8_t)n); }
|
||||
inline size_t write(unsigned int n) { return write((uint8_t)n); }
|
||||
inline size_t write(int n) { return write((uint8_t)n); }
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
using Print::write;
|
||||
};
|
||||
|
||||
|
||||
+892
-917
File diff suppressed because it is too large
Load Diff
+898
-909
File diff suppressed because it is too large
Load Diff
+220
-155
@@ -27,167 +27,232 @@ SOFTWARE.
|
||||
|
||||
int get_rpi_info(rpi_info *info)
|
||||
{
|
||||
FILE *fp;
|
||||
char buffer[1024];
|
||||
char hardware[1024];
|
||||
char revision[1024];
|
||||
char *rev;
|
||||
int found = 0;
|
||||
int len;
|
||||
FILE *fp;
|
||||
char buffer[1024];
|
||||
char hardware[1024];
|
||||
char revision[1024];
|
||||
char *rev;
|
||||
int found = 0;
|
||||
int len;
|
||||
|
||||
if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
|
||||
return -1;
|
||||
while(!feof(fp)) {
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
sscanf(buffer, "Hardware : %s", hardware);
|
||||
if (strcmp(hardware, "BCM2708") == 0 ||
|
||||
strcmp(hardware, "BCM2709") == 0 ||
|
||||
strcmp(hardware, "BCM2835") == 0 ||
|
||||
strcmp(hardware, "BCM2836") == 0 ||
|
||||
strcmp(hardware, "BCM2837") == 0 ) {
|
||||
found = 1;
|
||||
}
|
||||
sscanf(buffer, "Revision : %s", revision);
|
||||
}
|
||||
fclose(fp);
|
||||
if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
while(!feof(fp)) {
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
sscanf(buffer, "Hardware : %s", hardware);
|
||||
if (strcmp(hardware, "BCM2708") == 0 ||
|
||||
strcmp(hardware, "BCM2709") == 0 ||
|
||||
strcmp(hardware, "BCM2835") == 0 ||
|
||||
strcmp(hardware, "BCM2836") == 0 ||
|
||||
strcmp(hardware, "BCM2837") == 0 ) {
|
||||
found = 1;
|
||||
}
|
||||
sscanf(buffer, "Revision : %s", revision);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (!found)
|
||||
return -1;
|
||||
if (!found) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((len = strlen(revision)) == 0)
|
||||
return -1;
|
||||
if ((len = strlen(revision)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len >= 6 && strtol((char[]){revision[len-6],0}, NULL, 16) & 8) {
|
||||
// new scheme
|
||||
//info->rev = revision[len-1]-'0';
|
||||
strcpy(info->revision, revision);
|
||||
switch (revision[len-2]) {
|
||||
case '0': info->type = "Model A"; info->p1_revision = 2; break;
|
||||
case '1': info->type = "Model B"; info->p1_revision = 2; break;
|
||||
case '2': info->type = "Model A+"; info->p1_revision = 3; break;
|
||||
case '3': info->type = "Model B+"; info->p1_revision = 3; break;
|
||||
case '4': info->type = "Pi 2 Model B"; info->p1_revision = 3; break;
|
||||
case '5': info->type = "Alpha"; info->p1_revision = 3; break;
|
||||
case '6': info->type = "Compute"; info->p1_revision = 0; break;
|
||||
case '8': info->type = "Pi 3 Model B"; info->p1_revision = 3; break;
|
||||
case '9': info->type = "Zero"; info->p1_revision = 3; break;
|
||||
default : info->type = "Unknown"; info->p1_revision = 3; break;
|
||||
}
|
||||
switch (revision[len-4]) {
|
||||
case '0': info->processor = "BCM2835"; break;
|
||||
case '1': info->processor = "BCM2836"; break;
|
||||
case '2': info->processor = "BCM2837"; break;
|
||||
default : info->processor = "Unknown"; break;
|
||||
}
|
||||
switch (revision[len-5]) {
|
||||
case '0': info->manufacturer = "Sony"; break;
|
||||
case '1': info->manufacturer = "Egoman"; break;
|
||||
case '2': info->manufacturer = "Embest"; break;
|
||||
case '4': info->manufacturer = "Embest"; break;
|
||||
default : info->manufacturer = "Unknown"; break;
|
||||
}
|
||||
switch (strtol((char[]){revision[len-6],0}, NULL, 16) & 7) {
|
||||
case 0: info->ram = "256M"; break;
|
||||
case 1: info->ram = "512M"; break;
|
||||
case 2: info->ram = "1024M"; break;
|
||||
default: info->ram = "Unknown"; break;
|
||||
}
|
||||
} else {
|
||||
// old scheme
|
||||
info->ram = "Unknown";
|
||||
info->manufacturer = "Unknown";
|
||||
info->processor = "Unknown";
|
||||
info->type = "Unknown";
|
||||
strcpy(info->revision, revision);
|
||||
if (len >= 6 && strtol((char[]) {
|
||||
revision[len-6],0
|
||||
}, NULL, 16) & 8) {
|
||||
// new scheme
|
||||
//info->rev = revision[len-1]-'0';
|
||||
strcpy(info->revision, revision);
|
||||
switch (revision[len-2]) {
|
||||
case '0':
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
break;
|
||||
case '1':
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
break;
|
||||
case '2':
|
||||
info->type = "Model A+";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
case '3':
|
||||
info->type = "Model B+";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
case '4':
|
||||
info->type = "Pi 2 Model B";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
case '5':
|
||||
info->type = "Alpha";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
case '6':
|
||||
info->type = "Compute";
|
||||
info->p1_revision = 0;
|
||||
break;
|
||||
case '8':
|
||||
info->type = "Pi 3 Model B";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
case '9':
|
||||
info->type = "Zero";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
default :
|
||||
info->type = "Unknown";
|
||||
info->p1_revision = 3;
|
||||
break;
|
||||
}
|
||||
switch (revision[len-4]) {
|
||||
case '0':
|
||||
info->processor = "BCM2835";
|
||||
break;
|
||||
case '1':
|
||||
info->processor = "BCM2836";
|
||||
break;
|
||||
case '2':
|
||||
info->processor = "BCM2837";
|
||||
break;
|
||||
default :
|
||||
info->processor = "Unknown";
|
||||
break;
|
||||
}
|
||||
switch (revision[len-5]) {
|
||||
case '0':
|
||||
info->manufacturer = "Sony";
|
||||
break;
|
||||
case '1':
|
||||
info->manufacturer = "Egoman";
|
||||
break;
|
||||
case '2':
|
||||
info->manufacturer = "Embest";
|
||||
break;
|
||||
case '4':
|
||||
info->manufacturer = "Embest";
|
||||
break;
|
||||
default :
|
||||
info->manufacturer = "Unknown";
|
||||
break;
|
||||
}
|
||||
switch (strtol((char[]) {
|
||||
revision[len-6],0
|
||||
}, NULL, 16) & 7) {
|
||||
case 0:
|
||||
info->ram = "256M";
|
||||
break;
|
||||
case 1:
|
||||
info->ram = "512M";
|
||||
break;
|
||||
case 2:
|
||||
info->ram = "1024M";
|
||||
break;
|
||||
default:
|
||||
info->ram = "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// old scheme
|
||||
info->ram = "Unknown";
|
||||
info->manufacturer = "Unknown";
|
||||
info->processor = "Unknown";
|
||||
info->type = "Unknown";
|
||||
strcpy(info->revision, revision);
|
||||
|
||||
// get last four characters (ignore preceeding 1000 for overvolt)
|
||||
if (len > 4)
|
||||
rev = (char *)&revision+len-4;
|
||||
else
|
||||
rev = revision;
|
||||
// get last four characters (ignore preceeding 1000 for overvolt)
|
||||
if (len > 4) {
|
||||
rev = (char *)&revision+len-4;
|
||||
} else {
|
||||
rev = revision;
|
||||
}
|
||||
|
||||
if ((strcmp(rev, "0002") == 0) ||
|
||||
(strcmp(rev, "0003") == 0)) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 1;
|
||||
info->ram = "256M";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0004") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Sony";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0005") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Qisda";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0006") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Egoman";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0007") == 0) {
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Egoman";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0008") == 0) {
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Sony";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0009") == 0) {
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Qisda";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "000d") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "512M";
|
||||
info->manufacturer = "Egoman";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "000e") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "512M";
|
||||
info->manufacturer = "Sony";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "000f") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "512M";
|
||||
info->manufacturer = "Qisda";
|
||||
info->processor = "BCM2835";
|
||||
} else if ((strcmp(rev, "0011") == 0) ||
|
||||
(strcmp(rev, "0014") == 0)) {
|
||||
info->type = "Compute Module";
|
||||
info->p1_revision = 0;
|
||||
info->ram = "512M";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0012") == 0) {
|
||||
info->type = "Model A+";
|
||||
info->p1_revision = 3;
|
||||
info->ram = "256M";
|
||||
info->processor = "BCM2835";
|
||||
} else if ((strcmp(rev, "0010") == 0) ||
|
||||
(strcmp(rev, "0013") == 0)) {
|
||||
info->type = "Model B+";
|
||||
info->p1_revision = 3;
|
||||
info->ram = "512M";
|
||||
info->processor = "BCM2835";
|
||||
} else { // don't know - assume revision 3 p1 connector
|
||||
info->p1_revision = 3;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if ((strcmp(rev, "0002") == 0) ||
|
||||
(strcmp(rev, "0003") == 0)) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 1;
|
||||
info->ram = "256M";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0004") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Sony";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0005") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Qisda";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0006") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Egoman";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0007") == 0) {
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Egoman";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0008") == 0) {
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Sony";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0009") == 0) {
|
||||
info->type = "Model A";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "256M";
|
||||
info->manufacturer = "Qisda";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "000d") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "512M";
|
||||
info->manufacturer = "Egoman";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "000e") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "512M";
|
||||
info->manufacturer = "Sony";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "000f") == 0) {
|
||||
info->type = "Model B";
|
||||
info->p1_revision = 2;
|
||||
info->ram = "512M";
|
||||
info->manufacturer = "Qisda";
|
||||
info->processor = "BCM2835";
|
||||
} else if ((strcmp(rev, "0011") == 0) ||
|
||||
(strcmp(rev, "0014") == 0)) {
|
||||
info->type = "Compute Module";
|
||||
info->p1_revision = 0;
|
||||
info->ram = "512M";
|
||||
info->processor = "BCM2835";
|
||||
} else if (strcmp(rev, "0012") == 0) {
|
||||
info->type = "Model A+";
|
||||
info->p1_revision = 3;
|
||||
info->ram = "256M";
|
||||
info->processor = "BCM2835";
|
||||
} else if ((strcmp(rev, "0010") == 0) ||
|
||||
(strcmp(rev, "0013") == 0)) {
|
||||
info->type = "Model B+";
|
||||
info->p1_revision = 3;
|
||||
info->ram = "512M";
|
||||
info->processor = "BCM2835";
|
||||
} else { // don't know - assume revision 3 p1 connector
|
||||
info->p1_revision = 3;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -28,14 +28,13 @@ SOFTWARE.
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int p1_revision;
|
||||
char *ram;
|
||||
char *manufacturer;
|
||||
char *processor;
|
||||
char *type;
|
||||
char revision[1024];
|
||||
typedef struct {
|
||||
int p1_revision;
|
||||
char *ram;
|
||||
char *manufacturer;
|
||||
char *processor;
|
||||
char *type;
|
||||
char revision[1024];
|
||||
} rpi_info;
|
||||
|
||||
int get_rpi_info(rpi_info *info);
|
||||
|
||||
@@ -35,14 +35,15 @@
|
||||
|
||||
int piHiPri (const int pri)
|
||||
{
|
||||
struct sched_param sched ;
|
||||
struct sched_param sched ;
|
||||
|
||||
memset (&sched, 0, sizeof(sched)) ;
|
||||
memset (&sched, 0, sizeof(sched)) ;
|
||||
|
||||
if (pri > sched_get_priority_max (SCHED_RR))
|
||||
sched.sched_priority = sched_get_priority_max (SCHED_RR) ;
|
||||
else
|
||||
sched.sched_priority = pri ;
|
||||
if (pri > sched_get_priority_max (SCHED_RR)) {
|
||||
sched.sched_priority = sched_get_priority_max (SCHED_RR) ;
|
||||
} else {
|
||||
sched.sched_priority = pri ;
|
||||
}
|
||||
|
||||
return sched_setscheduler (0, SCHED_RR, &sched) ;
|
||||
return sched_setscheduler (0, SCHED_RR, &sched) ;
|
||||
}
|
||||
|
||||
+43
-25
@@ -55,8 +55,7 @@ static pthread_t *threadIds[64] = {NULL};
|
||||
|
||||
// sysFds:
|
||||
// Map a file descriptor from the /sys/class/gpio/gpioX/value
|
||||
static int sysFds[64] =
|
||||
{
|
||||
static int sysFds[64] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
@@ -82,7 +81,7 @@ int get_gpio_number(uint8_t physPin, uint8_t *gpio)
|
||||
}
|
||||
|
||||
if ((rpiinfo.p1_revision != 3 && physPin > 26)
|
||||
|| (rpiinfo.p1_revision == 3 && physPin > 40)) {
|
||||
|| (rpiinfo.p1_revision == 3 && physPin > 40)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -95,7 +94,8 @@ int get_gpio_number(uint8_t physPin, uint8_t *gpio)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *interruptHandler(void *args) {
|
||||
void *interruptHandler(void *args)
|
||||
{
|
||||
int fd, ret;
|
||||
struct pollfd polls;
|
||||
char c;
|
||||
@@ -126,7 +126,7 @@ void *interruptHandler(void *args) {
|
||||
// A one character read appars to be enough.
|
||||
// Followed by a seek to reset it.
|
||||
(void)read (fd, &c, 1) ;
|
||||
lseek (fd, 0, SEEK_SET) ;
|
||||
lseek (fd, 0, SEEK_SET) ;
|
||||
// Call user function.
|
||||
pthread_mutex_lock(&intMutex);
|
||||
if (interruptsEnabled) {
|
||||
@@ -142,7 +142,8 @@ void *interruptHandler(void *args) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rpi_util::pinMode(uint8_t physPin, uint8_t mode) {
|
||||
void rpi_util::pinMode(uint8_t physPin, uint8_t mode)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
@@ -158,7 +159,8 @@ void rpi_util::pinMode(uint8_t physPin, uint8_t mode) {
|
||||
}
|
||||
}
|
||||
|
||||
void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) {
|
||||
void rpi_util::digitalWrite(uint8_t physPin, uint8_t value)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
@@ -178,7 +180,8 @@ void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rpi_util::digitalRead(uint8_t physPin) {
|
||||
uint8_t rpi_util::digitalRead(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
@@ -194,7 +197,8 @@ uint8_t rpi_util::digitalRead(uint8_t physPin) {
|
||||
}
|
||||
}
|
||||
|
||||
void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) {
|
||||
void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode)
|
||||
{
|
||||
FILE *fd;
|
||||
char fName[40];
|
||||
char c;
|
||||
@@ -220,7 +224,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) {
|
||||
logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fd, "%d\n", gpioPin);
|
||||
fprintf(fd, "%d\n", gpioPin);
|
||||
fclose(fd);
|
||||
|
||||
// Wait a bit the system to create /sys/class/gpio/gpio<GPIO number>
|
||||
@@ -228,7 +232,8 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) {
|
||||
|
||||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ;
|
||||
if ((fd = fopen (fName, "w")) == NULL) {
|
||||
fprintf (stderr, "attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", physPin, strerror(errno));
|
||||
fprintf (stderr, "attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n",
|
||||
physPin, strerror(errno));
|
||||
exit(1) ;
|
||||
}
|
||||
fprintf(fd, "in\n") ;
|
||||
@@ -236,18 +241,27 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) {
|
||||
|
||||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/edge", gpioPin) ;
|
||||
if ((fd = fopen(fName, "w")) == NULL) {
|
||||
fprintf (stderr, "attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", physPin, strerror(errno));
|
||||
fprintf (stderr, "attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", physPin,
|
||||
strerror(errno));
|
||||
exit(1) ;
|
||||
}
|
||||
switch (mode) {
|
||||
case CHANGE: fprintf(fd, "both\n"); break;
|
||||
case FALLING: fprintf(fd, "falling\n"); break;
|
||||
case RISING: fprintf(fd, "rising\n"); break;
|
||||
case NONE: fprintf(fd, "none\n"); break;
|
||||
default:
|
||||
logError("attachInterrupt: Invalid mode\n");
|
||||
fclose(fd);
|
||||
return;
|
||||
case CHANGE:
|
||||
fprintf(fd, "both\n");
|
||||
break;
|
||||
case FALLING:
|
||||
fprintf(fd, "falling\n");
|
||||
break;
|
||||
case RISING:
|
||||
fprintf(fd, "rising\n");
|
||||
break;
|
||||
case NONE:
|
||||
fprintf(fd, "none\n");
|
||||
break;
|
||||
default:
|
||||
logError("attachInterrupt: Invalid mode\n");
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
@@ -275,7 +289,8 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) {
|
||||
pthread_create(threadIds[gpioPin], NULL, interruptHandler, (void *)threadArgs);
|
||||
}
|
||||
|
||||
void rpi_util::detachInterrupt(uint8_t physPin) {
|
||||
void rpi_util::detachInterrupt(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (get_gpio_number(physPin, &gpioPin)) {
|
||||
@@ -301,22 +316,25 @@ void rpi_util::detachInterrupt(uint8_t physPin) {
|
||||
logError("Unable to unexport pin %d for interrupt\n", gpioPin);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fp, "%d", gpioPin);
|
||||
fprintf(fp, "%d", gpioPin);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
uint8_t rpi_util::digitalPinToInterrupt(uint8_t physPin) {
|
||||
uint8_t rpi_util::digitalPinToInterrupt(uint8_t physPin)
|
||||
{
|
||||
// No need to convert the pin to gpio, we do it in attachInterrupt().
|
||||
return physPin;
|
||||
}
|
||||
|
||||
void rpi_util::interrupts() {
|
||||
void rpi_util::interrupts()
|
||||
{
|
||||
pthread_mutex_lock(&intMutex);
|
||||
interruptsEnabled = true;
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
|
||||
void rpi_util::noInterrupts() {
|
||||
void rpi_util::noInterrupts()
|
||||
{
|
||||
pthread_mutex_lock(&intMutex);
|
||||
interruptsEnabled = false;
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
|
||||
@@ -29,7 +29,8 @@ const int pin_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 1
|
||||
const int pin_to_gpio_rev2[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
const int pin_to_gpio_rev3[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21 };
|
||||
|
||||
namespace rpi_util {
|
||||
namespace rpi_util
|
||||
{
|
||||
|
||||
typedef enum {
|
||||
LSBFIRST = BCM2835_SPI_BIT_ORDER_LSBFIRST,
|
||||
|
||||
+201
-188
@@ -47,46 +47,50 @@ uint8_t SPIFlash::UNIQUEID[8];
|
||||
/// get this from the datasheet of your flash chip
|
||||
/// Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf)
|
||||
/// Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf)
|
||||
SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) {
|
||||
_slaveSelectPin = slaveSelectPin;
|
||||
_jedecID = jedecID;
|
||||
SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID)
|
||||
{
|
||||
_slaveSelectPin = slaveSelectPin;
|
||||
_jedecID = jedecID;
|
||||
}
|
||||
|
||||
/// Select the flash chip
|
||||
void SPIFlash::select() {
|
||||
//save current SPI settings
|
||||
void SPIFlash::select()
|
||||
{
|
||||
//save current SPI settings
|
||||
#ifndef SPI_HAS_TRANSACTION
|
||||
noInterrupts();
|
||||
noInterrupts();
|
||||
#endif
|
||||
#ifndef ESP8266
|
||||
_SPCR = SPCR;
|
||||
_SPSR = SPSR;
|
||||
_SPCR = SPCR;
|
||||
_SPSR = SPSR;
|
||||
#endif
|
||||
|
||||
#ifdef SPI_HAS_TRANSACTION
|
||||
SPI.beginTransaction(_settings);
|
||||
SPI.beginTransaction(_settings);
|
||||
#else
|
||||
// set FLASH SPI settings
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present
|
||||
SPI.begin();
|
||||
// set FLASH SPI settings
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setClockDivider(
|
||||
SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present
|
||||
SPI.begin();
|
||||
#endif
|
||||
hwDigitalWrite(_slaveSelectPin, LOW);
|
||||
hwDigitalWrite(_slaveSelectPin, LOW);
|
||||
}
|
||||
|
||||
/// UNselect the flash chip
|
||||
void SPIFlash::unselect() {
|
||||
hwDigitalWrite(_slaveSelectPin, HIGH);
|
||||
//restore SPI settings to what they were before talking to the FLASH chip
|
||||
void SPIFlash::unselect()
|
||||
{
|
||||
hwDigitalWrite(_slaveSelectPin, HIGH);
|
||||
//restore SPI settings to what they were before talking to the FLASH chip
|
||||
#ifdef SPI_HAS_TRANSACTION
|
||||
SPI.endTransaction();
|
||||
SPI.endTransaction();
|
||||
#else
|
||||
interrupts();
|
||||
interrupts();
|
||||
#endif
|
||||
#ifndef ESP8266
|
||||
SPCR = _SPCR;
|
||||
SPSR = _SPSR;
|
||||
SPCR = _SPCR;
|
||||
SPSR = _SPSR;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -94,39 +98,39 @@ void SPIFlash::unselect() {
|
||||
boolean SPIFlash::initialize()
|
||||
{
|
||||
#ifndef ESP8266
|
||||
_SPCR = SPCR;
|
||||
_SPSR = SPSR;
|
||||
_SPCR = SPCR;
|
||||
_SPSR = SPSR;
|
||||
#endif
|
||||
hwPinMode(_slaveSelectPin, OUTPUT);
|
||||
hwPinMode(_slaveSelectPin, OUTPUT);
|
||||
#ifdef SPI_HAS_TRANSACTION
|
||||
_settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
_settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
#endif
|
||||
|
||||
unselect();
|
||||
wakeup();
|
||||
unselect();
|
||||
wakeup();
|
||||
|
||||
if (_jedecID == 0 || readDeviceId() == _jedecID) {
|
||||
command(SPIFLASH_STATUSWRITE, true); // Write Status Register
|
||||
SPI.transfer(0); // Global Unprotect
|
||||
unselect();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (_jedecID == 0 || readDeviceId() == _jedecID) {
|
||||
command(SPIFLASH_STATUSWRITE, true); // Write Status Register
|
||||
SPI.transfer(0); // Global Unprotect
|
||||
unselect();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Get the manufacturer and device ID bytes (as a short word)
|
||||
uint16_t SPIFlash::readDeviceId()
|
||||
{
|
||||
#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
|
||||
command(SPIFLASH_IDREAD); // Read JEDEC ID
|
||||
command(SPIFLASH_IDREAD); // Read JEDEC ID
|
||||
#else
|
||||
select();
|
||||
SPI.transfer(SPIFLASH_IDREAD);
|
||||
select();
|
||||
SPI.transfer(SPIFLASH_IDREAD);
|
||||
#endif
|
||||
uint16_t jedecid = SPI.transfer(0) << 8;
|
||||
jedecid |= SPI.transfer(0);
|
||||
unselect();
|
||||
return jedecid;
|
||||
uint16_t jedecid = SPI.transfer(0) << 8;
|
||||
jedecid |= SPI.transfer(0);
|
||||
unselect();
|
||||
return jedecid;
|
||||
}
|
||||
|
||||
/// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize
|
||||
@@ -137,97 +141,100 @@ uint16_t SPIFlash::readDeviceId()
|
||||
/// flash.readUniqueId(); uint8_t* MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
|
||||
uint8_t* SPIFlash::readUniqueId()
|
||||
{
|
||||
command(SPIFLASH_MACREAD);
|
||||
SPI.transfer(0);
|
||||
SPI.transfer(0);
|
||||
SPI.transfer(0);
|
||||
SPI.transfer(0);
|
||||
for (uint8_t i=0;i<8;i++) {
|
||||
UNIQUEID[i] = SPI.transfer(0);
|
||||
}
|
||||
unselect();
|
||||
return UNIQUEID;
|
||||
command(SPIFLASH_MACREAD);
|
||||
SPI.transfer(0);
|
||||
SPI.transfer(0);
|
||||
SPI.transfer(0);
|
||||
SPI.transfer(0);
|
||||
for (uint8_t i=0; i<8; i++) {
|
||||
UNIQUEID[i] = SPI.transfer(0);
|
||||
}
|
||||
unselect();
|
||||
return UNIQUEID;
|
||||
}
|
||||
|
||||
/// read 1 byte from flash memory
|
||||
uint8_t SPIFlash::readByte(uint32_t addr) {
|
||||
command(SPIFLASH_ARRAYREADLOWFREQ);
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
uint8_t result = SPI.transfer(0);
|
||||
unselect();
|
||||
return result;
|
||||
uint8_t SPIFlash::readByte(uint32_t addr)
|
||||
{
|
||||
command(SPIFLASH_ARRAYREADLOWFREQ);
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
uint8_t result = SPI.transfer(0);
|
||||
unselect();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// read unlimited # of bytes
|
||||
void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) {
|
||||
command(SPIFLASH_ARRAYREAD);
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
SPI.transfer(0); //"dont care"
|
||||
for (uint16_t i = 0; i < len; ++i) {
|
||||
((uint8_t*) buf)[i] = SPI.transfer(0);
|
||||
}
|
||||
unselect();
|
||||
void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len)
|
||||
{
|
||||
command(SPIFLASH_ARRAYREAD);
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
SPI.transfer(0); //"dont care"
|
||||
for (uint16_t i = 0; i < len; ++i) {
|
||||
((uint8_t*) buf)[i] = SPI.transfer(0);
|
||||
}
|
||||
unselect();
|
||||
}
|
||||
|
||||
/// Send a command to the flash chip, pass TRUE for isWrite when its a write command
|
||||
void SPIFlash::command(uint8_t cmd, boolean isWrite){
|
||||
void SPIFlash::command(uint8_t cmd, boolean isWrite)
|
||||
{
|
||||
#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
|
||||
DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
|
||||
PORTB |= B00000001;
|
||||
DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
|
||||
PORTB |= B00000001;
|
||||
#endif
|
||||
if (isWrite)
|
||||
{
|
||||
command(SPIFLASH_WRITEENABLE); // Write Enable
|
||||
unselect();
|
||||
}
|
||||
//wait for any write/erase to complete
|
||||
// a time limit cannot really be added here without it being a very large safe limit
|
||||
// that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations
|
||||
// a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the
|
||||
// open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present
|
||||
while(busy());
|
||||
select();
|
||||
SPI.transfer(cmd);
|
||||
if (isWrite) {
|
||||
command(SPIFLASH_WRITEENABLE); // Write Enable
|
||||
unselect();
|
||||
}
|
||||
//wait for any write/erase to complete
|
||||
// a time limit cannot really be added here without it being a very large safe limit
|
||||
// that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations
|
||||
// a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the
|
||||
// open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present
|
||||
while(busy());
|
||||
select();
|
||||
SPI.transfer(cmd);
|
||||
}
|
||||
|
||||
/// check if the chip is busy erasing/writing
|
||||
boolean SPIFlash::busy()
|
||||
{
|
||||
/*
|
||||
select();
|
||||
SPI.transfer(SPIFLASH_STATUSREAD);
|
||||
uint8_t status = SPI.transfer(0);
|
||||
unselect();
|
||||
return status & 1;
|
||||
*/
|
||||
return readStatus() & 1;
|
||||
/*
|
||||
select();
|
||||
SPI.transfer(SPIFLASH_STATUSREAD);
|
||||
uint8_t status = SPI.transfer(0);
|
||||
unselect();
|
||||
return status & 1;
|
||||
*/
|
||||
return readStatus() & 1;
|
||||
}
|
||||
|
||||
/// return the STATUS register
|
||||
uint8_t SPIFlash::readStatus()
|
||||
{
|
||||
select();
|
||||
SPI.transfer(SPIFLASH_STATUSREAD);
|
||||
uint8_t status = SPI.transfer(0);
|
||||
unselect();
|
||||
return status;
|
||||
select();
|
||||
SPI.transfer(SPIFLASH_STATUSREAD);
|
||||
uint8_t status = SPI.transfer(0);
|
||||
unselect();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/// Write 1 byte to flash memory
|
||||
/// WARNING: you can only write to previously erased memory locations (see datasheet)
|
||||
/// use the block erase commands to first clear memory (write 0xFFs)
|
||||
void SPIFlash::writeByte(uint32_t addr, uint8_t byt) {
|
||||
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
SPI.transfer(byt);
|
||||
unselect();
|
||||
void SPIFlash::writeByte(uint32_t addr, uint8_t byt)
|
||||
{
|
||||
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
SPI.transfer(byt);
|
||||
unselect();
|
||||
}
|
||||
|
||||
/// write multiple bytes to flash memory (up to 64K)
|
||||
@@ -235,74 +242,74 @@ void SPIFlash::writeByte(uint32_t addr, uint8_t byt) {
|
||||
/// use the block erase commands to first clear memory (write 0xFFs)
|
||||
/// This version handles both page alignment and data blocks larger than 256 bytes.
|
||||
/// See documentation of #MY_SPIFLASH_SST25TYPE define for more information
|
||||
void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
|
||||
void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len)
|
||||
{
|
||||
#ifdef MY_SPIFLASH_SST25TYPE
|
||||
//SST25 Type of Flash does not support Page Programming but AAI Word Programming
|
||||
uint16_t i=0;
|
||||
uint8_t oddAdr=0;
|
||||
char s[5];
|
||||
//SST25 Type of Flash does not support Page Programming but AAI Word Programming
|
||||
uint16_t i=0;
|
||||
uint8_t oddAdr=0;
|
||||
char s[5];
|
||||
|
||||
command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
|
||||
if (addr%2){
|
||||
//start address is not even, i.e. first byte of word must be 0xff
|
||||
SPI.transfer(0xff);
|
||||
SPI.transfer(((uint8_t*) buf)[0]);
|
||||
unselect();
|
||||
oddAdr=1; //following addresses must all be shifted one off
|
||||
len--;
|
||||
if (len > 0) {
|
||||
command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command
|
||||
}
|
||||
}
|
||||
if (addr%2) {
|
||||
//start address is not even, i.e. first byte of word must be 0xff
|
||||
SPI.transfer(0xff);
|
||||
SPI.transfer(((uint8_t*) buf)[0]);
|
||||
unselect();
|
||||
oddAdr=1; //following addresses must all be shifted one off
|
||||
len--;
|
||||
if (len > 0) {
|
||||
command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<(len/2);i++){
|
||||
//AAI command must be set before every new word
|
||||
if (i>0) {
|
||||
command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before
|
||||
}
|
||||
SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
|
||||
SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]);
|
||||
unselect();
|
||||
}
|
||||
for (i=0; i<(len/2); i++) {
|
||||
//AAI command must be set before every new word
|
||||
if (i>0) {
|
||||
command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before
|
||||
}
|
||||
SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
|
||||
SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]);
|
||||
unselect();
|
||||
}
|
||||
|
||||
if (len-i*2 == 1){
|
||||
//There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd)
|
||||
if (i>0) {
|
||||
command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid
|
||||
}
|
||||
SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
|
||||
SPI.transfer(0xff);
|
||||
unselect();
|
||||
}
|
||||
if (len-i*2 == 1) {
|
||||
//There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd)
|
||||
if (i>0) {
|
||||
command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid
|
||||
}
|
||||
SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
|
||||
SPI.transfer(0xff);
|
||||
unselect();
|
||||
}
|
||||
|
||||
command(SPIFLASH_WRITEDISABLE); //end AAI programming
|
||||
unselect();
|
||||
command(SPIFLASH_WRITEDISABLE); //end AAI programming
|
||||
unselect();
|
||||
#else
|
||||
uint16_t n;
|
||||
uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
|
||||
uint16_t offset = 0;
|
||||
while (len>0)
|
||||
{
|
||||
n = (len<=maxBytes) ? len : maxBytes;
|
||||
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
uint16_t n;
|
||||
uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
|
||||
uint16_t offset = 0;
|
||||
while (len>0) {
|
||||
n = (len<=maxBytes) ? len : maxBytes;
|
||||
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
|
||||
for (uint16_t i = 0; i < n; i++) {
|
||||
SPI.transfer(((uint8_t*) buf)[offset + i]);
|
||||
}
|
||||
unselect();
|
||||
for (uint16_t i = 0; i < n; i++) {
|
||||
SPI.transfer(((uint8_t*) buf)[offset + i]);
|
||||
}
|
||||
unselect();
|
||||
|
||||
addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
|
||||
offset +=n;
|
||||
len -= n;
|
||||
maxBytes = 256; // now we can do up to 256 bytes per loop
|
||||
}
|
||||
addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
|
||||
offset +=n;
|
||||
len -= n;
|
||||
maxBytes = 256; // now we can do up to 256 bytes per loop
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -312,40 +319,46 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
|
||||
/// other things and later check if the chip is done with busy()
|
||||
/// note that any command will first wait for chip to become available using busy()
|
||||
/// so no need to do that twice
|
||||
void SPIFlash::chipErase() {
|
||||
command(SPIFLASH_CHIPERASE, true);
|
||||
unselect();
|
||||
void SPIFlash::chipErase()
|
||||
{
|
||||
command(SPIFLASH_CHIPERASE, true);
|
||||
unselect();
|
||||
}
|
||||
|
||||
/// erase a 4Kbyte block
|
||||
void SPIFlash::blockErase4K(uint32_t addr) {
|
||||
command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
unselect();
|
||||
void SPIFlash::blockErase4K(uint32_t addr)
|
||||
{
|
||||
command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
unselect();
|
||||
}
|
||||
|
||||
/// erase a 32Kbyte block
|
||||
void SPIFlash::blockErase32K(uint32_t addr) {
|
||||
command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
unselect();
|
||||
void SPIFlash::blockErase32K(uint32_t addr)
|
||||
{
|
||||
command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase
|
||||
SPI.transfer(addr >> 16);
|
||||
SPI.transfer(addr >> 8);
|
||||
SPI.transfer(addr);
|
||||
unselect();
|
||||
}
|
||||
|
||||
void SPIFlash::sleep() {
|
||||
command(SPIFLASH_SLEEP);
|
||||
unselect();
|
||||
void SPIFlash::sleep()
|
||||
{
|
||||
command(SPIFLASH_SLEEP);
|
||||
unselect();
|
||||
}
|
||||
|
||||
void SPIFlash::wakeup() {
|
||||
command(SPIFLASH_WAKE);
|
||||
unselect();
|
||||
void SPIFlash::wakeup()
|
||||
{
|
||||
command(SPIFLASH_WAKE);
|
||||
unselect();
|
||||
}
|
||||
|
||||
/// cleanup
|
||||
void SPIFlash::end() {
|
||||
SPI.end();
|
||||
void SPIFlash::end()
|
||||
{
|
||||
SPI.end();
|
||||
}
|
||||
|
||||
+56
-53
@@ -7,28 +7,28 @@
|
||||
// > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment.
|
||||
// > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
|
||||
// > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4
|
||||
// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02,
|
||||
// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02,
|
||||
// > use define MY_SPIFLASH_SST25TYPE for SST25 Type Flash Memory. Added / changed comments to better suit doxygen
|
||||
// **********************************************************************************
|
||||
// License
|
||||
// **********************************************************************************
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// This program is free software; you can redistribute it
|
||||
// and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software
|
||||
// Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General
|
||||
// Public License along with this program.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Licence can be viewed at
|
||||
//
|
||||
// Licence can be viewed at
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
//
|
||||
// Please maintain this license information along with authorship
|
||||
@@ -82,7 +82,7 @@
|
||||
#define SPIFLASH_BLOCKERASE_32K 0x52 //!< erase one 32K block of flash memory
|
||||
#define SPIFLASH_BLOCKERASE_64K 0xD8 //!< erase one 64K block of flash memory
|
||||
#define SPIFLASH_CHIPERASE 0x60 //!< @brief chip erase (may take several seconds depending on size)
|
||||
//!< Chip is erased but not actually waited for completion (instead need to check the status register BUSY bit)
|
||||
//!< Chip is erased but not actually waited for completion (instead need to check the status register BUSY bit)
|
||||
#define SPIFLASH_STATUSREAD 0x05 //!< read status register
|
||||
#define SPIFLASH_STATUSWRITE 0x01 //!< write status register
|
||||
#define SPIFLASH_ARRAYREAD 0x0B //!< read array (fast, need to add 1 dummy byte after 3 address bytes)
|
||||
@@ -92,13 +92,13 @@
|
||||
#define SPIFLASH_WAKE 0xAB //!< deep power wake up
|
||||
#define SPIFLASH_BYTEPAGEPROGRAM 0x02 //!< write (1 to 256bytes). Writing more than one Byte is not supported on all devices (e.g. SST25 Series)
|
||||
#define SPIFLASH_AAIWORDPROGRAM 0xAD //!< @brief Auto Address Increment Programming on Microchip SST Family Devices which do not support page program. <BR>
|
||||
//!< Use define #MY_SPIFLASH_SST25TYPE to use AAI prog instead of Bytepageprogram which does not work on SST Family Chips
|
||||
//!< tested with SST25PF020B80 http://ww1.microchip.com/downloads/en/DeviceDoc/20005135B.pdf
|
||||
//!< Use define #MY_SPIFLASH_SST25TYPE to use AAI prog instead of Bytepageprogram which does not work on SST Family Chips
|
||||
//!< tested with SST25PF020B80 http://ww1.microchip.com/downloads/en/DeviceDoc/20005135B.pdf
|
||||
#define SPIFLASH_IDREAD 0x9F //!< @brief read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device)
|
||||
//!< Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf)
|
||||
//!< Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf)
|
||||
//!< Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf)
|
||||
//!< Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf)
|
||||
#define SPIFLASH_MACREAD 0x4B //!< read unique ID number (MAC)
|
||||
|
||||
|
||||
///
|
||||
/// @def MY_SPIFLASH_SST25TYPE
|
||||
/// @brief If set AAI Word Programming is used to support SST25 Family SPI Flash.
|
||||
@@ -107,41 +107,44 @@
|
||||
/// If SPIFLASH_SST25TYPE is set and writeBytes is called, it will use opcode 0xAD #SPIFLASH_AAIWORDPROGRAM and care for Byte alignment.<BR>
|
||||
/// Note: AAI Wordprogramming is independent of Pages, so pagebreaking is not an issue when using AAI Wordprogramming.
|
||||
///
|
||||
#ifdef DOXYGEN //needed to tell doxygen not to ignore the define which is actually made somewhere else
|
||||
#define MY_SPIFLASH_SST25TYPE
|
||||
#endif
|
||||
|
||||
#ifdef DOXYGEN //needed to tell doxygen not to ignore the define which is actually made somewhere else
|
||||
#define MY_SPIFLASH_SST25TYPE
|
||||
#endif
|
||||
|
||||
/** SPIFlash class */
|
||||
class SPIFlash {
|
||||
class SPIFlash
|
||||
{
|
||||
public:
|
||||
static uint8_t UNIQUEID[8]; //!< Storage for unique identifier
|
||||
SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); //!< Constructor
|
||||
boolean initialize(); //!< setup SPI, read device ID etc...
|
||||
void command(uint8_t cmd, boolean isWrite=false); //!< Send a command to the flash chip, pass TRUE for isWrite when its a write command
|
||||
uint8_t readStatus(); //!< return the STATUS register
|
||||
uint8_t readByte(uint32_t addr); //!< read 1 byte from flash memory
|
||||
void readBytes(uint32_t addr, void* buf, uint16_t len); //!< read unlimited # of bytes
|
||||
void writeByte(uint32_t addr, uint8_t byt); //!< Write 1 byte to flash memory
|
||||
void writeBytes(uint32_t addr, const void* buf, uint16_t len); //!< write multiple bytes to flash memory (up to 64K), if define SPIFLASH_SST25TYPE is set AAI Word Programming will be used
|
||||
boolean busy(); //!< check if the chip is busy erasing/writing
|
||||
void chipErase(); //!< erase entire flash memory array
|
||||
void blockErase4K(uint32_t address); //!< erase a 4Kbyte block
|
||||
void blockErase32K(uint32_t address); //!< erase a 32Kbyte block
|
||||
uint16_t readDeviceId(); //!< Get the manufacturer and device ID bytes (as a short word)
|
||||
uint8_t* readUniqueId(); //!< Get the 64 bit unique identifier, stores it in @ref UNIQUEID[8]
|
||||
|
||||
void sleep(); //!< Put device to sleep
|
||||
void wakeup(); //!< Wake device
|
||||
void end(); //!< end
|
||||
static uint8_t UNIQUEID[8]; //!< Storage for unique identifier
|
||||
SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); //!< Constructor
|
||||
boolean initialize(); //!< setup SPI, read device ID etc...
|
||||
void command(uint8_t cmd, boolean isWrite=
|
||||
false); //!< Send a command to the flash chip, pass TRUE for isWrite when its a write command
|
||||
uint8_t readStatus(); //!< return the STATUS register
|
||||
uint8_t readByte(uint32_t addr); //!< read 1 byte from flash memory
|
||||
void readBytes(uint32_t addr, void* buf, uint16_t len); //!< read unlimited # of bytes
|
||||
void writeByte(uint32_t addr, uint8_t byt); //!< Write 1 byte to flash memory
|
||||
void writeBytes(uint32_t addr, const void* buf,
|
||||
uint16_t len); //!< write multiple bytes to flash memory (up to 64K), if define SPIFLASH_SST25TYPE is set AAI Word Programming will be used
|
||||
boolean busy(); //!< check if the chip is busy erasing/writing
|
||||
void chipErase(); //!< erase entire flash memory array
|
||||
void blockErase4K(uint32_t address); //!< erase a 4Kbyte block
|
||||
void blockErase32K(uint32_t address); //!< erase a 32Kbyte block
|
||||
uint16_t readDeviceId(); //!< Get the manufacturer and device ID bytes (as a short word)
|
||||
uint8_t* readUniqueId(); //!< Get the 64 bit unique identifier, stores it in @ref UNIQUEID[8]
|
||||
|
||||
void sleep(); //!< Put device to sleep
|
||||
void wakeup(); //!< Wake device
|
||||
void end(); //!< end
|
||||
protected:
|
||||
void select(); //!< select
|
||||
void unselect(); //!< unselect
|
||||
uint8_t _slaveSelectPin; //!< Slave select pin
|
||||
uint16_t _jedecID; //!< JEDEC ID
|
||||
uint8_t _SPCR; //!< SPCR
|
||||
uint8_t _SPSR; //!< SPSR
|
||||
void select(); //!< select
|
||||
void unselect(); //!< unselect
|
||||
uint8_t _slaveSelectPin; //!< Slave select pin
|
||||
uint16_t _jedecID; //!< JEDEC ID
|
||||
uint8_t _SPCR; //!< SPCR
|
||||
uint8_t _SPSR; //!< SPSR
|
||||
#ifdef SPI_HAS_TRANSACTION
|
||||
SPISettings _settings;
|
||||
SPISettings _settings;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user