hellomqttt to thingspeak mqtt and ifttt
Dependencies: Servo MQTTPacket FP
Revision 25:ca1b1098c77f, committed 2021-05-05
- Comitter:
- jasonberry
- Date:
- Wed May 05 14:48:01 2021 +0000
- Parent:
- 24:d2e25cdf9084
- Commit message:
- TEST
Changed in this revision
diff -r d2e25cdf9084 -r ca1b1098c77f C12832.lib --- a/C12832.lib Thu Mar 11 13:56:02 2021 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://mbed.org/teams/components/code/C12832/#03069e3deaa4
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/C12832.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/C12832.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,564 @@ +/* mbed library for the mbed Lab Board 128*32 pixel LCD + * use C12832 controller + * Copyright (c) 2012 Peter Drescher - DC2PD + * Released under the MIT License: http://mbed.org/license/mit + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// 13.10.12 initial design +// 25.10.12 add autorefresh of screen +// 25.10.12 add standart font +// 20.12.12 add bitmap graphics + +// optional defines : +// #define debug_lcd 1 + +#include "C12832.h" +#include "mbed.h" +#include "stdio.h" +#include "Small_7.h" + +#define BPP 1 // Bits per pixel + + +C12832::C12832(PinName mosi, PinName sck, PinName reset, PinName a0, PinName ncs, const char* name) + : GraphicsDisplay(name),_spi(mosi,NC,sck),_reset(reset),_A0(a0),_CS(ncs) +{ + orientation = 1; + draw_mode = NORMAL; + char_x = 0; + lcd_reset(); +} + + +int C12832::width() +{ + if (orientation == 0 || orientation == 2) return 32; + else return 128; +} + +int C12832::height() +{ + if (orientation == 0 || orientation == 2) return 128; + else return 32; +} + + +void C12832::invert(unsigned int o) +{ + if(o == 0) wr_cmd(0xA6); + else wr_cmd(0xA7); +} + + +void C12832::set_contrast(unsigned int o) +{ + contrast = o; + wr_cmd(0x81); // set volume + wr_cmd(o & 0x3F); +} + +unsigned int C12832::get_contrast(void) +{ + return(contrast); +} + + +// write command to lcd controller + +void C12832::wr_cmd(unsigned char cmd) +{ + _A0 = 0; + _CS = 0; + _spi.write(cmd); + _CS = 1; +} + +// write data to lcd controller + +void C12832::wr_dat(unsigned char dat) +{ + _A0 = 1; + _CS = 0; + _spi.write(dat); + _CS = 1; +} + +// reset and init the lcd controller + +void C12832::lcd_reset() +{ + + _spi.format(8,3); // 8 bit spi mode 3 + _spi.frequency(20000000); // 19,2 Mhz SPI clock + _A0 = 0; + _CS = 1; + _reset = 0; // display reset + wait_us(50); + _reset = 1; // end reset + wait_ms(5); + + /* Start Initial Sequence ----------------------------------------------------*/ + + wr_cmd(0xAE); // display off + wr_cmd(0xA2); // bias voltage + + wr_cmd(0xA0); + wr_cmd(0xC8); // colum normal + + wr_cmd(0x22); // voltage resistor ratio + wr_cmd(0x2F); // power on + //wr_cmd(0xA4); // LCD display ram + wr_cmd(0x40); // start line = 0 + wr_cmd(0xAF); // display ON + + wr_cmd(0x81); // set contrast + wr_cmd(0x17); // set contrast + + wr_cmd(0xA6); // display normal + + + // clear and update LCD + memset(buffer,0x00,512); // clear display buffer + copy_to_lcd(); + auto_up = 1; // switch on auto update + // dont do this by default. Make the user call + //claim(stdout); // redirekt printf to lcd + locate(0,0); + set_font((unsigned char*)Small_7); // standart font +} + +// set one pixel in buffer + +void C12832::pixel(int x, int y, int color) +{ + // first check parameter + if(x > 128 || y > 32 || x < 0 || y < 0) return; + + if(draw_mode == NORMAL) { + if(color == 0) + buffer[x + ((y/8) * 128)] &= ~(1 << (y%8)); // erase pixel + else + buffer[x + ((y/8) * 128)] |= (1 << (y%8)); // set pixel + } else { // XOR mode + if(color == 1) + buffer[x + ((y/8) * 128)] ^= (1 << (y%8)); // xor pixel + } +} + +// update lcd + +void C12832::copy_to_lcd(void) +{ + + int i=0; + + //page 0 + wr_cmd(0x00); // set column low nibble 0 + wr_cmd(0x10); // set column hi nibble 0 + wr_cmd(0xB0); // set page address 0 + _A0 = 1; + for(i=0; i<128; i++) { + wr_dat(buffer[i]); + } + + // page 1 + wr_cmd(0x00); // set column low nibble 0 + wr_cmd(0x10); // set column hi nibble 0 + wr_cmd(0xB1); // set page address 1 + _A0 = 1; + for(i=128; i<256; i++) { + wr_dat(buffer[i]); + } + + //page 2 + wr_cmd(0x00); // set column low nibble 0 + wr_cmd(0x10); // set column hi nibble 0 + wr_cmd(0xB2); // set page address 2 + _A0 = 1; + for(i=256; i<384; i++) { + wr_dat(buffer[i]); + } + + //page 3 + wr_cmd(0x00); // set column low nibble 0 + wr_cmd(0x10); // set column hi nibble 0 + wr_cmd(0xB3); // set page address 3 + _A0 = 1; + + _CS = 0; + + for(i=384; i<512; i++) { + wr_dat(buffer[i]); + } + +} + +void C12832::cls(void) +{ + memset(buffer,0x00,512); // clear display buffer + copy_to_lcd(); +} + + +void C12832::line(int x0, int y0, int x1, int y1, int color) +{ + int dx = 0, dy = 0; + int dx_sym = 0, dy_sym = 0; + int dx_x2 = 0, dy_x2 = 0; + int di = 0; + + dx = x1-x0; + dy = y1-y0; + + // if (dx == 0) { /* vertical line */ + // if (y1 > y0) vline(x0,y0,y1,color); + // else vline(x0,y1,y0,color); + // return; + // } + + if (dx > 0) { + dx_sym = 1; + } else { + dx_sym = -1; + } + // if (dy == 0) { /* horizontal line */ + // if (x1 > x0) hline(x0,x1,y0,color); + // else hline(x1,x0,y0,color); + // return; + // } + + if (dy > 0) { + dy_sym = 1; + } else { + dy_sym = -1; + } + + dx = dx_sym*dx; + dy = dy_sym*dy; + + dx_x2 = dx*2; + dy_x2 = dy*2; + + if (dx >= dy) { + di = dy_x2 - dx; + while (x0 != x1) { + + pixel(x0, y0, color); + x0 += dx_sym; + if (di<0) { + di += dy_x2; + } else { + di += dy_x2 - dx_x2; + y0 += dy_sym; + } + } + pixel(x0, y0, color); + } else { + di = dx_x2 - dy; + while (y0 != y1) { + pixel(x0, y0, color); + y0 += dy_sym; + if (di < 0) { + di += dx_x2; + } else { + di += dx_x2 - dy_x2; + x0 += dx_sym; + } + } + pixel(x0, y0, color); + } + if(auto_up) copy_to_lcd(); +} + +void C12832::rect(int x0, int y0, int x1, int y1, int color) +{ + + if (x1 > x0) line(x0,y0,x1,y0,color); + else line(x1,y0,x0,y0,color); + + if (y1 > y0) line(x0,y0,x0,y1,color); + else line(x0,y1,x0,y0,color); + + if (x1 > x0) line(x0,y1,x1,y1,color); + else line(x1,y1,x0,y1,color); + + if (y1 > y0) line(x1,y0,x1,y1,color); + else line(x1,y1,x1,y0,color); + + if(auto_up) copy_to_lcd(); +} + +void C12832::fillrect(int x0, int y0, int x1, int y1, int color) +{ + int l,c,i; + if(x0 > x1) { + i = x0; + x0 = x1; + x1 = i; + } + + if(y0 > y1) { + i = y0; + y0 = y1; + y1 = i; + } + + for(l = x0; l<= x1; l ++) { + for(c = y0; c<= y1; c++) { + pixel(l,c,color); + } + } + if(auto_up) copy_to_lcd(); +} + + + +void C12832::circle(int x0, int y0, int r, int color) +{ + + int draw_x0, draw_y0; + int draw_x1, draw_y1; + int draw_x2, draw_y2; + int draw_x3, draw_y3; + int draw_x4, draw_y4; + int draw_x5, draw_y5; + int draw_x6, draw_y6; + int draw_x7, draw_y7; + int xx, yy; + int di; + //WindowMax(); + if (r == 0) { /* no radius */ + return; + } + + draw_x0 = draw_x1 = x0; + draw_y0 = draw_y1 = y0 + r; + if (draw_y0 < height()) { + pixel(draw_x0, draw_y0, color); /* 90 degree */ + } + + draw_x2 = draw_x3 = x0; + draw_y2 = draw_y3 = y0 - r; + if (draw_y2 >= 0) { + pixel(draw_x2, draw_y2, color); /* 270 degree */ + } + + draw_x4 = draw_x6 = x0 + r; + draw_y4 = draw_y6 = y0; + if (draw_x4 < width()) { + pixel(draw_x4, draw_y4, color); /* 0 degree */ + } + + draw_x5 = draw_x7 = x0 - r; + draw_y5 = draw_y7 = y0; + if (draw_x5>=0) { + pixel(draw_x5, draw_y5, color); /* 180 degree */ + } + + if (r == 1) { + return; + } + + di = 3 - 2*r; + xx = 0; + yy = r; + while (xx < yy) { + + if (di < 0) { + di += 4*xx + 6; + } else { + di += 4*(xx - yy) + 10; + yy--; + draw_y0--; + draw_y1--; + draw_y2++; + draw_y3++; + draw_x4--; + draw_x5++; + draw_x6--; + draw_x7++; + } + xx++; + draw_x0++; + draw_x1--; + draw_x2++; + draw_x3--; + draw_y4++; + draw_y5++; + draw_y6--; + draw_y7--; + + if ( (draw_x0 <= width()) && (draw_y0>=0) ) { + pixel(draw_x0, draw_y0, color); + } + + if ( (draw_x1 >= 0) && (draw_y1 >= 0) ) { + pixel(draw_x1, draw_y1, color); + } + + if ( (draw_x2 <= width()) && (draw_y2 <= height()) ) { + pixel(draw_x2, draw_y2, color); + } + + if ( (draw_x3 >=0 ) && (draw_y3 <= height()) ) { + pixel(draw_x3, draw_y3, color); + } + + if ( (draw_x4 <= width()) && (draw_y4 >= 0) ) { + pixel(draw_x4, draw_y4, color); + } + + if ( (draw_x5 >= 0) && (draw_y5 >= 0) ) { + pixel(draw_x5, draw_y5, color); + } + if ( (draw_x6 <=width()) && (draw_y6 <= height()) ) { + pixel(draw_x6, draw_y6, color); + } + if ( (draw_x7 >= 0) && (draw_y7 <= height()) ) { + pixel(draw_x7, draw_y7, color); + } + } + if(auto_up) copy_to_lcd(); +} + +void C12832::fillcircle(int x, int y, int r, int color) +{ + int i,up; + up = auto_up; + auto_up = 0; // off + for (i = 0; i <= r; i++) + circle(x,y,i,color); + auto_up = up; + if(auto_up) copy_to_lcd(); +} + +void C12832::setmode(int mode) +{ + draw_mode = mode; +} + +void C12832::locate(int x, int y) +{ + char_x = x; + char_y = y; +} + + + +int C12832::columns() +{ + return width() / font[1]; +} + + + +int C12832::rows() +{ + return height() / font[2]; +} + + + +int C12832::_putc(int value) +{ + if (value == '\n') { // new line + char_x = 0; + char_y = char_y + font[2]; + if (char_y >= height() - font[2]) { + char_y = 0; + } + } else { + character(char_x, char_y, value); + if(auto_up) copy_to_lcd(); + } + return value; +} + +void C12832::character(int x, int y, int c) +{ + unsigned int hor,vert,offset,bpl,j,i,b; + unsigned char* zeichen; + unsigned char z,w; + + if ((c < 31) || (c > 127)) return; // test char range + + // read font parameter from start of array + offset = font[0]; // bytes / char + hor = font[1]; // get hor size of font + vert = font[2]; // get vert size of font + bpl = font[3]; // bytes per line + + if (char_x + hor > width()) { + char_x = 0; + char_y = char_y + vert; + if (char_y >= height() - font[2]) { + char_y = 0; + } + } + + zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap + w = zeichen[0]; // width of actual char + // construct the char into the buffer + for (j=0; j<vert; j++) { // vert line + for (i=0; i<hor; i++) { // horz line + z = zeichen[bpl * i + ((j & 0xF8) >> 3)+1]; + b = 1 << (j & 0x07); + if (( z & b ) == 0x00) { + pixel(x+i,y+j,0); + } else { + pixel(x+i,y+j,1); + } + + } + } + + char_x += w; +} + + +void C12832::set_font(unsigned char* f) +{ + font = f; +} + +void C12832::set_auto_up(unsigned int up) +{ + if(up ) auto_up = 1; + else auto_up = 0; +} + +unsigned int C12832::get_auto_up(void) +{ + return (auto_up); +} + +void C12832::print_bm(Bitmap bm, int x, int y) +{ + int h,v,b; + char d; + + for(v=0; v < bm.ySize; v++) { // lines + for(h=0; h < bm.xSize; h++) { // pixel + if(h + x > 127) break; + if(v + y > 31) break; + d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)]; + b = 0x80 >> (h & 0x07); + if((d & b) == 0) { + pixel(x+h,y+v,0); + } else { + pixel(x+h,y+v,1); + } + } + } + +} + +
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/C12832.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/C12832.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,314 @@ +/* mbed library for the mbed Lab Board 128*32 pixel LCD + * use C12832 controller + * Copyright (c) 2012 Peter Drescher - DC2PD + * Released under the MIT License: http://mbed.org/license/mit + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef C12832_H +#define C12832_H + +#include "mbed.h" +#include "GraphicsDisplay.h" + + +/** + * Optional Defines: + * #define debug_lcd 1 enable infos to PC_USB + */ + +// some defines for the DMA use +#define DMA_CHANNEL_ENABLE 1 +#define DMA_TRANSFER_TYPE_M2P (1UL << 11) +#define DMA_CHANNEL_TCIE (1UL << 31) +#define DMA_CHANNEL_SRC_INC (1UL << 26) +#define DMA_MASK_IE (1UL << 14) +#define DMA_MASK_ITC (1UL << 15) +#define DMA_SSP1_TX (1UL << 2) +#define DMA_SSP0_TX (0) +#define DMA_DEST_SSP1_TX (2UL << 6) +#define DMA_DEST_SSP0_TX (0UL << 6) + +/** + * Draw mode + * NORMAL + * XOR set pixel by xor the screen + */ +enum {NORMAL,XOR}; + +/** + * Bitmap + */ +struct Bitmap{ + int xSize; + int ySize; + int Byte_in_Line; + char* data; +}; + +/** + * The C12832 class + */ +class C12832 : public GraphicsDisplay +{ +public: + /** + * Create a C12832 object connected to SPI1 + */ + C12832(PinName mosi, PinName sck, PinName reset, PinName a0, PinName ncs, const char* name = "LCD"); + + /** + * Get the width of the screen in pixel + * + * @returns width of screen in pixel + * + */ + virtual int width(); + + /** + * Get the height of the screen in pixel + * + * @returns height of screen in pixel + */ + virtual int height(); + + /** + * Draw a pixel at x,y black or white + * + * @param x horizontal position + * @param y vertical position + * @param color - 1 set pixel, 0 erase pixel + */ + virtual void pixel(int x, int y,int colour); + + /** + * Draw a circle + * + * @param x0,y0 center + * @param r radius + * @param color - 1 set pixel, 0 erase pixel + */ + void circle(int x, int y, int r, int colour); + + /** + * Draw a filled circle + * + * @param x0,y0 center + * @param r radius + * @param color - 1 set pixel, 0 erase pixel + * + * Use circle with different radius, + * Can miss some pixels + */ + void fillcircle(int x, int y, int r, int colour); + + /** + * Draw a 1 pixel line + * + * @param x0,y0 start point + * @param x1,y1 stop point + * @param color - 1 set pixel, 0 erase pixel + */ + void line(int x0, int y0, int x1, int y1, int colour); + + /** + * Draw a rect + * + * @param x0,y0 top left corner + * @param x1,y1 down right corner + * @param color - 1 set pixel, 0 erase pixel + */ + void rect(int x0, int y0, int x1, int y1, int colour); + + /** + * Draw a filled rect + * + * @param x0,y0 top left corner + * @param x1,y1 down right corner + * @param color - 1 set pixel, 0 erase pixel + */ + void fillrect(int x0, int y0, int x1, int y1, int colour); + + /** + * Copy display buffer to LCD + */ + void copy_to_lcd(void); + + /** + * Set the orienation of the screen + */ + + void set_contrast(unsigned int o); + + /** + * Read the contrast level + */ + unsigned int get_contrast(void); + + /** + * Invert the screen + * + * @param o = 0 normal, 1 invert + */ + void invert(unsigned int o); + + /** + * Clear the screen + */ + virtual void cls(void); + + /** + * Set the drawing mode + * + * @param mode NORMAl or XOR + */ + void setmode(int mode); + + virtual int columns(void); + + /** + * Calculate the max number of columns. + * Depends on actual font size + * + * @returns max column + */ + virtual int rows(void); + + /** + * Put a char on the screen + * + * @param value char to print + * @returns printed char + */ + virtual int _putc(int value); + + /** + * Draw a character on given position out of the active font to the LCD + * + * @param x x-position of char (top left) + * @param y y-position + * @param c char to print + */ + virtual void character(int x, int y, int c); + + /** + * Setup cursor position + * + * @param x x-position (top left) + * @param y y-position + */ + virtual void locate(int x, int y); + + /** + * Setup auto update of screen + * + * @param up 1 = on , 0 = off + * + * if switched off the program has to call copy_to_lcd() + * to update screen from framebuffer + */ + void set_auto_up(unsigned int up); + + /** + * Get status of the auto update function + * + * @returns if auto update is on + */ + unsigned int get_auto_up(void); + + /** Vars */ + SPI _spi; + DigitalOut _reset; + DigitalOut _A0; + DigitalOut _CS; + unsigned char* font; + unsigned int draw_mode; + + + /** + * Select the font to use + * + * @param f pointer to font array + * + * font array can created with GLCD Font Creator from http://www.mikroe.com + * you have to add 4 parameter at the beginning of the font array to use: + * - the number of byte / char + * - the vertial size in pixel + * - the horizontal size in pixel + * - the number of byte per vertical line + * you also have to change the array to char[] + */ + void set_font(unsigned char* f); + + /** + * Print bitmap to buffer + * + * @param bm Bitmap in flash + * @param x x start + * @param y y start + */ + void print_bm(Bitmap bm, int x, int y); + +protected: + + /** + * Draw a horizontal line + * + * @param x0 horizontal start + * @param x1 horizontal stop + * @param y vertical position + * @param color - 1 set pixel, 0 erase pixel + */ + void hline(int x0, int x1, int y, int colour); + + /** + * Draw a vertical line + * + * @param x horizontal position + * @param y0 vertical start + * @param y1 vertical stop + * @param color - 1 set pixel, 0 erase pixel + */ + void vline(int y0, int y1, int x, int colour); + + /** + * Init the C12832 LCD controller + */ + void lcd_reset(); + + /** + * Write data to the LCD controller + * + * @param dat data written to LCD controller + */ + void wr_dat(unsigned char value); + + /** + * Write a command the LCD controller + * + * @param cmd: command to be written + */ + void wr_cmd(unsigned char value); + + void wr_cnt(unsigned char cmd); + + unsigned int orientation; + unsigned int char_x; + unsigned int char_y; + unsigned char buffer[512]; + unsigned int contrast; + unsigned int auto_up; + +}; + + + + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/GraphicsDisplay.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/GraphicsDisplay.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,176 @@ +/* mbed GraphicsDisplay Display Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "GraphicsDisplay.h" + +const unsigned char FONT8x8[97][8] = { +0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20 +0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00, // ! +0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00, // " +0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00, // # +0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00, // $ +0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00, // % +0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00, // & +0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00, // ' +0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00, // ( +0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00, // ) +0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00, // * +0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00, // + +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30, // , +0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // - +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, // . +0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00, // / (forward slash) +0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00, // 0 0x30 +0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00, // 1 +0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00, // 2 +0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00, // 3 +0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00, // 4 +0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00, // 5 +0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00, // 6 +0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00, // 7 +0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00, // 8 +0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00, // 9 +0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00, // : +0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30, // ; +0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00, // < +0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00, // = +0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00, // > +0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00, // ? +0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00, // @ 0x40 +0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00, // A +0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00, // B +0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00, // C +0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00, // D +0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00, // E +0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00, // F +0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00, // G +0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00, // H +0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // I +0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // J +0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00, // K +0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00, // L +0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00, // M +0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00, // N +0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00, // O +0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00, // P 0x50 +0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00, // Q +0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00, // R +0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00, // S +0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00, // T +0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00, // U +0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00, // V +0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00, // W +0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00, // X +0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00, // Y +0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00, // Z +0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00, // [ +0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, // \ (back slash) +0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00, // ] +0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, // ^ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, // _ +0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00, // ` 0x60 +0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00, // a +0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00, // b +0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00, // c +0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00, // d +0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00, // e +0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00, // f +0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C, // g +0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00, // h +0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00, // i +0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C, // j +0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00, // k +0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // l +0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00, // m +0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00, // n +0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00, // o +0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78, // p +0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F, // q +0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00, // r +0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00, // s +0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00, // t +0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00, // u +0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00, // v +0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00, // w +0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00, // x +0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C, // y +0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00, // z +0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00, // { +0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00, // | +0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00, // } +0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00, // ~ +0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00}; // DEL + +GraphicsDisplay::GraphicsDisplay(const char *name):TextDisplay(name) { + foreground(0xFFFF); + background(0x0000); +} + +void GraphicsDisplay::character(int column, int row, int value) { + blitbit(column * 8, row * 8, 8, 8, (char*)&(FONT8x8[value - 0x1F][0])); +} + +void GraphicsDisplay::window(int x, int y, int w, int h) { + // current pixel location + _x = x; + _y = y; + // window settings + _x1 = x; + _x2 = x + w - 1; + _y1 = y; + _y2 = y + h - 1; +} + +void GraphicsDisplay::putp(int colour) { + // put pixel at current pixel location + pixel(_x, _y, colour); + // update pixel location based on window settings + _x++; + if(_x > _x2) { + _x = _x1; + _y++; + if(_y > _y2) { + _y = _y1; + } + } +} + +void GraphicsDisplay::fill(int x, int y, int w, int h, int colour) { + window(x, y, w, h); + for(int i=0; i<w*h; i++) { + putp(colour); + } +} + +void GraphicsDisplay::cls() { + fill(0, 0, width(), height(), _background); +} + +void GraphicsDisplay::blit(int x, int y, int w, int h, const int *colour) { + window(x, y, w, h); + for(int i=0; i<w*h; i++) { + putp(colour[i]); + } +} + +void GraphicsDisplay::blitbit(int x, int y, int w, int h, const char* colour) { + window(x, y, w, h); + for(int i = 0; i < w*h; i++) { + char byte = colour[i >> 3]; + int offset = i & 0x7; + int c = ((byte << offset) & 0x80) ? _foreground : _background; + putp(c); + } +} + +int GraphicsDisplay::columns() { + return width() / 8; +} + +int GraphicsDisplay::rows() { + return height() / 8; +} +
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/GraphicsDisplay.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/GraphicsDisplay.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,55 @@ +/* mbed GraphicsDisplay Display Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + * + * A library for providing a common base class for Graphics displays + * To port a new display, derive from this class and implement + * the constructor (setup the display), pixel (put a pixel + * at a location), width and height functions. Everything else + * (locate, printf, putc, cls, window, putp, fill, blit, blitbit) + * will come for free. You can also provide a specialised implementation + * of window and putp to speed up the results + */ + +#ifndef MBED_GRAPHICSDISPLAY_H +#define MBED_GRAPHICSDISPLAY_H + +#include "TextDisplay.h" + +class GraphicsDisplay : public TextDisplay { + +public: + + GraphicsDisplay(const char* name); + + virtual void pixel(int x, int y, int colour) = 0; + virtual int width() = 0; + virtual int height() = 0; + + virtual void window(int x, int y, int w, int h); + virtual void putp(int colour); + + virtual void cls(); + virtual void fill(int x, int y, int w, int h, int colour); + virtual void blit(int x, int y, int w, int h, const int *colour); + virtual void blitbit(int x, int y, int w, int h, const char* colour); + + virtual void character(int column, int row, int value); + virtual int columns(); + virtual int rows(); + +protected: + + // pixel location + short _x; + short _y; + + // window location + short _x1; + short _x2; + short _y1; + short _y2; + +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/Small_7.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/Small_7.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,104 @@ +#ifndef small_7 +#define small_7 + +const unsigned char Small_7[] = { + 19,9,9,2, // Length,horz,vert,byte/vert + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char + 0x02, 0x00, 0x00, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ! + 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char " + 0x06, 0x00, 0x00, 0x50, 0x00, 0xF8, 0x00, 0x50, 0x00, 0xF8, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char # + 0x06, 0x00, 0x00, 0x8C, 0x00, 0x92, 0x00, 0xFE, 0x01, 0xA2, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char $ + 0x07, 0x1E, 0x00, 0x92, 0x00, 0x5E, 0x00, 0x20, 0x00, 0xF8, 0x00, 0x94, 0x00, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char % + 0x07, 0x00, 0x00, 0x64, 0x00, 0x9A, 0x00, 0xAA, 0x00, 0xCC, 0x00, 0x60, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char & + 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ' + 0x03, 0x00, 0x00, 0x7C, 0x00, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ( + 0x03, 0x00, 0x00, 0x83, 0x01, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ) + 0x04, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char * + 0x05, 0x10, 0x00, 0x10, 0x00, 0x7C, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char + + 0x02, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char , + 0x04, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char - + 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char . + 0x04, 0x00, 0x01, 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char / + 0x05, 0x00, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x82, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 0 + 0x05, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 1 + 0x05, 0x00, 0x00, 0x84, 0x00, 0xC2, 0x00, 0xA2, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 2 + 0x05, 0x00, 0x00, 0x82, 0x00, 0x92, 0x00, 0x92, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 3 + 0x05, 0x00, 0x00, 0x38, 0x00, 0x2C, 0x00, 0x22, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 4 + 0x05, 0x00, 0x00, 0x9E, 0x00, 0x92, 0x00, 0x92, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 5 + 0x05, 0x00, 0x00, 0x7C, 0x00, 0x92, 0x00, 0x92, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 6 + 0x05, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x00, 0x32, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 7 + 0x05, 0x00, 0x00, 0x6C, 0x00, 0x92, 0x00, 0x92, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 8 + 0x05, 0x00, 0x00, 0x9C, 0x00, 0x92, 0x00, 0x92, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 9 + 0x02, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char : + 0x02, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ; + 0x05, 0x10, 0x00, 0x10, 0x00, 0x28, 0x00, 0x28, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char < + 0x05, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char = + 0x05, 0x00, 0x00, 0x44, 0x00, 0x28, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char > + 0x05, 0x00, 0x00, 0x02, 0x00, 0xB2, 0x00, 0x12, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ? + 0x09, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x01, 0x72, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x7A, 0x01, 0x42, 0x00, 0x3C, 0x00, // Code for char @ + 0x06, 0x00, 0x00, 0xF8, 0x00, 0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char A + 0x06, 0x00, 0x00, 0xFE, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char B + 0x06, 0x00, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char C + 0x06, 0x00, 0x00, 0xFE, 0x00, 0x82, 0x00, 0x82, 0x00, 0xC6, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char D + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char E + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char F + 0x06, 0x00, 0x00, 0x7C, 0x00, 0xC6, 0x00, 0x82, 0x00, 0x92, 0x00, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char G + 0x06, 0x00, 0x00, 0xFE, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char H + 0x02, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char I + 0x04, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char J + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x10, 0x00, 0x2C, 0x00, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char K + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char L + 0x08, 0x00, 0x00, 0xFE, 0x00, 0x06, 0x00, 0x18, 0x00, 0xE0, 0x00, 0x18, 0x00, 0x06, 0x00, 0xFE, 0x00, 0x00, 0x00, // Code for char M + 0x06, 0x00, 0x00, 0xFE, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char N + 0x06, 0x00, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char O + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x12, 0x00, 0x12, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char P + 0x07, 0x00, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x82, 0x00, 0xC2, 0x00, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Code for char Q + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x12, 0x00, 0x12, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char R + 0x05, 0x00, 0x00, 0xCC, 0x00, 0x92, 0x00, 0x92, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char S + 0x06, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char T + 0x06, 0x00, 0x00, 0x7E, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char U + 0x07, 0x00, 0x00, 0x06, 0x00, 0x3C, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char V + 0x06, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x00, 0x3E, 0x00, 0xE0, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char W + 0x06, 0x00, 0x00, 0x82, 0x00, 0x64, 0x00, 0x38, 0x00, 0x6C, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char X + 0x06, 0x00, 0x00, 0x02, 0x00, 0x0C, 0x00, 0xF0, 0x00, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char Y + 0x06, 0x00, 0x00, 0x82, 0x00, 0xE2, 0x00, 0x92, 0x00, 0x8E, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char Z + 0x03, 0x00, 0x00, 0xFF, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char [ + 0x04, 0x01, 0x00, 0x0E, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char BackSlash + 0x02, 0x01, 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ] + 0x04, 0x00, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ^ + 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char _ + 0x03, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ` + 0x05, 0x00, 0x00, 0xE8, 0x00, 0xA8, 0x00, 0xA8, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char a + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x88, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char b + 0x05, 0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char c + 0x05, 0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0x88, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char d + 0x05, 0x00, 0x00, 0x70, 0x00, 0xA8, 0x00, 0xA8, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char e + 0x04, 0x08, 0x00, 0xFE, 0x00, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char f + 0x05, 0x00, 0x00, 0x30, 0x00, 0x48, 0x01, 0x48, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char g + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char h + 0x02, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char i + 0x02, 0x00, 0x01, 0xFA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char j + 0x05, 0x00, 0x00, 0xFE, 0x00, 0x20, 0x00, 0x50, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char k + 0x02, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char l + 0x06, 0x00, 0x00, 0xF8, 0x00, 0x08, 0x00, 0xF8, 0x00, 0x08, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char m + 0x05, 0x00, 0x00, 0xF8, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char n + 0x05, 0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char o + 0x05, 0x00, 0x00, 0xF8, 0x01, 0x48, 0x00, 0x48, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char p + 0x05, 0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char q + 0x04, 0x00, 0x00, 0xF8, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char r + 0x04, 0x00, 0x00, 0x98, 0x00, 0xA8, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char s + 0x04, 0x00, 0x00, 0x08, 0x00, 0xFC, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char t + 0x05, 0x00, 0x00, 0x78, 0x00, 0x80, 0x00, 0x80, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char u + 0x04, 0x00, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char v + 0x06, 0x00, 0x00, 0x78, 0x00, 0xC0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char w + 0x05, 0x00, 0x00, 0x88, 0x00, 0x70, 0x00, 0x70, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char x + 0x05, 0x00, 0x00, 0x38, 0x00, 0x40, 0x01, 0x40, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char y + 0x05, 0x00, 0x00, 0xC8, 0x00, 0xE8, 0x00, 0xB8, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char z + 0x04, 0x10, 0x00, 0x38, 0x00, 0xEF, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char { + 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char | + 0x04, 0x01, 0x01, 0xC7, 0x01, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char } + 0x05, 0x0C, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ~ + 0x03, 0xFE, 0x01, 0x02, 0x01, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Code for char + }; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/TextDisplay.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/TextDisplay.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,77 @@ +/* mbed TextDisplay Display Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "TextDisplay.h" + +TextDisplay::TextDisplay(const char *name) : Stream(name){ + _row = 0; + _column = 0; + if (name == NULL) { + _path = NULL; + } else { + _path = new char[strlen(name) + 2]; + sprintf(_path, "/%s", name); + } +} + +int TextDisplay::_putc(int value) { + if(value == '\n') { + _column = 0; + _row++; + if(_row >= rows()) { + _row = 0; + } + } else { + character(_column, _row, value); + _column++; + if(_column >= columns()) { + _column = 0; + _row++; + if(_row >= rows()) { + _row = 0; + } + } + } + return value; +} + +// crude cls implementation, should generally be overwritten in derived class +void TextDisplay::cls() { + locate(0, 0); + for(int i=0; i<columns()*rows(); i++) { + putc(' '); + } +} + +void TextDisplay::locate(int column, int row) { + _column = column; + _row = row; +} + +int TextDisplay::_getc() { + return -1; +} + +void TextDisplay::foreground(uint16_t colour) { + _foreground = colour; +} + +void TextDisplay::background(uint16_t colour) { + _background = colour; +} + +bool TextDisplay::claim (FILE *stream) { + if ( _path == NULL) { + fprintf(stderr, "claim requires a name to be given in the instantioator of the TextDisplay instance!\r\n"); + return false; + } + if (freopen(_path, "w", stream) == NULL) { + // Failed, should not happen + return false; + } + // make sure we use line buffering + setvbuf(stdout, NULL, _IOLBF, columns()); + return true; +}
diff -r d2e25cdf9084 -r ca1b1098c77f C12832/TextDisplay.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832/TextDisplay.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,96 @@ +/* mbed TextDisplay Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + * + * A common base class for Text displays + * To port a new display, derive from this class and implement + * the constructor (setup the display), character (put a character + * at a location), rows and columns (number of rows/cols) functions. + * Everything else (locate, printf, putc, cls) will come for free + * + * The model is the display will wrap at the right and bottom, so you can + * keep writing and will always get valid characters. The location is + * maintained internally to the class to make this easy + */ + +#ifndef MBED_TEXTDISPLAY_H +#define MBED_TEXTDISPLAY_H + +#include "mbed.h" + +/** + * TextDisplay interface + */ +class TextDisplay : public Stream { +public: + + /** + * Create a TextDisplay interface + * + * @param name The name used in the path to access the strean through the filesystem + */ + TextDisplay(const char *name = NULL); + + /** + * Output a character at the given position + * + * @param column column where charater must be written + * @param row where character must be written + * @param c the character to be written to the TextDisplay + */ + virtual void character(int column, int row, int c) = 0; + + /** + * Return number of rows on TextDisplay + * + * @results number of rows + */ + virtual int rows() = 0; + + /** + * Return number if columns on TextDisplay\ + * + * @results number of rows + */ + virtual int columns() = 0; + + // functions that come for free, but can be overwritten + + /** + * Redirect output from a stream (stoud, sterr) to display + * + * @param stream stream that shall be redirected to the TextDisplay + */ + virtual bool claim (FILE *stream); + + /** + * Clear screen + */ + virtual void cls(); + + /** + * Change the cursor position to column, row (in pixels) + */ + virtual void locate(int column, int row); + + virtual void foreground(uint16_t colour); + virtual void background(uint16_t colour); + // putc (from Stream) + // printf (from Stream) + +protected: + + virtual int _putc(int value); + virtual int _getc(); + + // character location + uint16_t _column; + uint16_t _row; + + // colours + uint16_t _foreground; + uint16_t _background; + char *_path; +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f LM75B/.hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LM75B/.hgignore Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,19 @@ +syntax: regexp +\.hgignore$ +\.git$ +\.svn$ +\.orig$ +\.msub$ +\.meta$ +\.ctags +\.uvproj$ +\.uvopt$ +\.project$ +\.cproject$ +\.launch$ +\.project$ +\.cproject$ +\.launch$ +Makefile$ +\.ewp$ +\.eww$ \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f LM75B/LM75B.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LM75B/LM75B.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,286 @@ +/* LM75B Driver Library + * Copyright (c) 2013 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LM75B.h" + +LM75B::LM75B(PinName sda, PinName scl, Address addr, int hz) : m_I2C(sda, scl), m_ADDR((int)addr) +{ + //Set the I2C bus frequency + m_I2C.frequency(hz); +} + +bool LM75B::open() +{ + //Probe for the LM75B using a Zero Length Transfer + if (!m_I2C.write(m_ADDR, NULL, 0)) { + //Return success + return true; + } else { + //Return failure + return false; + } +} + +LM75B::PowerMode LM75B::powerMode() +{ + //Read the 8-bit register value + char value = read8(REG_CONF); + + //Return the status of the SHUTDOWN bit + if (value & (1 << 0)) + return POWER_SHUTDOWN; + else + return POWER_NORMAL; +} + +void LM75B::powerMode(PowerMode mode) +{ + //Read the current 8-bit register value + char value = read8(REG_CONF); + + //Set or clear the SHUTDOWN bit + if (mode == POWER_SHUTDOWN) + value |= (1 << 0); + else + value &= ~(1 << 0); + + //Write the value back out + write8(REG_CONF, value); +} + +LM75B::OSMode LM75B::osMode() +{ + //Read the 8-bit register value + char value = read8(REG_CONF); + + //Return the status of the OS_COMP_INT bit + if (value & (1 << 1)) + return OS_INTERRUPT; + else + return OS_COMPARATOR; +} + +void LM75B::osMode(OSMode mode) +{ + //Read the current 8-bit register value + char value = read8(REG_CONF); + + //Set or clear the OS_COMP_INT bit + if (mode == OS_INTERRUPT) + value |= (1 << 1); + else + value &= ~(1 << 1); + + //Write the value back out + write8(REG_CONF, value); +} + +LM75B::OSPolarity LM75B::osPolarity() +{ + //Read the 8-bit register value + char value = read8(REG_CONF); + + //Return the status of the OS_POL bit + if (value & (1 << 2)) + return OS_ACTIVE_HIGH; + else + return OS_ACTIVE_LOW; +} + +void LM75B::osPolarity(OSPolarity polarity) +{ + //Read the current 8-bit register value + char value = read8(REG_CONF); + + //Set or clear the OS_POL bit + if (polarity == OS_ACTIVE_HIGH) + value |= (1 << 2); + else + value &= ~(1 << 2); + + //Write the value back out + write8(REG_CONF, value); +} + +LM75B::OSFaultQueue LM75B::osFaultQueue() +{ + //Read the 8-bit register value + char value = read8(REG_CONF); + + //Return the status of the OS_F_QUE bits + if ((value & (1 << 3)) && (value & (1 << 4))) + return OS_FAULT_QUEUE_6; + else if (!(value & (1 << 3)) && (value & (1 << 4))) + return OS_FAULT_QUEUE_4; + else if ((value & (1 << 3)) && !(value & (1 << 4))) + return OS_FAULT_QUEUE_2; + else + return OS_FAULT_QUEUE_1; +} + +void LM75B::osFaultQueue(OSFaultQueue queue) +{ + //Read the current 8-bit register value + char value = read8(REG_CONF); + + //Clear the old OS_F_QUE bits + value &= ~(3 << 3); + + //Set the new OS_F_QUE bits + if (queue == OS_FAULT_QUEUE_2) + value |= (1 << 3); + else if (queue == OS_FAULT_QUEUE_4) + value |= (2 << 3); + else if (queue == OS_FAULT_QUEUE_6) + value |= (3 << 3); + + //Write the value back out + write8(REG_CONF, value); +} + +float LM75B::alertTemp() +{ + //Use the 9-bit helper to read the TOS register + return readAlertTempHelper(REG_TOS); +} + +void LM75B::alertTemp(float temp) +{ + //Use the 9-bit helper to write to the TOS register + return writeAlertTempHelper(REG_TOS, temp); +} + +float LM75B::alertHyst() +{ + //Use the 9-bit helper to read the THYST register + return readAlertTempHelper(REG_THYST); +} + +void LM75B::alertHyst(float temp) +{ + //Use the 9-bit helper to write to the THYST register + return writeAlertTempHelper(REG_THYST, temp); +} + +float LM75B::temp() +{ + //Signed return value + short value; + + //Read the 11-bit raw temperature value + value = read16(REG_TEMP) >> 5; + + //Sign extend negative numbers + if (value & (1 << 10)) + value |= 0xFC00; + + //Return the temperature in °C + return value * 0.125; +} + +#ifdef MBED_OPERATORS +LM75B::operator float() +{ + //Return the current temperature reading + return temp(); +} +#endif + +char LM75B::read8(char reg) +{ + //Select the register + m_I2C.write(m_ADDR, ®, 1, true); + + //Read the 8-bit register + m_I2C.read(m_ADDR, ®, 1); + + //Return the byte + return reg; +} + +void LM75B::write8(char reg, char data) +{ + //Create a temporary buffer + char buff[2]; + + //Load the register address and 8-bit data + buff[0] = reg; + buff[1] = data; + + //Write the data + m_I2C.write(m_ADDR, buff, 2); +} + +unsigned short LM75B::read16(char reg) +{ + //Create a temporary buffer + char buff[2]; + + //Select the register + m_I2C.write(m_ADDR, ®, 1, true); + + //Read the 16-bit register + m_I2C.read(m_ADDR, buff, 2); + + //Return the combined 16-bit value + return (buff[0] << 8) | buff[1]; +} + +void LM75B::write16(char reg, unsigned short data) +{ + //Create a temporary buffer + char buff[3]; + + //Load the register address and 16-bit data + buff[0] = reg; + buff[1] = data >> 8; + buff[2] = data; + + //Write the data + m_I2C.write(m_ADDR, buff, 3); +} + +float LM75B::readAlertTempHelper(char reg) +{ + //Signed return value + short value; + + //Read the 9-bit raw temperature value + value = read16(reg) >> 7; + + //Sign extend negative numbers + if (value & (1 << 8)) + value |= 0xFF00; + + //Return the temperature in °C + return value * 0.5; +} + +void LM75B::writeAlertTempHelper(char reg, float temp) +{ + //Range limit temp + if (temp < -55.0) + temp = -55.0; + else if (temp > 125.0) + temp = 125.0; + + //Extract and shift the signed integer + short value = temp * 2; + value <<= 7; + + //Send the new value + write16(reg, value); +}
diff -r d2e25cdf9084 -r ca1b1098c77f LM75B/LM75B.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LM75B/LM75B.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,223 @@ +/* LM75B Driver Library + * Copyright (c) 2013 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LM75B_H +#define LM75B_H + +#include "mbed.h" + +/** LM75B class. + * Used for controlling an LM75B temperature sensor connected via I2C. + * + * Example: + * @code + * #include "mbed.h" + * #include "LM75B.h" + * + * //Create an LM75B object at the default address (ADDRESS_0) + * LM75B sensor(p28, p27); + * + * int main() + * { + * //Try to open the LM75B + * if (sensor.open()) { + * printf("Device detected!\n"); + * + * while (1) { + * //Print the current temperature + * printf("Temp = %.3f\n", (float)sensor); + * + * //Sleep for 0.5 seconds + * wait(0.5); + * } + * } else { + * error("Device not detected!\n"); + * } + * } + * @endcode + */ +class LM75B +{ +public: + /** Represents the different I2C address possibilities for the LM75B + */ + enum Address { + ADDRESS_0 = (0x48 << 1), /**< A[2:0] pins = 000 */ + ADDRESS_1 = (0x49 << 1), /**< A[2:0] pins = 001 */ + ADDRESS_2 = (0x4A << 1), /**< A[2:0] pins = 010 */ + ADDRESS_3 = (0x4B << 1), /**< A[2:0] pins = 011 */ + ADDRESS_4 = (0x4C << 1), /**< A[2:0] pins = 100 */ + ADDRESS_5 = (0x4D << 1), /**< A[2:0] pins = 101 */ + ADDRESS_6 = (0x4E << 1), /**< A[2:0] pins = 110 */ + ADDRESS_7 = (0x4F << 1) /**< A[2:0] pins = 111 */ + }; + + /** Represents the power mode of the LM75B + */ + enum PowerMode { + POWER_NORMAL, /**< Chip is enabled and samples every 100ms */ + POWER_SHUTDOWN /**< Chip is in low-power shutdown mode */ + }; + + /** Represents OS pin mode of the LM75B + */ + enum OSMode { + OS_COMPARATOR, /**< OS is asserted when the temperature reaches the alert threshold, and de-asserted when the temperature drops below the alert hysteresis threshold */ + OS_INTERRUPT /**< OS is asserted when the temperature reaches the alert threshold, or drops below the alert hysteresis threshold, and only de-asserted when a register has been read */ + }; + + /** Represents OS pin polarity of the LM75B + */ + enum OSPolarity { + OS_ACTIVE_LOW, /**< OS is a logic low when asserted, and a logic high when de-asserted */ + OS_ACTIVE_HIGH /**< OS is a logic high when asserted, and a logic low when de-asserted */ + }; + + /** Represents OS pin fault queue length of the LM75B + */ + enum OSFaultQueue { + OS_FAULT_QUEUE_1, /**< OS is asserted after 1 fault */ + OS_FAULT_QUEUE_2, /**< OS is asserted after 2 consecutive faults */ + OS_FAULT_QUEUE_4, /**< OS is asserted after 4 consecutive faults */ + OS_FAULT_QUEUE_6 /**< OS is asserted after 6 consecutive faults */ + }; + + /** Create an LM75B object connected to the specified I2C pins with the specified I2C slave address + * + * @param sda The I2C data pin. + * @param scl The I2C clock pin. + * @param addr The I2C slave address (defaults to ADDRESS_0). + * @param hz The I2C bus frequency (defaults to 400kHz). + */ + LM75B(PinName sda, PinName scl, Address addr = ADDRESS_0, int hz = 400000); + + /** Probe for the LM75B and indicate if it's present on the bus + * + * @returns + * 'true' if the device exists on the bus, + * 'false' if the device doesn't exist on the bus. + */ + bool open(); + + /** Get the current power mode of the LM75B + * + * @returns The current power mode as a PowerMode enum. + */ + LM75B::PowerMode powerMode(); + + /** Set the power mode of the LM75B + * + * @param mode The new power mode as a PowerMode enum. + */ + void powerMode(PowerMode mode); + + /** Get the current OS pin mode of the LM75B + * + * @returns The current OS pin mode as an OSMode enum. + */ + LM75B::OSMode osMode(); + + /** Set the OS pin mode of the LM75B + * + * @param mode The new OS pin mode as an OSMode enum. + */ + void osMode(OSMode mode); + + /** Get the current OS pin polarity of the LM75B + * + * @returns The current OS pin polarity as an OSPolarity enum. + */ + LM75B::OSPolarity osPolarity(); + + /** Set the OS pin polarity of the LM75B + * + * @param polarity The new OS pin polarity as an OSPolarity enum. + */ + void osPolarity(OSPolarity polarity); + + /** Get the current OS pin fault queue length of the LM75B + * + * @returns The current OS pin fault queue length as an OSFaultQueue enum. + */ + LM75B::OSFaultQueue osFaultQueue(); + + /** Set the OS pin fault queue length of the LM75B + * + * @param queue The new OS pin fault queue length as an OSFaultQueue enum. + */ + void osFaultQueue(OSFaultQueue queue); + + /** Get the current alert temperature threshold of the LM75B + * + * @returns The current alert temperature threshold in °C. + */ + float alertTemp(); + + /** Set the alert temperature threshold of the LM75B + * + * @param temp The new alert temperature threshold in °C. + */ + void alertTemp(float temp); + + /** Get the current alert temperature hysteresis threshold of the LM75B + * + * @returns The current alert temperature hysteresis threshold in °C. + */ + float alertHyst(); + + /** Set the alert temperature hysteresis threshold of the LM75B + * + * @param temp The new alert temperature hysteresis threshold in °C. + */ + void alertHyst(float temp); + + /** Get the current temperature measurement of the LM75B + * + * @returns The current temperature measurement in °C. + */ + float temp(); + +#ifdef MBED_OPERATORS + /** A shorthand for temp() + * + * @returns The current temperature measurement in °C. + */ + operator float(); +#endif + +private: + //I2C register addresses + enum Register { + REG_TEMP = 0x00, + REG_CONF = 0x01, + REG_THYST = 0x02, + REG_TOS = 0x03 + }; + + //Member variables + I2C m_I2C; + const int m_ADDR; + + //Internal functions + char read8(char reg); + void write8(char reg, char data); + unsigned short read16(char reg); + void write16(char reg, unsigned short data); + float readAlertTempHelper(char reg); + void writeAlertTempHelper(char reg, float temp); +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f MMA7660/.hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA7660/.hgignore Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,19 @@ +syntax: regexp +\.hgignore$ +\.git$ +\.svn$ +\.orig$ +\.msub$ +\.meta$ +\.ctags +\.uvproj$ +\.uvopt$ +\.project$ +\.cproject$ +\.launch$ +\.project$ +\.cproject$ +\.launch$ +Makefile$ +\.ewp$ +\.eww$ \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f MMA7660/MMA7660.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA7660/MMA7660.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,194 @@ +#include "MMA7660.h" + +MMA7660::MMA7660(PinName sda, PinName scl, bool active) : _i2c(sda, scl) +{ + setActive(active); + samplerate = 64; +} + +//Since the MMA lacks a WHO_AM_I register, we can only check if there is a device that answers to the I2C address +bool MMA7660::testConnection( void ) +{ + if (_i2c.write(MMA7660_ADDRESS, NULL, 0) == 0 ) + return true; + else + return false; +} + +void MMA7660::setActive(bool state) +{ + active = state; + char modereg = read(MMA7660_MODE_R); + modereg &= ~(1<<0); + + //If it somehow was in testmode, disable that + if (modereg && (1<<2)) { + modereg &= ~(1<<2); + write(MMA7660_MODE_R, modereg); + } + + modereg += state; + write(MMA7660_MODE_R, modereg); +} + +void MMA7660::readData(int *data) +{ + bool active_old = active; + if (!active) { + setActive(true); + wait(0.012 + 1/samplerate); //Wait until new sample is ready, my experience is that 1/samplerate isnt needed, but datasheet says so + } + + char temp[3]; + bool alert; + + do { + alert = false; + read(MMA7660_XOUT_R, temp, 3); + for (int i = 0; i<3; i++) { + if (temp[i] > 63) + alert = true; + if (temp[i] > 31) + temp[i] += 128+64; + data[i] = (signed char)temp[i]; + } + } while (alert); + + if (!active_old) + setActive(false); +} + + +void MMA7660::readData(float *data) +{ + int intdata[3]; + readData(intdata); + for (int i = 0; i<3; i++) + data[i] = intdata[i]/MMA7660_SENSITIVITY; +} + +float MMA7660::x( void ) +{ + return getSingle(0); +} + +float MMA7660::y( void ) +{ + return getSingle(1); +} + +float MMA7660::z( void ) +{ + return getSingle(2); +} + + +void MMA7660::setSampleRate(int samplerate) +{ + bool active_old = active; + setActive(false); //Not allowed to be active to change anything + int rates[] = {120, 64, 32, 16, 8, 4, 2, 1}; //Alowed samplerates (and their number in array is also number required for MMA) + int sampleLoc = 0, sampleError = 10000, temp; + for (int i = 0; i<8; i++) { + temp = abs( rates[i] - samplerate ); + if (temp<sampleError) { + sampleLoc = i; + sampleError=temp; + } + } + + //Update the samplerate reg + temp = read(MMA7660_SR_R); + temp &= ~0x07; //Awake sample rate are lowest 3 bit + temp |= sampleLoc; + write(MMA7660_SR_R, temp); + this->samplerate = rates[sampleLoc]; + setActive(active_old); //Restore previous active state +} + + +MMA7660::Orientation MMA7660::getSide( void ) +{ + char tiltreg = read(MMA7660_TILT_R); + //We care about 2 LSBs + tiltreg &= 0x03; + if (tiltreg == 0x01) + return MMA7660::Front; + if (tiltreg == 0x02) + return MMA7660::Back; + return MMA7660::Unknown; +} + +MMA7660::Orientation MMA7660::getOrientation( void ) +{ + char tiltreg = read(MMA7660_TILT_R); + + //We care about bit 2, 3 and 4 (counting from zero) + tiltreg &= 0x07<<2; + tiltreg >>= 2; + if (tiltreg == 0x01) + return MMA7660::Left; + if (tiltreg == 0x02) + return MMA7660::Right; + if (tiltreg == 0x05) + return MMA7660::Down; + if (tiltreg == 0x06) + return MMA7660::Up; + return MMA7660::Unknown; +} + + + +////////////////////////////////////////////// +///////////////PRIVATE//////////////////////// +////////////////////////////////////////////// + + +void MMA7660::write(char address, char data) +{ + char temp[2]; + temp[0]=address; + temp[1]=data; + + _i2c.write(MMA7660_ADDRESS, temp, 2); +} + +char MMA7660::read(char address) +{ + char retval; + _i2c.write(MMA7660_ADDRESS, &address, 1, true); + _i2c.read(MMA7660_ADDRESS, &retval, 1); + return retval; +} + +void MMA7660::read(char address, char *data, int length) +{ + _i2c.write(MMA7660_ADDRESS, &address, 1, true); + _i2c.read(MMA7660_ADDRESS, data, length); +} + +float MMA7660::getSingle( int number ) +{ + bool active_old = active; + if (!active) { + setActive(true); + wait(0.012 + 1/samplerate); //Wait until new sample is ready + } + + signed char temp; + bool alert; + + do { + alert = false; + temp = read(MMA7660_XOUT_R + number); + if (temp > 63) + alert = true; + if (temp > 31) + temp += 128+64; + } while (alert); + + if (!active_old) + setActive(false); + + return temp / MMA7660_SENSITIVITY; +} \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f MMA7660/MMA7660.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA7660/MMA7660.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,207 @@ +/* Copyright (c) <year> <copyright holders>, MIT License + * + * 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "mbed.h" + + +#ifndef MMA7660_H +#define MMA7660_H + +#define MMA7660_ADDRESS 0x98 +#define MMA7660_SENSITIVITY 21.33 + +#define MMA7660_XOUT_R 0x00 +#define MMA7660_YOUT_R 0x01 +#define MMA7660_ZOUT_R 0x02 +#define MMA7660_TILT_R 0x03 +#define MMA7660_INT_R 0x06 +#define MMA7660_MODE_R 0x07 +#define MMA7660_SR_R 0x08 + + +/** An interface for the MMA7660 triple axis accelerometer + * + * @code + * //Uses the measured z-acceleration to drive leds 2 and 3 of the mbed + * + * #include "mbed.h" + * #include "MMA7660.h" + * + * MMA7660 MMA(p28, p27); + * + * DigitalOut connectionLed(LED1); + * PwmOut Zaxis_p(LED2); + * PwmOut Zaxis_n(LED3); + * + * int main() { + * if (MMA.testConnection()) + * connectionLed = 1; + * + * while(1) { + * Zaxis_p = MMA.z(); + * Zaxis_n = -MMA.z(); + * } + * + * } + * @endcode + */ +class MMA7660 +{ +public: + /** + * The 6 different orientations and unknown + * + * Up & Down = X-axis + * Right & Left = Y-axis + * Back & Front = Z-axis + * + */ + enum Orientation {Up, Down, + Right, Left, + Back, Front, + Unknown + }; + + /** + * Creates a new MMA7660 object + * + * @param sda - I2C data pin + * @param scl - I2C clock pin + * @param active - true (default) to enable the device, false to keep it standby + */ + MMA7660(PinName sda, PinName scl, bool active = true); + + /** + * Tests if communication is possible with the MMA7660 + * + * Because the MMA7660 lacks a WHO_AM_I register, this function can only check + * if there is an I2C device that responds to the MMA7660 address + * + * @param return - true for successfull connection, false for no connection + */ + bool testConnection( void ); + + /** + * Sets the active state of the MMA7660 + * + * Note: This is unrelated to awake/sleep mode + * + * @param state - true for active, false for standby + */ + void setActive( bool state); + + /** + * Reads acceleration data from the sensor + * + * When the parameter is a pointer to an integer array it will be the raw data. + * When it is a pointer to a float array it will be the acceleration in g's + * + * @param data - pointer to array with length 3 where the acceleration data will be stored, X-Y-Z + */ + void readData( int *data); + void readData( float *data); + + /** + * Get X-data + * + * @param return - X-acceleration in g's + */ + float x( void ); + + /** + * Get Y-data + * + * @param return - Y-acceleration in g's + */ + float y( void ); + + /** + * Get Z-data + * + * @param return - Z-acceleration in g's + */ + float z( void ); + + /** + * Sets the active samplerate + * + * The entered samplerate will be rounded to nearest supported samplerate. + * Supported samplerates are: 120 - 64 - 32 - 16 - 8 - 4 - 2 - 1 samples/second. + * + * @param samplerate - the samplerate that will be set + */ + void setSampleRate(int samplerate); + + /** + * Returns if it is on its front, back, or unknown side + * + * This is read from MMA7760s registers, page 12 of datasheet + * + * @param return - Front, Back or Unknown orientation + */ + Orientation getSide( void ); + + /** + * Returns if it is on it left, right, down or up side + * + * This is read from MMA7760s registers, page 12 of datasheet + * + * @param return - Left, Right, Down, Up or Unknown orientation + */ + Orientation getOrientation ( void ); + + +private: + + /** + * Writes data to the device + * + * @param adress - register address to write to + * @param data - data to write + */ + void write( char address, char data); + + /** + * Read data from the device + * + * @param adress - register address to write to + * @return - data from the register specified by RA + */ + char read( char adress); + + /** + * Read multiple regigsters from the device, more efficient than using multiple normal reads. + * + * @param adress - register address to write to + * @param length - number of bytes to read + * @param data - pointer where the data needs to be written to + */ + void read( char adress, char *data, int length); + + /** + * Reads single axis + */ + float getSingle(int number); + + I2C _i2c; + bool active; + float samplerate; +}; + + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT.lib --- a/MQTT.lib Thu Mar 11 13:56:02 2021 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://mbed.org/teams/mqtt/code/MQTT/#9cff7b6bbd01
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/FP.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/FP.lib Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/sam_grove/code/FP/#3c62ba1807ac
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTAsync.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTAsync.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,609 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#if !defined(MQTTASYNC_H) +#define MQTTASYNC_H + +#include "FP.h" +#include "MQTTPacket.h" +#include "stdio.h" + +namespace MQTT +{ + + +enum QoS { QOS0, QOS1, QOS2 }; + + +struct Message +{ + enum QoS qos; + bool retained; + bool dup; + unsigned short id; + void *payload; + size_t payloadlen; +}; + + +class PacketId +{ +public: + PacketId(); + + int getNext(); + +private: + static const int MAX_PACKET_ID = 65535; + int next; +}; + +typedef void (*messageHandler)(Message*); + +typedef struct limits +{ + int MAX_MQTT_PACKET_SIZE; // + int MAX_MESSAGE_HANDLERS; // each subscription requires a message handler + int MAX_CONCURRENT_OPERATIONS; // each command which runs concurrently can have a result handler, when we are in multi-threaded mode + int command_timeout_ms; + + limits() + { + MAX_MQTT_PACKET_SIZE = 100; + MAX_MESSAGE_HANDLERS = 5; + MAX_CONCURRENT_OPERATIONS = 1; // 1 indicates single-threaded mode - set to >1 for multithreaded mode + command_timeout_ms = 30000; + } +} Limits; + + +/** + * @class Async + * @brief non-blocking, threaded MQTT client API + * @param Network a network class which supports send, receive + * @param Timer a timer class with the methods: + */ +template<class Network, class Timer, class Thread, class Mutex> class Async +{ + +public: + + struct Result + { + /* success or failure result data */ + Async<Network, Timer, Thread, Mutex>* client; + int rc; + }; + + typedef void (*resultHandler)(Result*); + + Async(Network* network, const Limits limits = Limits()); + + typedef struct + { + Async* client; + Network* network; + } connectionLostInfo; + + typedef int (*connectionLostHandlers)(connectionLostInfo*); + + /** Set the connection lost callback - called whenever the connection is lost and we should be connected + * @param clh - pointer to the callback function + */ + void setConnectionLostHandler(connectionLostHandlers clh) + { + connectionLostHandler.attach(clh); + } + + /** Set the default message handling callback - used for any message which does not match a subscription message handler + * @param mh - pointer to the callback function + */ + void setDefaultMessageHandler(messageHandler mh) + { + defaultMessageHandler.attach(mh); + } + + int connect(resultHandler fn, MQTTPacket_connectData* options = 0); + + template<class T> + int connect(void(T::*method)(Result *), MQTTPacket_connectData* options = 0, T *item = 0); // alternative to pass in pointer to member function + + int publish(resultHandler rh, const char* topic, Message* message); + + int subscribe(resultHandler rh, const char* topicFilter, enum QoS qos, messageHandler mh); + + int unsubscribe(resultHandler rh, const char* topicFilter); + + int disconnect(resultHandler rh); + +private: + + void run(void const *argument); + int cycle(int timeout); + int waitfor(int packet_type, Timer& atimer); + int keepalive(); + int findFreeOperation(); + + int decodePacket(int* value, int timeout); + int readPacket(int timeout); + int sendPacket(int length, int timeout); + int deliverMessage(MQTTString* topic, Message* message); + + Thread* thread; + Network* ipstack; + + Limits limits; + + char* buf; + char* readbuf; + + Timer ping_timer, connect_timer; + unsigned int keepAliveInterval; + bool ping_outstanding; + + PacketId packetid; + + typedef FP<void, Result*> resultHandlerFP; + resultHandlerFP connectHandler; + + typedef FP<void, Message*> messageHandlerFP; + struct MessageHandlers + { + const char* topic; + messageHandlerFP fp; + } *messageHandlers; // Message handlers are indexed by subscription topic + + // how many concurrent operations should we allow? Each one will require a function pointer + struct Operations + { + unsigned short id; + resultHandlerFP fp; + const char* topic; // if this is a publish, store topic name in case republishing is required + Message* message; // for publish, + Timer timer; // to check if the command has timed out + } *operations; // result handlers are indexed by packet ids + + static void threadfn(void* arg); + + messageHandlerFP defaultMessageHandler; + + typedef FP<int, connectionLostInfo*> connectionLostFP; + + connectionLostFP connectionLostHandler; + +}; + +} + + +template<class Network, class Timer, class Thread, class Mutex> void MQTT::Async<Network, Timer, Thread, Mutex>::threadfn(void* arg) +{ + ((Async<Network, Timer, Thread, Mutex>*) arg)->run(NULL); +} + + +template<class Network, class Timer, class Thread, class Mutex> MQTT::Async<Network, Timer, Thread, Mutex>::Async(Network* network, Limits limits) : limits(limits), packetid() +{ + this->thread = 0; + this->ipstack = network; + this->ping_timer = Timer(); + this->ping_outstanding = 0; + + // How to make these memory allocations portable? I was hoping to avoid the heap + buf = new char[limits.MAX_MQTT_PACKET_SIZE]; + readbuf = new char[limits.MAX_MQTT_PACKET_SIZE]; + this->operations = new struct Operations[limits.MAX_CONCURRENT_OPERATIONS]; + for (int i = 0; i < limits.MAX_CONCURRENT_OPERATIONS; ++i) + operations[i].id = 0; + this->messageHandlers = new struct MessageHandlers[limits.MAX_MESSAGE_HANDLERS]; + for (int i = 0; i < limits.MAX_MESSAGE_HANDLERS; ++i) + messageHandlers[i].topic = 0; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::sendPacket(int length, int timeout) +{ + int sent = 0; + + while (sent < length) + sent += ipstack->write(&buf[sent], length, timeout); + if (sent == length) + ping_timer.countdown(this->keepAliveInterval); // record the fact that we have successfully sent the packet + return sent; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::decodePacket(int* value, int timeout) +{ + char c; + int multiplier = 1; + int len = 0; + const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4; + + *value = 0; + do + { + int rc = MQTTPACKET_READ_ERROR; + + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) + { + rc = MQTTPACKET_READ_ERROR; /* bad data */ + goto exit; + } + rc = ipstack->read(&c, 1, timeout); + if (rc != 1) + goto exit; + *value += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); +exit: + return len; +} + + +/** + * If any read fails in this method, then we should disconnect from the network, as on reconnect + * the packets can be retried. + * @param timeout the max time to wait for the packet read to complete, in milliseconds + * @return the MQTT packet type, or -1 if none + */ +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::readPacket(int timeout) +{ + int rc = -1; + MQTTHeader header = {0}; + int len = 0; + int rem_len = 0; + + /* 1. read the header byte. This has the packet type in it */ + if (ipstack->read(readbuf, 1, timeout) != 1) + goto exit; + + len = 1; + /* 2. read the remaining length. This is variable in itself */ + decodePacket(&rem_len, timeout); + len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length back into the buffer */ + + /* 3. read the rest of the buffer using a callback to supply the rest of the data */ + if (ipstack->read(readbuf + len, rem_len, timeout) != rem_len) + goto exit; + + header.byte = readbuf[0]; + rc = header.bits.type; +exit: + return rc; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::deliverMessage(MQTTString* topic, Message* message) +{ + int rc = -1; + + // we have to find the right message handler - indexed by topic + for (int i = 0; i < limits.MAX_MESSAGE_HANDLERS; ++i) + { + if (messageHandlers[i].topic != 0 && MQTTPacket_equals(topic, (char*)messageHandlers[i].topic)) + { + messageHandlers[i].fp(message); + rc = 0; + break; + } + } + + return rc; +} + + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::cycle(int timeout) +{ + /* get one piece of work off the wire and one pass through */ + + // read the socket, see what work is due + int packet_type = readPacket(timeout); + + int len, rc; + switch (packet_type) + { + case CONNACK: + if (this->thread) + { + Result res = {this, 0}; + if (MQTTDeserialize_connack(&res.rc, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1) + ; + connectHandler(&res); + connectHandler.detach(); // only invoke the callback once + } + break; + case PUBACK: + if (this->thread) + ; //call resultHandler + case SUBACK: + break; + case PUBLISH: + MQTTString topicName; + Message msg; + rc = MQTTDeserialize_publish((int*)&msg.dup, (int*)&msg.qos, (int*)&msg.retained, (int*)&msg.id, &topicName, + (char**)&msg.payload, (int*)&msg.payloadlen, readbuf, limits.MAX_MQTT_PACKET_SIZE);; + if (msg.qos == QOS0) + deliverMessage(&topicName, &msg); + break; + case PUBREC: + int type, dup, mypacketid; + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1) + ; + // must lock this access against the application thread, if we are multi-threaded + len = MQTTSerialize_ack(buf, limits.MAX_MQTT_PACKET_SIZE, PUBREL, 0, mypacketid); + rc = sendPacket(len, timeout); // send the PUBREL packet + if (rc != len) + goto exit; // there was a problem + + break; + case PUBCOMP: + break; + case PINGRESP: + ping_outstanding = false; + break; + } + keepalive(); +exit: + return packet_type; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::keepalive() +{ + int rc = 0; + + if (keepAliveInterval == 0) + goto exit; + + if (ping_timer.expired()) + { + if (ping_outstanding) + rc = -1; + else + { + int len = MQTTSerialize_pingreq(buf, limits.MAX_MQTT_PACKET_SIZE); + rc = sendPacket(len, 1000); // send the ping packet + if (rc != len) + rc = -1; // indicate there's a problem + else + ping_outstanding = true; + } + } + +exit: + return rc; +} + + +template<class Network, class Timer, class Thread, class Mutex> void MQTT::Async<Network, Timer, Thread, Mutex>::run(void const *argument) +{ + while (true) + cycle(ping_timer.left_ms()); +} + + +// only used in single-threaded mode where one command at a time is in process +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::waitfor(int packet_type, Timer& atimer) +{ + int rc = -1; + + do + { + if (atimer.expired()) + break; // we timed out + } + while ((rc = cycle(atimer.left_ms())) != packet_type); + + return rc; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::connect(resultHandler resultHandler, MQTTPacket_connectData* options) +{ + connect_timer.countdown(limits.command_timeout_ms); + + MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer; + if (options == 0) + options = &default_options; // set default options if none were supplied + + this->keepAliveInterval = options->keepAliveInterval; + ping_timer.countdown(this->keepAliveInterval); + int len = MQTTSerialize_connect(buf, limits.MAX_MQTT_PACKET_SIZE, options); + int rc = sendPacket(len, connect_timer.left_ms()); // send the connect packet + if (rc != len) + goto exit; // there was a problem + + if (resultHandler == 0) // wait until the connack is received + { + // this will be a blocking call, wait for the connack + if (waitfor(CONNACK, connect_timer) == CONNACK) + { + int connack_rc = -1; + if (MQTTDeserialize_connack(&connack_rc, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1) + rc = connack_rc; + } + } + else + { + // set connect response callback function + connectHandler.attach(resultHandler); + + // start background thread + this->thread = new Thread((void (*)(void const *argument))&MQTT::Async<Network, Timer, Thread, Mutex>::threadfn, (void*)this); + } + +exit: + return rc; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::findFreeOperation() +{ + int found = -1; + for (int i = 0; i < limits.MAX_CONCURRENT_OPERATIONS; ++i) + { + if (operations[i].id == 0) + { + found = i; + break; + } + } + return found; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::subscribe(resultHandler resultHandler, const char* topicFilter, enum QoS qos, messageHandler messageHandler) +{ + int index = 0; + if (this->thread) + index = findFreeOperation(); + Timer& atimer = operations[index].timer; + + atimer.countdown(limits.command_timeout_ms); + MQTTString topic = {(char*)topicFilter, 0, 0}; + + int len = MQTTSerialize_subscribe(buf, limits.MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic, (int*)&qos); + int rc = sendPacket(len, atimer.left_ms()); // send the subscribe packet + if (rc != len) + goto exit; // there was a problem + + /* wait for suback */ + if (resultHandler == 0) + { + // this will block + if (waitfor(SUBACK, atimer) == SUBACK) + { + int count = 0, grantedQoS = -1, mypacketid; + if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1) + rc = grantedQoS; // 0, 1, 2 or 0x80 + if (rc != 0x80) + { + for (int i = 0; i < limits.MAX_MESSAGE_HANDLERS; ++i) + { + if (messageHandlers[i].topic == 0) + { + messageHandlers[i].topic = topicFilter; + messageHandlers[i].fp.attach(messageHandler); + rc = 0; + break; + } + } + } + } + } + else + { + // set subscribe response callback function + + } + +exit: + return rc; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::unsubscribe(resultHandler resultHandler, const char* topicFilter) +{ + int index = 0; + if (this->thread) + index = findFreeOperation(); + Timer& atimer = operations[index].timer; + + atimer.countdown(limits.command_timeout_ms); + MQTTString topic = {(char*)topicFilter, 0, 0}; + + int len = MQTTSerialize_unsubscribe(buf, limits.MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic); + int rc = sendPacket(len, atimer.left_ms()); // send the subscribe packet + if (rc != len) + goto exit; // there was a problem + + // set unsubscribe response callback function + + +exit: + return rc; +} + + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::publish(resultHandler resultHandler, const char* topicName, Message* message) +{ + int index = 0; + if (this->thread) + index = findFreeOperation(); + Timer& atimer = operations[index].timer; + + atimer.countdown(limits.command_timeout_ms); + MQTTString topic = {(char*)topicName, 0, 0}; + + if (message->qos == QOS1 || message->qos == QOS2) + message->id = packetid.getNext(); + + int len = MQTTSerialize_publish(buf, limits.MAX_MQTT_PACKET_SIZE, 0, message->qos, message->retained, message->id, topic, (char*)message->payload, message->payloadlen); + int rc = sendPacket(len, atimer.left_ms()); // send the subscribe packet + if (rc != len) + { + led2 = 1; + goto exit; // there was a problem + } + /* wait for acks */ + if (resultHandler == 0) + { + if (message->qos == QOS1) + { + if (waitfor(PUBACK, atimer) == PUBACK) + { + int type, dup, mypacketid; + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1) + rc = 0; + } + } + else if (message->qos == QOS2) + { + if (waitfor(PUBCOMP, atimer) == PUBCOMP) + { + int type, dup, mypacketid; + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1) + rc = 0; + } + + } + } + else + { + // set publish response callback function + + } + +exit: + return rc; +} + + +template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::disconnect(resultHandler resultHandler) +{ + Timer timer = Timer(limits.command_timeout_ms); // we might wait for incomplete incoming publishes to complete + int len = MQTTSerialize_disconnect(buf, limits.MAX_MQTT_PACKET_SIZE); + int rc = sendPacket(len, timer.left_ms()); // send the disconnect packet + + return (rc == len) ? 0 : -1; +} + + + +#endif \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTClient.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,1051 @@ +/******************************************************************************* + * Copyright (c) 2014, 2017 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Ian Craggs - fix for bug 458512 - QoS 2 messages + * Ian Craggs - fix for bug 460389 - send loop uses wrong length + * Ian Craggs - fix for bug 464169 - clearing subscriptions + * Ian Craggs - fix for bug 464551 - enums and ints can be different size + * Mark Sonnentag - fix for bug 475204 - inefficient instantiation of Timer + * Ian Craggs - fix for bug 475749 - packetid modified twice + * Ian Craggs - add ability to set message handler separately #6 + *******************************************************************************/ + +#if !defined(MQTTCLIENT_H) +#define MQTTCLIENT_H + +#include "FP.h" +#include "MQTTPacket.h" +#include <stdio.h> +#include "MQTTLogging.h" + +#if !defined(MQTTCLIENT_QOS1) + #define MQTTCLIENT_QOS1 1 +#endif +#if !defined(MQTTCLIENT_QOS2) + #define MQTTCLIENT_QOS2 0 +#endif + +namespace MQTT +{ + + +enum QoS { QOS0, QOS1, QOS2 }; + +// all failure return codes must be negative +enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 }; + + +struct Message +{ + enum QoS qos; + bool retained; + bool dup; + unsigned short id; + void *payload; + size_t payloadlen; +}; + + +struct MessageData +{ + MessageData(MQTTString &aTopicName, struct Message &aMessage) : message(aMessage), topicName(aTopicName) + { } + + struct Message &message; + MQTTString &topicName; +}; + + +struct connackData +{ + int rc; + bool sessionPresent; +}; + + +struct subackData +{ + int grantedQoS; +}; + + +class PacketId +{ +public: + PacketId() + { + next = 0; + } + + int getNext() + { + return next = (next == MAX_PACKET_ID) ? 1 : next + 1; + } + +private: + static const int MAX_PACKET_ID = 65535; + int next; +}; + + +/** + * @class Client + * @brief blocking, non-threaded MQTT client API + * + * This version of the API blocks on all method calls, until they are complete. This means that only one + * MQTT request can be in process at any one time. + * @param Network a network class which supports send, receive + * @param Timer a timer class with the methods: + */ +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE = 200, int MAX_MESSAGE_HANDLERS = 5> +class Client +{ + +public: + + typedef void (*messageHandler)(MessageData&); + + /** Construct the client + * @param network - pointer to an instance of the Network class - must be connected to the endpoint + * before calling MQTT connect + * @param limits an instance of the Limit class - to alter limits as required + */ + Client(Network& network, unsigned int command_timeout_ms = 30000); + + /** Set the default message handling callback - used for any message which does not match a subscription message handler + * @param mh - pointer to the callback function. Set to 0 to remove. + */ + void setDefaultMessageHandler(messageHandler mh) + { + if (mh != 0) + defaultMessageHandler.attach(mh); + else + defaultMessageHandler.detach(); + } + + /** Set a message handling callback. This can be used outside of the the subscribe method. + * @param topicFilter - a topic pattern which can include wildcards + * @param mh - pointer to the callback function. If 0, removes the callback if any + */ + int setMessageHandler(const char* topicFilter, messageHandler mh); + + /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack + * The nework object must be connected to the network endpoint before calling this + * Default connect options are used + * @return success code - + */ + int connect(); + + /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack + * The nework object must be connected to the network endpoint before calling this + * @param options - connect options + * @return success code - + */ + int connect(MQTTPacket_connectData& options); + + /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack + * The nework object must be connected to the network endpoint before calling this + * @param options - connect options + * @param connackData - connack data to be returned + * @return success code - + */ + int connect(MQTTPacket_connectData& options, connackData& data); + + /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs + * @param topic - the topic to publish to + * @param message - the message to send + * @return success code - + */ + int publish(const char* topicName, Message& message); + + /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs + * @param topic - the topic to publish to + * @param payload - the data to send + * @param payloadlen - the length of the data + * @param qos - the QoS to send the publish at + * @param retained - whether the message should be retained + * @return success code - + */ + int publish(const char* topicName, void* payload, size_t payloadlen, enum QoS qos = QOS0, bool retained = false); + + /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs + * @param topic - the topic to publish to + * @param payload - the data to send + * @param payloadlen - the length of the data + * @param id - the packet id used - returned + * @param qos - the QoS to send the publish at + * @param retained - whether the message should be retained + * @return success code - + */ + int publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos = QOS1, bool retained = false); + + /** MQTT Subscribe - send an MQTT subscribe packet and wait for the suback + * @param topicFilter - a topic pattern which can include wildcards + * @param qos - the MQTT QoS to subscribe at + * @param mh - the callback function to be invoked when a message is received for this subscription + * @return success code - + */ + int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh); + + /** MQTT Subscribe - send an MQTT subscribe packet and wait for the suback + * @param topicFilter - a topic pattern which can include wildcards + * @param qos - the MQTT QoS to subscribe at© + * @param mh - the callback function to be invoked when a message is received for this subscription + * @param + * @return success code - + */ + int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh, subackData &data); + + /** MQTT Unsubscribe - send an MQTT unsubscribe packet and wait for the unsuback + * @param topicFilter - a topic pattern which can include wildcards + * @return success code - + */ + int unsubscribe(const char* topicFilter); + + /** MQTT Disconnect - send an MQTT disconnect packet, and clean up any state + * @return success code - + */ + int disconnect(); + + /** A call to this API must be made within the keepAlive interval to keep the MQTT connection alive + * yield can be called if no other MQTT operation is needed. This will also allow messages to be + * received. + * @param timeout_ms the time to wait, in milliseconds + * @return success code - on failure, this means the client has disconnected + */ + int yield(unsigned long timeout_ms = 1000L); + + /** Is the client connected? + * @return flag - is the client connected or not? + */ + bool isConnected() + { + return isconnected; + } + +private: + + void closeSession(); + void cleanSession(); + int cycle(Timer& timer); + int waitfor(int packet_type, Timer& timer); + int keepalive(); + int publish(int len, Timer& timer, enum QoS qos); + + int decodePacket(int* value, int timeout); + int readPacket(Timer& timer); + int sendPacket(int length, Timer& timer); + int deliverMessage(MQTTString& topicName, Message& message); + bool isTopicMatched(char* topicFilter, MQTTString& topicName); + + Network& ipstack; + unsigned long command_timeout_ms; + + unsigned char sendbuf[MAX_MQTT_PACKET_SIZE]; + unsigned char readbuf[MAX_MQTT_PACKET_SIZE]; + + Timer last_sent, last_received; + unsigned int keepAliveInterval; + bool ping_outstanding; + bool cleansession; + + PacketId packetid; + + struct MessageHandlers + { + const char* topicFilter; + FP<void, MessageData&> fp; + } messageHandlers[MAX_MESSAGE_HANDLERS]; // Message handlers are indexed by subscription topic + + FP<void, MessageData&> defaultMessageHandler; + + bool isconnected; + +#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2 + unsigned char pubbuf[MAX_MQTT_PACKET_SIZE]; // store the last publish for sending on reconnect + int inflightLen; + unsigned short inflightMsgid; + enum QoS inflightQoS; +#endif + +#if MQTTCLIENT_QOS2 + bool pubrel; + #if !defined(MAX_INCOMING_QOS2_MESSAGES) + #define MAX_INCOMING_QOS2_MESSAGES 10 + #endif + unsigned short incomingQoS2messages[MAX_INCOMING_QOS2_MESSAGES]; + bool isQoS2msgidFree(unsigned short id); + bool useQoS2msgid(unsigned short id); + void freeQoS2msgid(unsigned short id); +#endif + +}; + +} + + +template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS> +void MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::cleanSession() +{ + for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) + messageHandlers[i].topicFilter = 0; + +#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2 + inflightMsgid = 0; + inflightQoS = QOS0; +#endif + +#if MQTTCLIENT_QOS2 + pubrel = false; + for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i) + incomingQoS2messages[i] = 0; +#endif +} + + +template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS> +void MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::closeSession() +{ + ping_outstanding = false; + isconnected = false; + if (cleansession) + cleanSession(); +} + + +template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS> +MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::Client(Network& network, unsigned int command_timeout_ms) : ipstack(network), packetid() +{ + this->command_timeout_ms = command_timeout_ms; + cleansession = true; + closeSession(); +} + + +#if MQTTCLIENT_QOS2 +template<class Network, class Timer, int a, int b> +bool MQTT::Client<Network, Timer, a, b>::isQoS2msgidFree(unsigned short id) +{ + for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i) + { + if (incomingQoS2messages[i] == id) + return false; + } + return true; +} + + +template<class Network, class Timer, int a, int b> +bool MQTT::Client<Network, Timer, a, b>::useQoS2msgid(unsigned short id) +{ + for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i) + { + if (incomingQoS2messages[i] == 0) + { + incomingQoS2messages[i] = id; + return true; + } + } + return false; +} + + +template<class Network, class Timer, int a, int b> +void MQTT::Client<Network, Timer, a, b>::freeQoS2msgid(unsigned short id) +{ + for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i) + { + if (incomingQoS2messages[i] == id) + { + incomingQoS2messages[i] = 0; + return; + } + } +} +#endif + + +template<class Network, class Timer, int a, int b> +int MQTT::Client<Network, Timer, a, b>::sendPacket(int length, Timer& timer) +{ + int rc = FAILURE, + sent = 0; + + while (sent < length) + { + rc = ipstack.write(&sendbuf[sent], length - sent, timer.left_ms()); + if (rc < 0) // there was an error writing the data + break; + sent += rc; + if (timer.expired()) // only check expiry after at least one attempt to write + break; + } + if (sent == length) + { + if (this->keepAliveInterval > 0) + last_sent.countdown(this->keepAliveInterval); // record the fact that we have successfully sent the packet + rc = SUCCESS; + } + else + rc = FAILURE; + +#if defined(MQTT_DEBUG) + char printbuf[150]; + DEBUG("Rc %d from sending packet %s\r\n", rc, + MQTTFormat_toServerString(printbuf, sizeof(printbuf), sendbuf, length)); +#endif + return rc; +} + + +template<class Network, class Timer, int a, int b> +int MQTT::Client<Network, Timer, a, b>::decodePacket(int* value, int timeout) +{ + unsigned char c; + int multiplier = 1; + int len = 0; + const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4; + + *value = 0; + do + { + int rc = MQTTPACKET_READ_ERROR; + + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) + { + rc = MQTTPACKET_READ_ERROR; /* bad data */ + goto exit; + } + rc = ipstack.read(&c, 1, timeout); + if (rc != 1) + goto exit; + *value += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); +exit: + return len; +} + + +/** + * If any read fails in this method, then we should disconnect from the network, as on reconnect + * the packets can be retried. + * @param timeout the max time to wait for the packet read to complete, in milliseconds + * @return the MQTT packet type, 0 if none, -1 if error + */ +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::readPacket(Timer& timer) +{ + int rc = FAILURE; + MQTTHeader header = {0}; + int len = 0; + int rem_len = 0; + + /* 1. read the header byte. This has the packet type in it */ + rc = ipstack.read(readbuf, 1, timer.left_ms()); + if (rc != 1) + goto exit; + + len = 1; + /* 2. read the remaining length. This is variable in itself */ + decodePacket(&rem_len, timer.left_ms()); + len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length into the buffer */ + + if (rem_len > (MAX_MQTT_PACKET_SIZE - len)) + { + rc = BUFFER_OVERFLOW; + goto exit; + } + + /* 3. read the rest of the buffer using a callback to supply the rest of the data */ + if (rem_len > 0 && (ipstack.read(readbuf + len, rem_len, timer.left_ms()) != rem_len)) + goto exit; + + header.byte = readbuf[0]; + rc = header.bits.type; + if (this->keepAliveInterval > 0) + last_received.countdown(this->keepAliveInterval); // record the fact that we have successfully received a packet +exit: + +#if defined(MQTT_DEBUG) + if (rc >= 0) + { + char printbuf[50]; + DEBUG("Rc %d receiving packet %s\r\n", rc, + MQTTFormat_toClientString(printbuf, sizeof(printbuf), readbuf, len)); + } +#endif + return rc; +} + + +// assume topic filter and name is in correct format +// # can only be at end +// + and # can only be next to separator +template<class Network, class Timer, int a, int b> +bool MQTT::Client<Network, Timer, a, b>::isTopicMatched(char* topicFilter, MQTTString& topicName) +{ + char* curf = topicFilter; + char* curn = topicName.lenstring.data; + char* curn_end = curn + topicName.lenstring.len; + + while (*curf && curn < curn_end) + { + if (*curn == '/' && *curf != '/') + break; + if (*curf != '+' && *curf != '#' && *curf != *curn) + break; + if (*curf == '+') + { // skip until we meet the next separator, or end of string + char* nextpos = curn + 1; + while (nextpos < curn_end && *nextpos != '/') + nextpos = ++curn + 1; + } + else if (*curf == '#') + curn = curn_end - 1; // skip until end of string + curf++; + curn++; + }; + + return (curn == curn_end) && (*curf == '\0'); +} + + + +template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS> +int MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::deliverMessage(MQTTString& topicName, Message& message) +{ + int rc = FAILURE; + + // we have to find the right message handler - indexed by topic + for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) + { + if (messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(&topicName, (char*)messageHandlers[i].topicFilter) || + isTopicMatched((char*)messageHandlers[i].topicFilter, topicName))) + { + if (messageHandlers[i].fp.attached()) + { + MessageData md(topicName, message); + messageHandlers[i].fp(md); + rc = SUCCESS; + } + } + } + + if (rc == FAILURE && defaultMessageHandler.attached()) + { + MessageData md(topicName, message); + defaultMessageHandler(md); + rc = SUCCESS; + } + + return rc; +} + + + +template<class Network, class Timer, int a, int b> +int MQTT::Client<Network, Timer, a, b>::yield(unsigned long timeout_ms) +{ + int rc = SUCCESS; + Timer timer; + + timer.countdown_ms(timeout_ms); + while (!timer.expired()) + { + if (cycle(timer) < 0) + { + rc = FAILURE; + break; + } + } + + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::cycle(Timer& timer) +{ + // get one piece of work off the wire and one pass through + int len = 0, + rc = SUCCESS; + + int packet_type = readPacket(timer); // read the socket, see what work is due + + switch (packet_type) + { + default: + // no more data to read, unrecoverable. Or read packet fails due to unexpected network error + rc = packet_type; + goto exit; + case 0: // timed out reading packet + break; + case CONNACK: + case PUBACK: + case SUBACK: + break; + case PUBLISH: + { + MQTTString topicName = MQTTString_initializer; + Message msg; + int intQoS; + msg.payloadlen = 0; /* this is a size_t, but deserialize publish sets this as int */ + if (MQTTDeserialize_publish((unsigned char*)&msg.dup, &intQoS, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName, + (unsigned char**)&msg.payload, (int*)&msg.payloadlen, readbuf, MAX_MQTT_PACKET_SIZE) != 1) + goto exit; + msg.qos = (enum QoS)intQoS; +#if MQTTCLIENT_QOS2 + if (msg.qos != QOS2) +#endif + deliverMessage(topicName, msg); +#if MQTTCLIENT_QOS2 + else if (isQoS2msgidFree(msg.id)) + { + if (useQoS2msgid(msg.id)) + deliverMessage(topicName, msg); + else + WARN("Maximum number of incoming QoS2 messages exceeded"); + } +#endif +#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2 + if (msg.qos != QOS0) + { + if (msg.qos == QOS1) + len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBACK, 0, msg.id); + else if (msg.qos == QOS2) + len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREC, 0, msg.id); + if (len <= 0) + rc = FAILURE; + else + rc = sendPacket(len, timer); + if (rc == FAILURE) + goto exit; // there was a problem + } + break; +#endif + } +#if MQTTCLIENT_QOS2 + case PUBREC: + case PUBREL: + unsigned short mypacketid; + unsigned char dup, type; + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1) + rc = FAILURE; + else if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, + (packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0) + rc = FAILURE; + else if ((rc = sendPacket(len, timer)) != SUCCESS) // send the PUBREL packet + rc = FAILURE; // there was a problem + if (rc == FAILURE) + goto exit; // there was a problem + if (packet_type == PUBREL) + freeQoS2msgid(mypacketid); + break; + + case PUBCOMP: + break; +#endif + case PINGRESP: + ping_outstanding = false; + break; + } + + if (keepalive() != SUCCESS) + //check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULT + rc = FAILURE; + +exit: + if (rc == SUCCESS) + rc = packet_type; + else if (isconnected) + closeSession(); + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::keepalive() +{ + int rc = SUCCESS; + static Timer ping_sent; + + if (keepAliveInterval == 0) + goto exit; + + if (ping_outstanding) + { + if (ping_sent.expired()) + { + rc = FAILURE; // session failure + #if defined(MQTT_DEBUG) + DEBUG("PINGRESP not received in keepalive interval\r\n"); + #endif + } + } + else if (last_sent.expired() || last_received.expired()) + { + Timer timer(1000); + int len = MQTTSerialize_pingreq(sendbuf, MAX_MQTT_PACKET_SIZE); + if (len > 0 && (rc = sendPacket(len, timer)) == SUCCESS) // send the ping packet + { + ping_outstanding = true; + ping_sent.countdown(this->keepAliveInterval); + } + } +exit: + return rc; +} + + +// only used in single-threaded mode where one command at a time is in process +template<class Network, class Timer, int a, int b> +int MQTT::Client<Network, Timer, a, b>::waitfor(int packet_type, Timer& timer) +{ + int rc = FAILURE; + + do + { + if (timer.expired()) + break; // we timed out + rc = cycle(timer); + } + while (rc != packet_type && rc >= 0); + + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect(MQTTPacket_connectData& options, connackData& data) +{ + Timer connect_timer(command_timeout_ms); + int rc = FAILURE; + int len = 0; + + if (isconnected) // don't send connect packet again if we are already connected + goto exit; + + this->keepAliveInterval = options.keepAliveInterval; + this->cleansession = options.cleansession; + if ((len = MQTTSerialize_connect(sendbuf, MAX_MQTT_PACKET_SIZE, &options)) <= 0) + goto exit; + if ((rc = sendPacket(len, connect_timer)) != SUCCESS) // send the connect packet + goto exit; // there was a problem + + if (this->keepAliveInterval > 0) + last_received.countdown(this->keepAliveInterval); + // this will be a blocking call, wait for the connack + if (waitfor(CONNACK, connect_timer) == CONNACK) + { + data.rc = 0; + data.sessionPresent = false; + if (MQTTDeserialize_connack((unsigned char*)&data.sessionPresent, + (unsigned char*)&data.rc, readbuf, MAX_MQTT_PACKET_SIZE) == 1) + rc = data.rc; + else + rc = FAILURE; + } + else + rc = FAILURE; + +#if MQTTCLIENT_QOS2 + // resend any inflight publish + if (inflightMsgid > 0 && inflightQoS == QOS2 && pubrel) + { + if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREL, 0, inflightMsgid)) <= 0) + rc = FAILURE; + else + rc = publish(len, connect_timer, inflightQoS); + } + else +#endif +#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2 + if (inflightMsgid > 0) + { + memcpy(sendbuf, pubbuf, MAX_MQTT_PACKET_SIZE); + rc = publish(inflightLen, connect_timer, inflightQoS); + } +#endif + +exit: + if (rc == SUCCESS) + { + isconnected = true; + ping_outstanding = false; + } + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect(MQTTPacket_connectData& options) +{ + connackData data; + return connect(options, data); +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect() +{ + MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer; + return connect(default_options); +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::setMessageHandler(const char* topicFilter, messageHandler messageHandler) +{ + int rc = FAILURE; + int i = -1; + + // first check for an existing matching slot + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) + { + if (messageHandlers[i].topicFilter != 0 && strcmp(messageHandlers[i].topicFilter, topicFilter) == 0) + { + if (messageHandler == 0) // remove existing + { + messageHandlers[i].topicFilter = 0; + messageHandlers[i].fp.detach(); + } + rc = SUCCESS; // return i when adding new subscription + break; + } + } + // if no existing, look for empty slot (unless we are removing) + if (messageHandler != 0) { + if (rc == FAILURE) + { + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) + { + if (messageHandlers[i].topicFilter == 0) + { + rc = SUCCESS; + break; + } + } + } + if (i < MAX_MESSAGE_HANDLERS) + { + messageHandlers[i].topicFilter = topicFilter; + messageHandlers[i].fp.attach(messageHandler); + } + } + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::subscribe(const char* topicFilter, + enum QoS qos, messageHandler messageHandler, subackData& data) +{ + int rc = FAILURE; + Timer timer(command_timeout_ms); + int len = 0; + MQTTString topic = {(char*)topicFilter, {0, 0}}; + + if (!isconnected) + goto exit; + + len = MQTTSerialize_subscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic, (int*)&qos); + if (len <= 0) + goto exit; + if ((rc = sendPacket(len, timer)) != SUCCESS) // send the subscribe packet + goto exit; // there was a problem + + if (waitfor(SUBACK, timer) == SUBACK) // wait for suback + { + int count = 0; + unsigned short mypacketid; + data.grantedQoS = 0; + if (MQTTDeserialize_suback(&mypacketid, 1, &count, &data.grantedQoS, readbuf, MAX_MQTT_PACKET_SIZE) == 1) + { + if (data.grantedQoS != 0x80) + rc = setMessageHandler(topicFilter, messageHandler); + } + } + else + rc = FAILURE; + +exit: + if (rc == FAILURE) + closeSession(); + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::subscribe(const char* topicFilter, enum QoS qos, messageHandler messageHandler) +{ + subackData data; + return subscribe(topicFilter, qos, messageHandler, data); +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::unsubscribe(const char* topicFilter) +{ + int rc = FAILURE; + Timer timer(command_timeout_ms); + MQTTString topic = {(char*)topicFilter, {0, 0}}; + int len = 0; + + if (!isconnected) + goto exit; + + if ((len = MQTTSerialize_unsubscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic)) <= 0) + goto exit; + if ((rc = sendPacket(len, timer)) != SUCCESS) // send the unsubscribe packet + goto exit; // there was a problem + + if (waitfor(UNSUBACK, timer) == UNSUBACK) + { + unsigned short mypacketid; // should be the same as the packetid above + if (MQTTDeserialize_unsuback(&mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) == 1) + { + // remove the subscription message handler associated with this topic, if there is one + setMessageHandler(topicFilter, 0); + } + } + else + rc = FAILURE; + +exit: + if (rc != SUCCESS) + closeSession(); + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(int len, Timer& timer, enum QoS qos) +{ + int rc; + + if ((rc = sendPacket(len, timer)) != SUCCESS) // send the publish packet + goto exit; // there was a problem + +#if MQTTCLIENT_QOS1 + if (qos == QOS1) + { + if (waitfor(PUBACK, timer) == PUBACK) + { + unsigned short mypacketid; + unsigned char dup, type; + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1) + rc = FAILURE; + else if (inflightMsgid == mypacketid) + inflightMsgid = 0; + } + else + rc = FAILURE; + } +#endif +#if MQTTCLIENT_QOS2 + else if (qos == QOS2) + { + if (waitfor(PUBCOMP, timer) == PUBCOMP) + { + unsigned short mypacketid; + unsigned char dup, type; + if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1) + rc = FAILURE; + else if (inflightMsgid == mypacketid) + inflightMsgid = 0; + } + else + rc = FAILURE; + } +#endif + +exit: + if (rc != SUCCESS) + closeSession(); + return rc; +} + + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos, bool retained) +{ + int rc = FAILURE; + Timer timer(command_timeout_ms); + MQTTString topicString = MQTTString_initializer; + int len = 0; + + if (!isconnected) + goto exit; + + topicString.cstring = (char*)topicName; + +#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2 + if (qos == QOS1 || qos == QOS2) + id = packetid.getNext(); +#endif + + len = MQTTSerialize_publish(sendbuf, MAX_MQTT_PACKET_SIZE, 0, qos, retained, id, + topicString, (unsigned char*)payload, payloadlen); + if (len <= 0) + goto exit; + +#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2 + if (!cleansession) + { + memcpy(pubbuf, sendbuf, len); + inflightMsgid = id; + inflightLen = len; + inflightQoS = qos; +#if MQTTCLIENT_QOS2 + pubrel = false; +#endif + } +#endif + + rc = publish(len, timer, qos); +exit: + return rc; +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, void* payload, size_t payloadlen, enum QoS qos, bool retained) +{ + unsigned short id = 0; // dummy - not used for anything + return publish(topicName, payload, payloadlen, id, qos, retained); +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, Message& message) +{ + return publish(topicName, message.payload, message.payloadlen, message.qos, message.retained); +} + + +template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b> +int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::disconnect() +{ + int rc = FAILURE; + Timer timer(command_timeout_ms); // we might wait for incomplete incoming publishes to complete + int len = MQTTSerialize_disconnect(sendbuf, MAX_MQTT_PACKET_SIZE); + if (len > 0) + rc = sendPacket(len, timer); // send the disconnect packet + closeSession(); + return rc; +} + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTEthernet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTEthernet.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,29 @@ + +#if !defined(MQTTETHERNET_H) +#define MQTTETHERNET_H + +#include "MQTTmbed.h" +#include "EthernetInterface.h" +#include "MQTTSocket.h" + +class MQTTEthernet : public MQTTSocket +{ +public: + MQTTEthernet() : MQTTSocket(ð) + { + eth.connect(); + } + + EthernetInterface& getEth() + { + return eth; + } + +private: + + EthernetInterface eth; + +}; + + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTLogging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTLogging.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,39 @@ +#if !defined(MQTT_LOGGING_H) +#define MQTT_LOGGING_H + +#define STREAM stdout +#if !defined(DEBUG) +#define DEBUG(...) \ + {\ + fprintf(STREAM, "DEBUG: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + fprintf(STREAM, ##__VA_ARGS__); \ + fflush(STREAM); \ + } +#endif +#if !defined(LOG) +#define LOG(...) \ + {\ + fprintf(STREAM, "LOG: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + fprintf(STREAM, ##__VA_ARGS__); \ + fflush(STREAM); \ + } +#endif +#if !defined(WARN) +#define WARN(...) \ + { \ + fprintf(STREAM, "WARN: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + fprintf(STREAM, ##__VA_ARGS__); \ + fflush(STREAM); \ + } +#endif +#if !defined(ERROR) +#define ERROR(...) \ + { \ + fprintf(STREAM, "ERROR: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \ + fprintf(STREAM, ##__VA_ARGS__); \ + fflush(STREAM); \ + exit(1); \ + } +#endif + +#endif \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTPacket.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTPacket.lib Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/mqtt/code/MQTTPacket/#aedcaf7984d5
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTSocket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTSocket.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,103 @@ +#if !defined(MQTTSOCKET_H) +#define MQTTSOCKET_H + +#include "MQTTmbed.h" +#include <EthernetInterface.h> +#include <Timer.h> + +class MQTTSocket +{ +public: + MQTTSocket(EthernetInterface *anet) + { + net = anet; + open = false; + } + + int connect(char* hostname, int port, int timeout=1000) + { + if (open) + disconnect(); + nsapi_error_t rc = mysock.open(net); + open = true; + mysock.set_blocking(true); + mysock.set_timeout((unsigned int)timeout); + rc = mysock.connect(hostname, port); + mysock.set_blocking(false); // blocking timeouts seem not to work + return rc; + } + + // common read/write routine, avoiding blocking timeouts + int common(unsigned char* buffer, int len, int timeout, bool read) + { + timer.start(); + mysock.set_blocking(false); // blocking timeouts seem not to work + int bytes = 0; + bool first = true; + do + { + if (first) + first = false; + else + wait_ms(timeout < 100 ? timeout : 100); + int rc; + if (read) + { + mysock.set_timeout(timeout); + rc = mysock.recv((char*)buffer, len); + mysock.set_timeout(0); + return rc; + } + //rc = mysock.recv((char*)buffer, len); + else + rc = mysock.send((char*)buffer, len); + if (rc < 0) + { + if (rc != NSAPI_ERROR_WOULD_BLOCK) + { + bytes = -1; + break; + } + } + else + bytes += rc; + } + while (bytes < len && timer.read_ms() < timeout); + timer.stop(); + return bytes; + } + + /* returns the number of bytes read, which could be 0. + -1 if there was an error on the socket + */ + int read(unsigned char* buffer, int len, int timeout) + { + return common(buffer, len, timeout, true); + } + + int write(unsigned char* buffer, int len, int timeout) + { + return common(buffer, len, timeout, false); + } + + int disconnect() + { + open = false; + return mysock.close(); + } + + /*bool is_connected() + { + return mysock.is_connected(); + }*/ + +private: + + bool open; + TCPSocket mysock; + EthernetInterface *net; + Timer timer; + +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f MQTT/MQTTmbed.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTmbed.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,48 @@ +#if !defined(MQTT_MBED_H) +#define MQTT_MBED_H + +#include "mbed.h" + +class Countdown +{ +public: + Countdown() : t() + { + + } + + Countdown(int ms) : t() + { + countdown_ms(ms); + } + + + bool expired() + { + return t.read_ms() >= interval_end_ms; + } + + void countdown_ms(unsigned long ms) + { + t.stop(); + interval_end_ms = ms; + t.reset(); + t.start(); + } + + void countdown(int seconds) + { + countdown_ms((unsigned long)seconds * 1000L); + } + + int left_ms() + { + return interval_end_ms - t.read_ms(); + } + +private: + Timer t; + unsigned long interval_end_ms; +}; + +#endif \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f Servo.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Servo.lib Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/simon/code/Servo/#36b69a7ced07
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect.lib --- a/easy-connect.lib Thu Mar 11 13:56:02 2021 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://github.com/ARMmbed/easy-connect/#cb933fb19cda0a733a64d6b71d271fb6bdaf9e6d
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/README.md Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,90 @@ +# Easy Connect - Easily add all supported connectivity methods to your mbed OS project + +Often you want to give users of your application the choice to switch between connectivity methods. The `NetworkInterface` API makes this easy, but you'll still need a mechanism for the user to chooce the method, throw in some `#define`'s, etc. Easy Connect handles all this for you. Just declare the desired connectivity method in your `mbed_app.json` file, and call `easy_connect()` from your application. + +## Specifying connectivity method + +Add the following to your ``mbed_app.json`` file: + +```json +{ + "config": { + "network-interface":{ + "help": "options are ETHERNET,WIFI_ESP8266,MESH_LOWPAN_ND,MESH_THREAD", + "value": "ETHERNET" + } + }, + "target_overrides": { + "*": { + "target.features_add": ["NANOSTACK", "LOWPAN_ROUTER", "COMMON_PAL"], + "mbed-mesh-api.6lowpan-nd-channel-page": 0, + "mbed-mesh-api.6lowpan-nd-channel": 12 + } + } +} +``` + +If you choose `WIFI_ESP8266`, you'll also need to add the WiFi SSID and password: + +```json + "config": { + "network-interface":{ + "help": "options are ETHERNET,WIFI_ESP8266,MESH_LOWPAN_ND,MESH_THREAD", + "value": "WIFI_ESP8266" + }, + "esp8266-tx": { + "help": "Pin used as TX (connects to ESP8266 RX)", + "value": "PTD3" + }, + "esp8266-rx": { + "help": "Pin used as RX (connects to ESP8266 TX)", + "value": "PTD2" + }, + "esp8266-ssid": { + "value": "\"SSID\"" + }, + "esp8266-password": { + "value": "\"Password\"" + }, + "esp8266-debug": { + "value": true + } + } +``` + +If you use `MESH_LOWPAN_ND` or `MESH_THREAD` you will need to specify your radio module: + +```json + "config": { + "network-interface":{ + "help": "options are ETHERNET,WIFI_ESP8266,MESH_LOWPAN_ND,MESH_THREAD", + "value": "MESH_LOWPAN_ND" + }, + "mesh_radio_type": { + "help": "options are ATMEL, MCR20", + "value": "ATMEL" + } + } +``` + +## Using Easy Connect from your application + +Easy Connect has just one function which will either return a `NetworkInterface`-pointer or `NULL`: + +```cpp +#include "easy-connect.h" + +int main(int, char**) { + NetworkInterface* network = easy_connect(true); /* has 1 argument, enable_logging (pass in true to log to serial port) */ + if (!network) { + printf("Connecting to the network failed... See serial output.\r\n"); + return 1; + } + + // Rest of your program +} +``` + +## Extra defines + +If you'd like to use Easy Connect with mbed Client then you're in luck. Easy Connect automatically defines the `MBED_SERVER_ADDRESS` macro depending on your connectivity method (either IPv4 or IPv6 address). Use this address to connect to the right instance of mbed Device Connector.
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.gitignore Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,6 @@ +*~ +*.swo +*.swp +build +yotta_modules +yotta_targets
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/LICENSE Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/README.md Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,7 @@ +# Example RF driver for Atmel 802.15.4 transceivers # + +Support for: + * AT86RF233 + * AT86RF212B + +This driver is used with 6LoWPAN stack. \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/apache-2.0.txt Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NANOSTACK_RF_PHY_ATMEL_H_ +#define NANOSTACK_RF_PHY_ATMEL_H_ + +#include "NanostackRfPhy.h" +#include "at24mac.h" +#include "PinNames.h" + +// Arduino pin defaults for convenience +#if !defined(ATMEL_SPI_MOSI) +#define ATMEL_SPI_MOSI D11 +#endif +#if !defined(ATMEL_SPI_MISO) +#define ATMEL_SPI_MISO D12 +#endif +#if !defined(ATMEL_SPI_SCLK) +#define ATMEL_SPI_SCLK D13 +#endif +#if !defined(ATMEL_SPI_CS) +#define ATMEL_SPI_CS D10 +#endif +#if !defined(ATMEL_SPI_RST) +#define ATMEL_SPI_RST D5 +#endif +#if !defined(ATMEL_SPI_SLP) +#define ATMEL_SPI_SLP D7 +#endif +#if !defined(ATMEL_SPI_IRQ) +#define ATMEL_SPI_IRQ D9 +#endif +#if !defined(ATMEL_I2C_SDA) +#define ATMEL_I2C_SDA D14 +#endif +#if !defined(ATMEL_I2C_SCL) +#define ATMEL_I2C_SCL D15 +#endif + +class RFBits; + +class NanostackRfPhyAtmel : public NanostackRfPhy { +public: + NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, + PinName i2c_sda, PinName i2c_scl); + ~NanostackRfPhyAtmel(); + int8_t rf_register(); + void rf_unregister(); + void get_mac_address(uint8_t *mac); + void set_mac_address(uint8_t *mac); + +private: + AT24Mac _mac; + uint8_t _mac_addr[8]; + RFBits *_rf; + bool _mac_set; + + const PinName _spi_mosi; + const PinName _spi_miso; + const PinName _spi_sclk; + const PinName _spi_cs; + const PinName _spi_rst; + const PinName _spi_slp; + const PinName _spi_irq; +}; + +#endif /* NANOSTACK_RF_PHY_ATMEL_H_ */
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/module.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/module.json Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,17 @@ +{ + "name": "atmel-rf-driver", + "version": "3.0.2", + "description": "RF driver for Atmel AT86RF233", + "keywords": [ + "rf", + "driver" + ], + "author": "Seppo Takalo <seppo.takalo@arm.com>", + "license": "Apache-2.0", + "dependencies": { + "nanostack-libservice": "^3.0.0", + "sal-stack-nanostack": "^5.0.0", + "mbed-drivers": "^1.0.0" + }, + "targetDependencies": {} +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/source/AT86RFReg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/AT86RFReg.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AT86RFREG_H_ +#define AT86RFREG_H_ +#ifdef __cplusplus +extern "C" { +#endif + +/*AT86RF212 PHY Modes*/ +#define BPSK_20 0x00 +#define BPSK_40 0x04 +#define BPSK_40_ALT 0x14 +#define OQPSK_SIN_RC_100 0x08 +#define OQPSK_SIN_RC_200 0x09 +#define OQPSK_RC_100 0x18 +#define OQPSK_RC_200 0x19 +#define OQPSK_SIN_250 0x0c +#define OQPSK_SIN_500 0x0d +#define OQPSK_SIN_500_ALT 0x0f +#define OQPSK_RC_250 0x1c +#define OQPSK_RC_500 0x1d +#define OQPSK_RC_500_ALT 0x1f +#define OQPSK_SIN_RC_400_SCR_ON 0x2A +#define OQPSK_SIN_RC_400_SCR_OFF 0x0A +#define OQPSK_RC_400_SCR_ON 0x3A +#define OQPSK_RC_400_SCR_OFF 0x1A +#define OQPSK_SIN_1000_SCR_ON 0x2E +#define OQPSK_SIN_1000_SCR_OFF 0x0E +#define OQPSK_RC_1000_SCR_ON 0x3E +#define OQPSK_RC_1000_SCR_OFF 0x1E + +/*Supported transceivers*/ +#define PART_AT86RF231 0x03 +#define PART_AT86RF212 0x07 +#define PART_AT86RF233 0x0B +#define VERSION_AT86RF212 0x01 +#define VERSION_AT86RF212B 0x03 + +/*RF Configuration Registers*/ +#define TRX_STATUS 0x01 +#define TRX_STATE 0x02 +#define TRX_CTRL_0 0x03 +#define TRX_CTRL_1 0x04 +#define PHY_TX_PWR 0x05 +#define PHY_RSSI 0x06 +#define PHY_ED_LEVEL 0x07 +#define PHY_CC_CCA 0x08 +#define RX_CTRL 0x0A +#define SFD_VALUE 0x0B +#define TRX_CTRL_2 0x0C +#define ANT_DIV 0x0D +#define IRQ_MASK 0x0E +#define IRQ_STATUS 0x0F +#define VREG_CTRL 0x10 +#define BATMON 0x11 +#define XOSC_CTRL 0x12 +#define CC_CTRL_0 0x13 +#define CC_CTRL_1 0x14 +#define RX_SYN 0x15 +#define TRX_RPC 0x16 +#define RF_CTRL_0 0x16 +#define XAH_CTRL_1 0x17 +#define FTN_CTRL 0x18 +#define PLL_CF 0x1A +#define PLL_DCU 0x1B +#define PART_NUM 0x1C +#define VERSION_NUM 0x1D +#define MAN_ID_0 0x1E +#define MAN_ID_1 0x1F +#define SHORT_ADDR_0 0x20 +#define SHORT_ADDR_1 0x21 +#define PAN_ID_0 0x22 +#define PAN_ID_1 0x23 +#define IEEE_ADDR_0 0x24 +#define IEEE_ADDR_1 0x25 +#define IEEE_ADDR_2 0x26 +#define IEEE_ADDR_3 0x27 +#define IEEE_ADDR_4 0x28 +#define IEEE_ADDR_5 0x29 +#define IEEE_ADDR_6 0x2A +#define IEEE_ADDR_7 0x2B +#define XAH_CTRL_0 0x2C +#define CSMA_SEED_0 0x2D +#define CSMA_SEED_1 0x2E +#define CSMA_BE 0x2F + +/* CSMA_SEED_1*/ +#define AACK_FVN_MODE1 7 +#define AACK_FVN_MODE0 6 +#define AACK_SET_PD 5 +#define AACK_DIS_ACK 4 +#define AACK_I_AM_COORD 3 +#define CSMA_SEED_12 2 +#define CSMA_SEED_11 1 +#define CSMA_SEED_10 0 + +/*TRX_STATUS bits*/ +#define CCA_STATUS 0x40 +#define CCA_DONE 0x80 + +/*PHY_CC_CCA bits*/ +#define CCA_REQUEST 0x80 +#define CCA_MODE_1 0x20 +#define CCA_MODE_3 0x60 + +/*IRQ_MASK bits*/ +#define RX_START 0x04 +#define TRX_END 0x08 +#define CCA_ED_DONE 0x10 +#define AMI 0x20 +#define TRX_UR 0x40 + +/*ANT_DIV bits*/ +#define ANT_DIV_EN 0x08 +#define ANT_EXT_SW_EN 0x04 +#define ANT_CTRL_DEFAULT 0x03 + +/*TRX_CTRL_1 bits*/ +#define PA_EXT_EN 0x80 + +/*FTN_CTRL bits*/ +#define FTN_START 0x80 + +/*PHY_RSSI bits*/ +#define CRC_VALID 0x80 + +/*XAH_CTRL_1 bits*/ +#define AACK_PROM_MODE 0x02 + + +#ifdef __cplusplus +} +#endif + +#endif /* AT86RFREG_H_ */
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,2513 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <string.h> +#include "platform/arm_hal_interrupt.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "ns_types.h" +#include "NanostackRfPhyAtmel.h" +#include "randLIB.h" +#include "AT86RFReg.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "toolchain.h" + +/*Worst case sensitivity*/ +#define RF_DEFAULT_SENSITIVITY -88 +/*Run calibration every 5 minutes*/ +#define RF_CALIBRATION_INTERVAL 6000000 +/*Wait ACK for 2.5ms*/ +#define RF_ACK_WAIT_DEFAULT_TIMEOUT 50 +/*Base CCA backoff (50us units) - substitutes for Inter-Frame Spacing*/ +#define RF_CCA_BASE_BACKOFF 13 /* 650us */ +/*CCA random backoff (50us units)*/ +#define RF_CCA_RANDOM_BACKOFF 51 /* 2550us */ + +#define RF_BUFFER_SIZE 128 + +#define RF_PHY_MODE OQPSK_SIN_250 + +/*Radio RX and TX state definitions*/ +#define RFF_ON 0x01 +#define RFF_RX 0x02 +#define RFF_TX 0x04 +#define RFF_CCA 0x08 + +typedef enum +{ + RF_MODE_NORMAL = 0, + RF_MODE_SNIFFER = 1, + RF_MODE_ED = 2 +}rf_mode_t; + +/*Atmel RF Part Type*/ +typedef enum +{ + ATMEL_UNKNOW_DEV = 0, + ATMEL_AT86RF212, + ATMEL_AT86RF231, + ATMEL_AT86RF233 +}rf_trx_part_e; + +/*Atmel RF states*/ +typedef enum +{ + NOP = 0x00, + BUSY_RX = 0x01, + RF_TX_START = 0x02, + FORCE_TRX_OFF = 0x03, + FORCE_PLL_ON = 0x04, + RX_ON = 0x06, + TRX_OFF = 0x08, + PLL_ON = 0x09, + BUSY_RX_AACK = 0x11, + SLEEP = 0x0F, + RX_AACK_ON = 0x16, + TX_ARET_ON = 0x19 +}rf_trx_states_t; + +/*RF receive buffer*/ +static uint8_t rf_buffer[RF_BUFFER_SIZE]; +/*ACK wait duration changes depending on data rate*/ +static uint16_t rf_ack_wait_duration = RF_ACK_WAIT_DEFAULT_TIMEOUT; + +static int8_t rf_sensitivity = RF_DEFAULT_SENSITIVITY; +static rf_mode_t rf_mode = RF_MODE_NORMAL; +static uint8_t radio_tx_power = 0x00; // Default to +4dBm +static uint8_t rf_phy_channel = 12; +static uint8_t rf_tuned = 1; +static uint8_t rf_use_antenna_diversity = 0; +static uint8_t tx_sequence = 0xff; +static uint8_t need_ack = 0; +static uint8_t rf_rx_mode = 0; +static uint8_t rf_flags = 0; +static uint8_t rf_rnd_rssi = 0; +static int8_t rf_radio_driver_id = -1; +static phy_device_driver_s device_driver; +static uint8_t mac_tx_handle = 0; + +/* Channel configurations for 2.4 and sub-GHz */ +static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK}; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_2, &phy_subghz}, + { CHANNEL_PAGE_0, NULL} +}; + +/** + * RF output power write + * + * \brief TX power has to be set before network start. + * + * \param power + * AT86RF233 + * 0 = 4 dBm + * 1 = 3.7 dBm + * 2 = 3.4 dBm + * 3 = 3 dBm + * 4 = 2.5 dBm + * 5 = 2 dBm + * 6 = 1 dBm + * 7 = 0 dBm + * 8 = -1 dBm + * 9 = -2 dBm + * 10 = -3 dBm + * 11 = -4 dBm + * 12 = -6 dBm + * 13 = -8 dBm + * 14 = -12 dBm + * 15 = -17 dBm + * + * AT86RF212B + * See datasheet for TX power settings + * + * \return 0, Supported Value + * \return -1, Not Supported Value + */ +static int8_t rf_tx_power_set(uint8_t power); +static rf_trx_part_e rf_radio_type_read(void); +static void rf_ack_wait_timer_start(uint16_t slots); +static void rf_ack_wait_timer_stop(void); +static void rf_handle_cca_ed_done(void); +static void rf_handle_tx_end(void); +static void rf_handle_rx_end(void); +static void rf_on(void); +static void rf_receive(void); +static void rf_poll_trx_state_change(rf_trx_states_t trx_state); +static void rf_init(void); +static int8_t rf_device_register(const uint8_t *mac_addr); +static void rf_device_unregister(void); +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); +static void rf_cca_abort(void); +static void rf_calibration_cb(void); +static void rf_init_phy_mode(void); +static void rf_ack_wait_timer_interrupt(void); +static void rf_calibration_timer_interrupt(void); +static void rf_calibration_timer_start(uint32_t slots); +static void rf_cca_timer_interrupt(void); +static void rf_cca_timer_start(uint32_t slots); +static uint8_t rf_scale_lqi(int8_t rssi); + +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr); +static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr); + +static void rf_if_cca_timer_start(uint32_t slots); +static void rf_if_enable_promiscuous_mode(void); +static void rf_if_lock(void); +static void rf_if_unlock(void); +static uint8_t rf_if_read_rnd(void); +static void rf_if_calibration_timer_start(uint32_t slots); +static void rf_if_interrupt_handler(void); +static void rf_if_ack_wait_timer_start(uint16_t slots); +static void rf_if_ack_wait_timer_stop(void); +static void rf_if_ack_pending_ctrl(uint8_t state); +static void rf_if_calibration(void); +static uint8_t rf_if_read_register(uint8_t addr); +static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask); +static void rf_if_clear_bit(uint8_t addr, uint8_t bit); +static void rf_if_write_register(uint8_t addr, uint8_t data); +static void rf_if_reset_radio(void); +static void rf_if_enable_ant_div(void); +static void rf_if_disable_ant_div(void); +static void rf_if_enable_slptr(void); +static void rf_if_disable_slptr(void); +static void rf_if_write_antenna_diversity_settings(void); +static void rf_if_write_set_tx_power_register(uint8_t value); +static void rf_if_write_rf_settings(void); +static uint8_t rf_if_check_cca(void); +static uint8_t rf_if_check_crc(void); +static uint8_t rf_if_read_trx_state(void); +static void rf_if_read_packet(uint8_t *ptr, uint8_t len); +static void rf_if_write_short_addr_registers(uint8_t *short_address); +static uint8_t rf_if_last_acked_pending(void); +static void rf_if_write_pan_id_registers(uint8_t *pan_id); +static void rf_if_write_ieee_addr_registers(uint8_t *address); +static void rf_if_write_frame_buffer(uint8_t *ptr, uint8_t length); +static void rf_if_change_trx_state(rf_trx_states_t trx_state); +static void rf_if_enable_tx_end_interrupt(void); +static void rf_if_enable_rx_end_interrupt(void); +static void rf_if_enable_cca_ed_done_interrupt(void); +static void rf_if_start_cca_process(void); +static uint8_t rf_if_read_received_frame_length(void); +static int8_t rf_if_read_rssi(void); +static uint8_t rf_if_read_rx_status(void); +static void rf_if_set_channel_register(uint8_t channel); +static void rf_if_enable_promiscuous_mode(void); +static void rf_if_disable_promiscuous_mode(void); +static uint8_t rf_if_read_part_num(void); +static void rf_if_enable_irq(void); +static void rf_if_disable_irq(void); + +#ifdef MBED_CONF_RTOS_PRESENT +#include "mbed.h" +#include "rtos.h" + +static void rf_if_irq_task_process_irq(); + +#define SIG_RADIO 1 +#define SIG_TIMER_ACK 2 +#define SIG_TIMER_CAL 4 +#define SIG_TIMER_CCA 8 + +#define SIG_TIMERS (SIG_TIMER_ACK|SIG_TIMER_CAL|SIG_TIMER_CCA) +#define SIG_ALL (SIG_RADIO|SIG_TIMERS) +#endif + +// HW pins to RF chip +#define SPI_SPEED 7500000 + +class UnlockedSPI : public SPI { +public: + UnlockedSPI(PinName mosi, PinName miso, PinName sclk) : + SPI(mosi, miso, sclk) { } + virtual void lock() { } + virtual void unlock() { } +}; + +class RFBits { +public: + RFBits(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, + PinName spi_rst, PinName spi_slp, PinName spi_irq); + UnlockedSPI spi; + DigitalOut CS; + DigitalOut RST; + DigitalOut SLP_TR; + InterruptIn IRQ; + Timeout ack_timer; + Timeout cal_timer; + Timeout cca_timer; +#ifdef MBED_CONF_RTOS_PRESENT + Thread irq_thread; + Mutex mutex; + void rf_if_irq_task(); +#endif +}; + +RFBits::RFBits(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, + PinName spi_rst, PinName spi_slp, PinName spi_irq) + : spi(spi_mosi, spi_miso, spi_sclk), + CS(spi_cs), + RST(spi_rst), + SLP_TR(spi_slp), + IRQ(spi_irq) +#ifdef MBED_CONF_RTOS_PRESENT +,irq_thread(osPriorityRealtime, 1024) +#endif +{ +#ifdef MBED_CONF_RTOS_PRESENT + irq_thread.start(this, &RFBits::rf_if_irq_task); +#endif +} + +static RFBits *rf; +static uint8_t rf_part_num = 0; +static uint8_t rf_rx_lqi; +static int8_t rf_rx_rssi; +static uint8_t rf_rx_status; +/*TODO: RSSI Base value setting*/ +static int8_t rf_rssi_base_val = -91; + +static uint8_t rf_if_spi_exchange(uint8_t out); + +static void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +#ifdef MBED_CONF_RTOS_PRESENT +static void rf_if_cca_timer_signal(void) +{ + rf->irq_thread.signal_set(SIG_TIMER_CCA); +} + +static void rf_if_cal_timer_signal(void) +{ + rf->irq_thread.signal_set(SIG_TIMER_CAL); +} + +static void rf_if_ack_timer_signal(void) +{ + rf->irq_thread.signal_set(SIG_TIMER_ACK); +} +#endif + + +/* Delay functions for RF Chip SPI access */ +#ifdef __CC_ARM +__asm static void delay_loop(uint32_t count) +{ +1 + SUBS a1, a1, #1 + BCS %BT1 + BX lr +} +#elif defined (__ICCARM__) +static void delay_loop(uint32_t count) +{ + __asm volatile( + "loop: \n" + " SUBS %0, %0, #1 \n" + " BCS.n loop\n" + : "+r" (count) + : + : "cc" + ); +} +#else // GCC +static void delay_loop(uint32_t count) +{ + __asm__ volatile ( + "%=:\n\t" +#if defined(__thumb__) && !defined(__thumb2__) + "SUB %0, #1\n\t" +#else + "SUBS %0, %0, #1\n\t" +#endif + "BCS %=b\n\t" + : "+l" (count) + : + : "cc" + ); +} +#endif + +static void delay_ns(uint32_t ns) +{ + uint32_t cycles_per_us = SystemCoreClock / 1000000; + // Cortex-M0 takes 4 cycles per loop (SUB=1, BCS=3) + // Cortex-M3 and M4 takes 3 cycles per loop (SUB=1, BCS=2) + // Cortex-M7 - who knows? + // Cortex M3-M7 have "CYCCNT" - would be better than a software loop, but M0 doesn't + // Assume 3 cycles per loop for now - will be 33% slow on M0. No biggie, + // as original version of code was 300% slow on M4. + // [Note that this very calculation, plus call overhead, will take multiple + // cycles. Could well be 100ns on its own... So round down here, startup is + // worth at least one loop iteration.] + uint32_t count = (cycles_per_us * ns) / 3000; + + delay_loop(count); +} + +// t1 = 180ns, SEL falling edge to MISO active [SPI setup assumed slow enough to not need manual delay] +#define CS_SELECT() {rf->CS = 0; /* delay_ns(180); */} + // t9 = 250ns, last clock to SEL rising edge, t8 = 250ns, SPI idle time between consecutive access +#define CS_RELEASE() {delay_ns(250); rf->CS = 1; delay_ns(250);} + +/* + * \brief Function sets the TX power variable. + * + * \param power TX power setting + * + * \return 0 Success + * \return -1 Fail + */ +MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power) +{ + int8_t ret_val = -1; + + radio_tx_power = power; + rf_if_lock(); + rf_if_write_set_tx_power_register(radio_tx_power); + rf_if_unlock(); + ret_val = 0; + + return ret_val; +} + +/* + * \brief Read connected radio part. + * + * This function only return valid information when rf_init() is called + * + * \return + */ +static rf_trx_part_e rf_radio_type_read(void) +{ + rf_trx_part_e ret_val = ATMEL_UNKNOW_DEV; + + switch (rf_part_num) + { + case PART_AT86RF212: + ret_val = ATMEL_AT86RF212; + break; + + case PART_AT86RF231: + ret_val = ATMEL_AT86RF231; + break; + case PART_AT86RF233: + ret_val = ATMEL_AT86RF231; + break; + default: + break; + } + + return ret_val; +} + + +/* + * \brief Function starts the ACK wait timeout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_ack_wait_timer_start(uint16_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->ack_timer.attach(rf_if_ack_timer_signal, slots*50e-6); +#else + rf->ack_timer.attach(rf_ack_wait_timer_interrupt, slots*50e-6); +#endif +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_calibration_timer_start(uint32_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->cal_timer.attach(rf_if_cal_timer_signal, slots*50e-6); +#else + rf->cal_timer.attach(rf_calibration_timer_interrupt, slots*50e-6); +#endif +} + +/* + * \brief Function starts the CCA interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_cca_timer_start(uint32_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->cca_timer.attach(rf_if_cca_timer_signal, slots*50e-6); +#else + rf->cca_timer.attach(rf_cca_timer_interrupt, slots*50e-6); +#endif +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_if_ack_wait_timer_stop(void) +{ + rf->ack_timer.detach(); +} + +/* + * \brief Function reads data from the given RF SRAM address. + * + * \param ptr Read pointer + * \param sram_address Read address in SRAM + * \param len Length of the read + * + * \return none + */ +static void rf_if_read_payload(uint8_t *ptr, uint8_t sram_address, uint8_t len) +{ + uint8_t i; + + CS_SELECT(); + rf_if_spi_exchange(0x20); + rf_if_spi_exchange(sram_address); + for(i=0; i<len; i++) + *ptr++ = rf_if_spi_exchange(0); + + /*Read LQI and RSSI in variable*/ + rf_rx_lqi = rf_if_spi_exchange(0); + rf_rx_rssi = rf_if_spi_exchange(0); + rf_rx_status = rf_if_spi_exchange(0); + CS_RELEASE(); +} + +/* + * \brief Function sets bit(s) in given RF register. + * + * \param addr Address of the register to set + * \param bit Bit(s) to set + * \param bit_mask Masks the field inside the register + * + * \return none + */ +static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask) +{ + uint8_t reg = rf_if_read_register(addr); + reg &= ~bit_mask; + reg |= bit; + rf_if_write_register(addr, reg); +} + +/* + * \brief Function clears bit(s) in given RF register. + * + * \param addr Address of the register to clear + * \param bit Bit(s) to clear + * + * \return none + */ +static void rf_if_clear_bit(uint8_t addr, uint8_t bit) +{ + uint8_t reg = rf_if_read_register(addr); + reg &= ~bit; + rf_if_write_register(addr, reg); +} + +/* + * \brief Function writes register in RF. + * + * \param addr Address on the RF + * \param data Written data + * + * \return none + */ +static void rf_if_write_register(uint8_t addr, uint8_t data) +{ + uint8_t cmd = 0xC0; + CS_SELECT(); + rf_if_spi_exchange(cmd | addr); + rf_if_spi_exchange(data); + CS_RELEASE(); +} + +/* + * \brief Function reads RF register. + * + * \param addr Address on the RF + * + * \return Read data + */ +static uint8_t rf_if_read_register(uint8_t addr) +{ + uint8_t cmd = 0x80; + uint8_t data; + CS_SELECT(); + rf_if_spi_exchange(cmd | addr); + data = rf_if_spi_exchange(0); + CS_RELEASE(); + return data; +} + +/* + * \brief Function resets the RF. + * + * \param none + * + * \return none + */ +static void rf_if_reset_radio(void) +{ + rf->spi.frequency(SPI_SPEED); + rf->IRQ.rise(0); + rf->RST = 1; + wait(10e-4); + rf->RST = 0; + wait(10e-3); + CS_RELEASE(); + rf->SLP_TR = 0; + wait(10e-3); + rf->RST = 1; + wait(10e-3); + + rf->IRQ.rise(&rf_if_interrupt_handler); +} + +/* + * \brief Function enables the promiscuous mode. + * + * \param none + * + * \return none + */ +static void rf_if_enable_promiscuous_mode(void) +{ + /*Set AACK_PROM_MODE to enable the promiscuous mode*/ + rf_if_set_bit(XAH_CTRL_1, AACK_PROM_MODE, AACK_PROM_MODE); +} + +/* + * \brief Function enables the promiscuous mode. + * + * \param none + * + * \return none + */ +static void rf_if_disable_promiscuous_mode(void) +{ + /*Set AACK_PROM_MODE to enable the promiscuous mode*/ + rf_if_clear_bit(XAH_CTRL_1, AACK_PROM_MODE); +} + +/* + * \brief Function enables the Antenna diversity usage. + * + * \param none + * + * \return none + */ +static void rf_if_enable_ant_div(void) +{ + /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ + rf_if_set_bit(ANT_DIV, ANT_EXT_SW_EN, ANT_EXT_SW_EN); +} + +/* + * \brief Function disables the Antenna diversity usage. + * + * \param none + * + * \return none + */ +static void rf_if_disable_ant_div(void) +{ + rf_if_clear_bit(ANT_DIV, ANT_EXT_SW_EN); +} + +/* + * \brief Function sets the SLP TR pin. + * + * \param none + * + * \return none + */ +static void rf_if_enable_slptr(void) +{ + rf->SLP_TR = 1; +} + +/* + * \brief Function clears the SLP TR pin. + * + * \param none + * + * \return none + */ +static void rf_if_disable_slptr(void) +{ + rf->SLP_TR = 0; +} + +/* + * \brief Function writes the antenna diversity settings. + * + * \param none + * + * \return none + */ +static void rf_if_write_antenna_diversity_settings(void) +{ + /*Recommended setting of PDT_THRES is 3 when antenna diversity is used*/ + rf_if_set_bit(RX_CTRL, 0x03, 0x0f); + rf_if_write_register(ANT_DIV, ANT_DIV_EN | ANT_EXT_SW_EN | ANT_CTRL_DEFAULT); +} + +/* + * \brief Function writes the TX output power register. + * + * \param value Given register value + * + * \return none + */ +static void rf_if_write_set_tx_power_register(uint8_t value) +{ + rf_if_write_register(PHY_TX_PWR, value); +} + +/* + * \brief Function returns the RF part number. + * + * \param none + * + * \return part number + */ +static uint8_t rf_if_read_part_num(void) +{ + return rf_if_read_register(PART_NUM); +} + +/* + * \brief Function writes the RF settings and initialises SPI interface. + * + * \param none + * + * \return none + */ +static void rf_if_write_rf_settings(void) +{ + /*Reset RF module*/ + rf_if_reset_radio(); + + rf_part_num = rf_if_read_part_num(); + + rf_if_write_register(XAH_CTRL_0,0); + rf_if_write_register(TRX_CTRL_1, 0x20); + + /*CCA Mode - Carrier sense OR energy above threshold. Channel list is set separately*/ + rf_if_write_register(PHY_CC_CCA, 0x05); + + /*Read transceiver PART_NUM*/ + rf_part_num = rf_if_read_register(PART_NUM); + + /*Sub-GHz RF settings*/ + if(rf_part_num == PART_AT86RF212) + { + /*GC_TX_OFFS mode-dependent setting - OQPSK*/ + rf_if_write_register(RF_CTRL_0, 0x32); + + if(rf_if_read_register(VERSION_NUM) == VERSION_AT86RF212B) + { + /*TX Output Power setting - 0 dBm North American Band*/ + rf_if_write_register(PHY_TX_PWR, 0x03); + } + else + { + /*TX Output Power setting - 0 dBm North American Band*/ + rf_if_write_register(PHY_TX_PWR, 0x24); + } + + /*PHY Mode: IEEE 802.15.4-2006/2011 - OQPSK-SIN-250*/ + rf_if_write_register(TRX_CTRL_2, RF_PHY_MODE); + /*Based on receiver Characteristics. See AT86RF212B Datasheet where RSSI BASE VALUE in range -97 - -100 dBm*/ + rf_rssi_base_val = -98; + } + /*2.4GHz RF settings*/ + else + { + /*Set RPC register*/ + rf_if_write_register(TRX_RPC, 0xef); + /*PHY Mode: IEEE 802.15.4 - Data Rate 250 kb/s*/ + rf_if_write_register(TRX_CTRL_2, 0); + rf_rssi_base_val = -91; + } +} + +/* + * \brief Function checks the channel availability + * + * \param none + * + * \return 1 Channel clear + * \return 0 Channel not clear + */ +static uint8_t rf_if_check_cca(void) +{ + uint8_t retval = 0; + if(rf_if_read_register(TRX_STATUS) & CCA_STATUS) + { + retval = 1; + } + return retval; +} + +/* + * \brief Function checks if the CRC is valid in received frame + * + * \param none + * + * \return 1 CRC ok + * \return 0 CRC failed + */ +static uint8_t rf_if_check_crc(void) +{ + uint8_t retval = 0; + if(rf_if_read_register(PHY_RSSI) & CRC_VALID) + { + retval = 1; + } + return retval; +} + +/* + * \brief Function returns the RF state + * + * \param none + * + * \return RF state + */ +static uint8_t rf_if_read_trx_state(void) +{ + return rf_if_read_register(TRX_STATUS) & 0x1F; +} + +/* + * \brief Function reads data from RF SRAM. + * + * \param ptr Read pointer + * \param len Length of the read + * + * \return none + */ +static void rf_if_read_packet(uint8_t *ptr, uint8_t len) +{ + if(rf_part_num == PART_AT86RF231 || rf_part_num == PART_AT86RF212) + rf_if_read_payload(ptr, 0, len); + else if(rf_part_num == PART_AT86RF233) + rf_if_read_payload(ptr, 1, len); +} + +/* + * \brief Function writes RF short address registers + * + * \param short_address Given short address + * + * \return none + */ +static void rf_if_write_short_addr_registers(uint8_t *short_address) +{ + rf_if_write_register(SHORT_ADDR_1, *short_address++); + rf_if_write_register(SHORT_ADDR_0, *short_address); +} + +/* + * \brief Function sets the frame pending in ACK message + * + * \param state Given frame pending state + * + * \return none + */ +static void rf_if_ack_pending_ctrl(uint8_t state) +{ + rf_if_lock(); + if(state) + { + rf_if_set_bit(CSMA_SEED_1, (1 << AACK_SET_PD), (1 << AACK_SET_PD)); + } + else + { + rf_if_clear_bit(CSMA_SEED_1, (1 << AACK_SET_PD)); + } + rf_if_unlock(); +} + +/* + * \brief Function returns the state of frame pending control + * + * \param none + * + * \return Frame pending state + */ +static uint8_t rf_if_last_acked_pending(void) +{ + uint8_t last_acked_data_pending; + + rf_if_lock(); + if(rf_if_read_register(CSMA_SEED_1) & 0x20) + last_acked_data_pending = 1; + else + last_acked_data_pending = 0; + rf_if_unlock(); + + return last_acked_data_pending; +} + +/* + * \brief Function calibrates the RF part. + * + * \param none + * + * \return none + */ +static void rf_if_calibration(void) +{ + rf_if_set_bit(FTN_CTRL, FTN_START, FTN_START); + /*Wait while calibration is running*/ + while(rf_if_read_register(FTN_CTRL) & FTN_START); +} + +/* + * \brief Function writes RF PAN Id registers + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_if_write_pan_id_registers(uint8_t *pan_id) +{ + rf_if_write_register(PAN_ID_1, *pan_id++); + rf_if_write_register(PAN_ID_0, *pan_id); +} + +/* + * \brief Function writes RF IEEE Address registers + * + * \param address Given IEEE Address + * + * \return none + */ +static void rf_if_write_ieee_addr_registers(uint8_t *address) +{ + uint8_t i; + uint8_t temp = IEEE_ADDR_0; + + for(i=0; i<8; i++) + rf_if_write_register(temp++, address[7-i]); +} + +/* + * \brief Function writes data in RF frame buffer. + * + * \param ptr Pointer to data + * \param length Pointer to length + * + * \return none + */ +static void rf_if_write_frame_buffer(uint8_t *ptr, uint8_t length) +{ + uint8_t i; + uint8_t cmd = 0x60; + + CS_SELECT(); + rf_if_spi_exchange(cmd); + rf_if_spi_exchange(length + 2); + for(i=0; i<length; i++) + rf_if_spi_exchange(*ptr++); + + CS_RELEASE(); +} + +/* + * \brief Function returns 8-bit random value. + * + * \param none + * + * \return random value + */ +static uint8_t rf_if_read_rnd(void) +{ + uint8_t temp; + uint8_t tmp_rpc_val = 0; + /*RPC must be disabled while reading the random number*/ + if(rf_part_num == PART_AT86RF233) + { + tmp_rpc_val = rf_if_read_register(TRX_RPC); + rf_if_write_register(TRX_RPC, 0xc1); + } + + wait(1e-3); + temp = ((rf_if_read_register(PHY_RSSI)>>5) << 6); + wait(1e-3); + temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 4); + wait(1e-3); + temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 2); + wait(1e-3); + temp |= ((rf_if_read_register(PHY_RSSI)>>5)); + wait(1e-3); + if(rf_part_num == PART_AT86RF233) + rf_if_write_register(TRX_RPC, tmp_rpc_val); + return temp; +} + +/* + * \brief Function changes the state of the RF. + * + * \param trx_state Given RF state + * + * \return none + */ +static void rf_if_change_trx_state(rf_trx_states_t trx_state) +{ + rf_if_lock(); + rf_if_write_register(TRX_STATE, trx_state); + /*Wait while not in desired state*/ + rf_poll_trx_state_change(trx_state); + rf_if_unlock(); +} + +/* + * \brief Function enables the TX END interrupt + * + * \param none + * + * \return none + */ +static void rf_if_enable_tx_end_interrupt(void) +{ + rf_if_set_bit(IRQ_MASK, TRX_END, 0x08); +} + +/* + * \brief Function enables the RX END interrupt + * + * \param none + * + * \return none + */ +static void rf_if_enable_rx_end_interrupt(void) +{ + rf_if_set_bit(IRQ_MASK, TRX_END, 0x08); +} + +/* + * \brief Function enables the CCA ED interrupt + * + * \param none + * + * \return none + */ +static void rf_if_enable_cca_ed_done_interrupt(void) +{ + rf_if_set_bit(IRQ_MASK, CCA_ED_DONE, 0x10); +} + +/* + * \brief Function starts the CCA process + * + * \param none + * + * \return none + */ +static void rf_if_start_cca_process(void) +{ + rf_if_set_bit(PHY_CC_CCA, CCA_REQUEST, 0x80); +} + +/* + * \brief Function returns the length of the received packet + * + * \param none + * + * \return packet length + */ +static uint8_t rf_if_read_received_frame_length(void) +{ + uint8_t length; + + CS_SELECT(); + rf_if_spi_exchange(0x20); + length = rf_if_spi_exchange(0); + CS_RELEASE(); + + return length; +} + +/* + * \brief Function returns the RSSI of the received packet + * + * \param none + * + * \return packet RSSI + */ +static int8_t rf_if_read_rssi(void) +{ + int16_t rssi_calc_tmp; + if(rf_part_num == PART_AT86RF212) + rssi_calc_tmp = rf_rx_rssi * 103; + else + rssi_calc_tmp = rf_rx_rssi * 100; + rssi_calc_tmp /= 100; + rssi_calc_tmp = (rf_rssi_base_val + rssi_calc_tmp); + return (int8_t)rssi_calc_tmp; +} + +/* + * \brief Function returns the RSSI of the received packet + * + * \param none + * + * \return packet RSSI + */ +MBED_UNUSED uint8_t rf_if_read_rx_status(void) +{ + return rf_rx_status; +} + +/* + * \brief Function sets the RF channel field + * + * \param Given channel + * + * \return none + */ +static void rf_if_set_channel_register(uint8_t channel) +{ + rf_if_set_bit(PHY_CC_CCA, channel, 0x1f); +} + +/* + * \brief Function enables RF irq pin interrupts in RF interface. + * + * \param none + * + * \return none + */ +static void rf_if_enable_irq(void) +{ + rf->IRQ.enable_irq(); +} + +/* + * \brief Function disables RF irq pin interrupts in RF interface. + * + * \param none + * + * \return none + */ +static void rf_if_disable_irq(void) +{ + rf->IRQ.disable_irq(); +} + +#ifdef MBED_CONF_RTOS_PRESENT +static void rf_if_interrupt_handler(void) +{ + rf->irq_thread.signal_set(SIG_RADIO); +} + +// Started during construction of rf, so variable +// rf isn't set at the start. Uses 'this' instead. +void RFBits::rf_if_irq_task(void) +{ + for (;;) { + osEvent event = irq_thread.signal_wait(0); + if (event.status != osEventSignal) { + continue; + } + rf_if_lock(); + if (event.value.signals & SIG_RADIO) { + rf_if_irq_task_process_irq(); + } + if (event.value.signals & SIG_TIMER_ACK) { + rf_ack_wait_timer_interrupt(); + } + if (event.value.signals & SIG_TIMER_CCA) { + rf_cca_timer_interrupt(); + } + if (event.value.signals & SIG_TIMER_CAL) { + rf_calibration_timer_interrupt(); + } + rf_if_unlock(); + } +} + +static void rf_if_irq_task_process_irq(void) +#else +/* + * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt. + * + * \param none + * + * \return none + */ +static void rf_if_interrupt_handler(void) +#endif +{ + uint8_t irq_status; + + /*Read interrupt flag*/ + irq_status = rf_if_read_register(IRQ_STATUS); + + /*Disable interrupt on RF*/ + rf_if_clear_bit(IRQ_MASK, irq_status); + /*RX start interrupt*/ + if(irq_status & RX_START) + { + } + /*Address matching interrupt*/ + if(irq_status & AMI) + { + } + if(irq_status & TRX_UR) + { + } + /*Frame end interrupt (RX and TX)*/ + if(irq_status & TRX_END) + { + /*TX done interrupt*/ + if(rf_if_read_trx_state() == PLL_ON || rf_if_read_trx_state() == TX_ARET_ON) + { + rf_handle_tx_end(); + } + /*Frame received interrupt*/ + else + { + rf_handle_rx_end(); + } + } + if(irq_status & CCA_ED_DONE) + { + rf_handle_cca_ed_done(); + } +} + +/* + * \brief Function writes/read data in SPI interface + * + * \param out Output data + * + * \return Input data + */ +static uint8_t rf_if_spi_exchange(uint8_t out) +{ + uint8_t v; + v = rf->spi.write(out); + // t9 = t5 = 250ns, delay between LSB of last byte to next MSB or delay between LSB & SEL rising + // [SPI setup assumed slow enough to not need manual delay] + // delay_ns(250); + return v; +} + +/* + * \brief Function sets given RF flag on. + * + * \param x Given RF flag + * + * \return none + */ +static void rf_flags_set(uint8_t x) +{ + rf_flags |= x; +} + +/* + * \brief Function clears given RF flag on. + * + * \param x Given RF flag + * + * \return none + */ +static void rf_flags_clear(uint8_t x) +{ + rf_flags &= ~x; +} + +/* + * \brief Function checks if given RF flag is on. + * + * \param x Given RF flag + * + * \return states of the given flags + */ +static uint8_t rf_flags_check(uint8_t x) +{ + return (rf_flags & x); +} + +/* + * \brief Function clears all RF flags. + * + * \param none + * + * \return none + */ +static void rf_flags_reset(void) +{ + rf_flags = 0; +} + +/* + * \brief Function initialises and registers the RF driver. + * + * \param none + * + * \return rf_radio_driver_id Driver ID given by NET library + */ +static int8_t rf_device_register(const uint8_t *mac_addr) +{ + rf_trx_part_e radio_type; + + rf_init(); + + radio_type = rf_radio_type_read(); + if(radio_type != ATMEL_UNKNOW_DEV) + { + /*Set pointer to MAC address*/ + device_driver.PHY_MAC = (uint8_t *)mac_addr; + device_driver.driver_description = (char*)"ATMEL_MAC"; + //Create setup Used Radio chips + if(radio_type == ATMEL_AT86RF212) + { + device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; + } + else + { + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + } + device_driver.phy_channel_pages = phy_channel_pages; + /*Maximum size of payload is 127*/ + device_driver.phy_MTU = 127; + /*No header in PHY*/ + device_driver.phy_header_length = 0; + /*No tail in PHY*/ + device_driver.phy_tail_length = 0; + /*Set address write function*/ + device_driver.address_write = &rf_address_write; + /*Set RF extension function*/ + device_driver.extension = &rf_extension; + /*Set RF state control function*/ + device_driver.state_control = &rf_interface_state_control; + /*Set transmit function*/ + device_driver.tx = &rf_start_cca; + /*NULLIFY rx and tx_done callbacks*/ + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + } + return rf_radio_driver_id; +} + +/* + * \brief Function unregisters the RF driver. + * + * \param none + * + * \return none + */ +static void rf_device_unregister() +{ + if (rf_radio_driver_id >= 0) { + arm_net_phy_unregister(rf_radio_driver_id); + rf_radio_driver_id = -1; + } +} + +/* + * \brief Function is a call back for ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_interrupt(void) +{ + rf_if_lock(); + /*Force PLL state*/ + rf_if_change_trx_state(FORCE_PLL_ON); + rf_poll_trx_state_change(PLL_ON); + /*Start receiver in RX_AACK_ON state*/ + rf_rx_mode = 0; + rf_flags_clear(RFF_RX); + rf_receive(); + rf_if_unlock(); +} + +/* + * \brief Function is a call back for calibration interval timer. + * + * \param none + * + * \return none + */ +static void rf_calibration_timer_interrupt(void) +{ + /*Calibrate RF*/ + rf_calibration_cb(); + /*Start new calibration timeout*/ + rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); +} + +/* + * \brief Function is a call back for cca interval timer. + * + * \param none + * + * \return none + */ +static void rf_cca_timer_interrupt(void) +{ + /*Start CCA process*/ + if(rf_if_read_trx_state() == BUSY_RX_AACK) + { + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } + } + else + { + /*Set radio in RX state to read channel*/ + rf_receive(); + rf_if_enable_cca_ed_done_interrupt(); + rf_if_start_cca_process(); + } +} + +/* + * \brief Function starts the ACK wait timeout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_ack_wait_timer_start(uint16_t slots) +{ + rf_if_ack_wait_timer_start(slots); +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_calibration_timer_start(uint32_t slots) +{ + rf_if_calibration_timer_start(slots); +} + +/* + * \brief Function starts the CCA timout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_cca_timer_start(uint32_t slots) +{ + rf_if_cca_timer_start(slots); +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_stop(void) +{ + rf_if_ack_wait_timer_stop(); +} + +/* + * \brief Function writes various RF settings in startup. + * + * \param none + * + * \return none + */ +static void rf_write_settings(void) +{ + rf_if_lock(); + rf_if_write_rf_settings(); + /*Set output power*/ + rf_if_write_set_tx_power_register(radio_tx_power); + /*Initialise Antenna Diversity*/ + if(rf_use_antenna_diversity) + rf_if_write_antenna_diversity_settings(); + rf_if_unlock(); +} + +/* + * \brief Function writes 16-bit address in RF address filter. + * + * \param short_address Given short address + * + * \return none + */ +static void rf_set_short_adr(uint8_t * short_address) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_short_addr_registers(short_address); + /*RF back to sleep*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes PAN Id in RF PAN Id filter. + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_set_pan_id(uint8_t *pan_id) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_pan_id_registers(pan_id); + /*RF back to sleep*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes 64-bit address in RF address filter. + * + * \param address Given 64-bit address + * + * \return none + */ +static void rf_set_address(uint8_t *address) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_ieee_addr_registers(address); + /*RF back to sleep*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function sets the RF channel. + * + * \param ch New channel + * + * \return none + */ +static void rf_channel_set(uint8_t ch) +{ + rf_if_lock(); + rf_phy_channel = ch; + if(ch < 0x1f) + rf_if_set_channel_register(ch); + rf_if_unlock(); +} + + +/* + * \brief Function initialises the radio driver and resets the radio. + * + * \param none + * + * \return none + */ +static void rf_init(void) +{ + /*Reset RF module*/ + rf_if_reset_radio(); + + rf_if_lock(); + + /*Write RF settings*/ + rf_write_settings(); + /*Initialise PHY mode*/ + rf_init_phy_mode(); + /*Clear RF flags*/ + rf_flags_reset(); + /*Set RF in TRX OFF state*/ + rf_if_change_trx_state(TRX_OFF); + /*Set RF in PLL_ON state*/ + rf_if_change_trx_state(PLL_ON); + /*Start receiver*/ + rf_receive(); + /*Read random variable. This will be used when seeding pseudo-random generator*/ + rf_rnd_rssi = rf_if_read_rnd(); + /*Start RF calibration timer*/ + rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); + + rf_if_unlock(); +} + +/** + * \brief Function gets called when MAC is setting radio off. + * + * \param none + * + * \return none + */ +static void rf_off(void) +{ + if(rf_flags_check(RFF_ON)) + { + rf_if_lock(); + rf_cca_abort(); + uint16_t while_counter = 0; + /*Wait while receiving*/ + while(rf_if_read_trx_state() == BUSY_RX_AACK) + { + while_counter++; + if(while_counter == 0xffff) + break; + } + /*RF state change: RX_AACK_ON->PLL_ON->TRX_OFF->SLEEP*/ + if(rf_if_read_trx_state() == RX_AACK_ON) + { + rf_if_change_trx_state(PLL_ON); + } + rf_if_change_trx_state(TRX_OFF); + rf_if_enable_slptr(); + + /*Disable Antenna Diversity*/ + if(rf_use_antenna_diversity) + rf_if_disable_ant_div(); + rf_if_unlock(); + } + + /*Clears all flags*/ + rf_flags_reset(); +} + +/* + * \brief Function polls the RF state until it has changed to desired state. + * + * \param trx_state RF state + * + * \return none + */ +static void rf_poll_trx_state_change(rf_trx_states_t trx_state) +{ + uint16_t while_counter = 0; + rf_if_lock(); + + if(trx_state != RF_TX_START) + { + if(trx_state == FORCE_PLL_ON) + trx_state = PLL_ON; + else if(trx_state == FORCE_TRX_OFF) + trx_state = TRX_OFF; + + while(rf_if_read_trx_state() != trx_state) + { + while_counter++; + if(while_counter == 0x1ff) + break; + } + } + rf_if_unlock(); +} + +/* + * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. + * + * \param data_ptr Pointer to TX data + * \param data_length Length of the TX data + * \param tx_handle Handle to transmission + * \return 0 Success + * \return -1 Busy + */ +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ) +{ + (void)data_protocol; + /*Check if transmitter is busy*/ + if(rf_if_read_trx_state() == BUSY_RX_AACK) + { + /*Return busy*/ + return -1; + } + else + { + rf_if_lock(); + /*Check if transmitted data needs to be acked*/ + if(*data_ptr & 0x20) + need_ack = 1; + else + need_ack = 0; + /*Store the sequence number for ACK handling*/ + tx_sequence = *(data_ptr + 2); + + /*Write TX FIFO*/ + rf_if_write_frame_buffer(data_ptr, (uint8_t)data_length); + rf_flags_set(RFF_CCA); + /*Start CCA timeout*/ + rf_cca_timer_start(RF_CCA_BASE_BACKOFF + randLIB_get_random_in_range(0, RF_CCA_RANDOM_BACKOFF)); + /*Store TX handle*/ + mac_tx_handle = tx_handle; + rf_if_unlock(); + } + + /*Return success*/ + return 0; +} + +/* + * \brief Function aborts CCA process. + * + * \param none + * + * \return none + */ +static void rf_cca_abort(void) +{ + /*Clear RFF_CCA RF flag*/ + rf_flags_clear(RFF_CCA); +} + +/* + * \brief Function starts the transmission of the frame. + * + * \param none + * + * \return none + */ +static void rf_start_tx(void) +{ + /*Only start transmitting from RX state*/ + uint8_t trx_state = rf_if_read_trx_state(); + if(trx_state != RX_AACK_ON) + { + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } + } + else + { + /*RF state change: ->PLL_ON->RF_TX_START*/ + rf_if_change_trx_state(FORCE_PLL_ON); + rf_flags_clear(RFF_RX); + rf_if_enable_tx_end_interrupt(); + rf_flags_set(RFF_TX); + rf_if_change_trx_state(RF_TX_START); + } +} + +/* + * \brief Function sets the RF in RX state. + * + * \param none + * + * \return none + */ +static void rf_receive(void) +{ + uint16_t while_counter = 0; + if(rf_flags_check(RFF_ON) == 0) + { + rf_on(); + } + /*If not yet in RX state set it*/ + if(rf_flags_check(RFF_RX) == 0) + { + rf_if_lock(); + /*Wait while receiving data*/ + while(rf_if_read_trx_state() == BUSY_RX_AACK) + { + while_counter++; + if(while_counter == 0xffff) + { + break; + } + } + + rf_if_change_trx_state(PLL_ON); + + if((rf_mode == RF_MODE_SNIFFER) || (rf_mode == RF_MODE_ED)) + { + rf_if_change_trx_state(RX_ON); + } + else + { + /*ACK is always received in promiscuous mode to bypass address filters*/ + if(rf_rx_mode) + { + rf_rx_mode = 0; + rf_if_enable_promiscuous_mode(); + } + else + { + rf_if_disable_promiscuous_mode(); + } + rf_if_change_trx_state(RX_AACK_ON); + } + /*If calibration timer was unable to calibrate the RF, run calibration now*/ + if(!rf_tuned) + { + /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/ + rf_if_calibration(); + /*RF is tuned now*/ + rf_tuned = 1; + } + + rf_channel_set(rf_phy_channel); + rf_flags_set(RFF_RX); + // Don't receive packets when ED mode enabled + if (rf_mode != RF_MODE_ED) + { + rf_if_enable_rx_end_interrupt(); + } + rf_if_unlock(); + } + /*Stop the running CCA process*/ + if(rf_flags_check(RFF_CCA)) + rf_cca_abort(); +} + +/* + * \brief Function calibrates the radio. + * + * \param none + * + * \return none + */ +static void rf_calibration_cb(void) +{ + /*clear tuned flag to start tuning in rf_receive*/ + rf_tuned = 0; + /*If RF is in default receive state, start calibration*/ + if(rf_if_read_trx_state() == RX_AACK_ON) + { + rf_if_lock(); + /*Set RF in PLL_ON state*/ + rf_if_change_trx_state(PLL_ON); + /*Set RF in TRX_OFF state to start PLL tuning*/ + rf_if_change_trx_state(TRX_OFF); + /*Set RF in RX_ON state to calibrate*/ + rf_if_change_trx_state(RX_ON); + /*Calibrate FTN*/ + rf_if_calibration(); + /*RF is tuned now*/ + rf_tuned = 1; + /*Back to default receive state*/ + rf_flags_clear(RFF_RX); + rf_receive(); + rf_if_unlock(); + } +} + +/* + * \brief Function sets RF_ON flag when radio is powered. + * + * \param none + * + * \return none + */ +static void rf_on(void) +{ + /*Set RFF_ON flag*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_lock(); + rf_flags_set(RFF_ON); + /*Enable Antenna diversity*/ + if(rf_use_antenna_diversity) + /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ + rf_if_enable_ant_div(); + + /*Wake up from sleep state*/ + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + rf_if_unlock(); + } +} + +/* + * \brief Function handles the received ACK frame. + * + * \param seq_number Sequence number of received ACK + * \param data_pending Pending bit state in received ACK + * + * \return none + */ +static void rf_handle_ack(uint8_t seq_number, uint8_t data_pending) +{ + phy_link_tx_status_e phy_status; + rf_if_lock(); + /*Received ACK sequence must be equal with transmitted packet sequence*/ + if(tx_sequence == seq_number) + { + rf_ack_wait_timer_stop(); + /*When data pending bit in ACK frame is set, inform NET library*/ + if(data_pending) + phy_status = PHY_LINK_TX_DONE_PENDING; + else + phy_status = PHY_LINK_TX_DONE; + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle,phy_status, 1, 1); + } + } + rf_if_unlock(); +} + +/* + * \brief Function is a call back for RX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_rx_end(void) +{ + uint8_t rf_lqi = 0; + int8_t rf_rssi = 0; + + /*Start receiver*/ + rf_flags_clear(RFF_RX); + rf_receive(); + + /*Frame received interrupt*/ + if(rf_flags_check(RFF_RX)) + { + /*Check CRC_valid bit*/ + if(rf_if_check_crc()) + { + uint8_t *rf_rx_ptr; + uint8_t receiving_ack = 0; + /*Read length*/ + uint8_t len = rf_if_read_received_frame_length(); + + rf_rx_ptr = rf_buffer; + /*ACK frame*/ + if(len == 5) + { + /*Read ACK in static ACK buffer*/ + receiving_ack = 1; + } + /*Check the length is valid*/ + if(len > 1 && len < RF_BUFFER_SIZE) + { + /*Read received packet*/ + rf_if_read_packet(rf_rx_ptr, len); + + if(!receiving_ack) + { + rf_rssi = rf_if_read_rssi(); + /*Scale LQI using received RSSI*/ + rf_lqi = rf_scale_lqi(rf_rssi); + } + if(rf_mode == RF_MODE_SNIFFER) + { + if( device_driver.phy_rx_cb ){ + device_driver.phy_rx_cb(rf_buffer,len - 2, rf_lqi, rf_rssi, rf_radio_driver_id); + } + } + else + { + /*Handle received ACK*/ + if(receiving_ack && ((rf_buffer[0] & 0x07) == 0x02)) + { + uint8_t pending = 0; + /*Check if data is pending*/ + if ((rf_buffer[0] & 0x10)) + { + pending=1; + } + /*Send sequence number in ACK handler*/ + rf_handle_ack(rf_buffer[2], pending); + } + else + { + if( device_driver.phy_rx_cb ){ + device_driver.phy_rx_cb(rf_buffer,len - 2, rf_lqi, rf_rssi, rf_radio_driver_id); + } + } + } + } + } + } +} + +/* + * \brief Function is called when MAC is shutting down the radio. + * + * \param none + * + * \return none + */ +static void rf_shutdown(void) +{ + /*Call RF OFF*/ + rf_off(); +} + +/* + * \brief Function is a call back for TX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_tx_end(void) +{ + phy_link_tx_status_e phy_status = PHY_LINK_TX_SUCCESS; + + rf_rx_mode = 0; + /*If ACK is needed for this transmission*/ + if(need_ack && rf_flags_check(RFF_TX)) + { + rf_ack_wait_timer_start(rf_ack_wait_duration); + rf_rx_mode = 1; + } + rf_flags_clear(RFF_RX); + /*Start receiver*/ + rf_receive(); + + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 1, 1); + } +} + +/* + * \brief Function is a call back for CCA ED done interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_cca_ed_done(void) +{ + rf_flags_clear(RFF_CCA); + /*Check the result of CCA process*/ + if(rf_if_check_cca()) + { + rf_start_tx(); + } + else + { + /*Send CCA fail notification*/ + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } + } +} + +/* + * \brief Function returns the TX power variable. + * + * \param none + * + * \return radio_tx_power TX power variable + */ +MBED_UNUSED static uint8_t rf_tx_power_get(void) +{ + return radio_tx_power; +} + +/* + * \brief Function enables the usage of Antenna diversity. + * + * \param none + * + * \return 0 Success + */ +MBED_UNUSED static int8_t rf_enable_antenna_diversity(void) +{ + int8_t ret_val = 0; + rf_use_antenna_diversity = 1; + return ret_val; +} + +/* + * \brief Function gives the control of RF states to MAC. + * + * \param new_state RF state + * \param rf_channel RF channel + * + * \return 0 Success + */ +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) + { + /*Reset PHY driver and set to idle*/ + case PHY_INTERFACE_RESET: + break; + /*Disable PHY Interface driver*/ + case PHY_INTERFACE_DOWN: + rf_shutdown(); + break; + /*Enable PHY Interface driver*/ + case PHY_INTERFACE_UP: + rf_mode = RF_MODE_NORMAL; + rf_channel_set(rf_channel); + rf_receive(); + rf_if_enable_irq(); + break; + /*Enable wireless interface ED scan mode*/ + case PHY_INTERFACE_RX_ENERGY_STATE: + rf_mode = RF_MODE_ED; + rf_channel_set(rf_channel); + rf_receive(); + rf_if_disable_irq(); + // Read status to clear pending flags. + rf_if_read_register(IRQ_STATUS); + // Must set interrupt mask to be able to read IRQ status. GPIO interrupt is disabled. + rf_if_set_bit(IRQ_MASK, CCA_ED_DONE, CCA_ED_DONE); + // ED can be initiated by writing arbitrary value to PHY_ED_LEVEL + rf_if_write_register(PHY_ED_LEVEL, 0xff); + break; + case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ + rf_mode = RF_MODE_SNIFFER; + rf_channel_set(rf_channel); + rf_flags_clear(RFF_RX); + rf_receive(); + break; + } + return ret_val; +} + +/* + * \brief Function controls the ACK pending, channel setting and energy detection. + * + * \param extension_type Type of control + * \param data_ptr Data from NET library + * + * \return 0 Success + */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) + { + /*Control MAC pending bit for Indirect data transmission*/ + case PHY_EXTENSION_CTRL_PENDING_BIT: + if(*data_ptr) + { + rf_if_ack_pending_ctrl(1); + } + else + { + rf_if_ack_pending_ctrl(0); + } + break; + /*Return frame pending status*/ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: + *data_ptr = rf_if_last_acked_pending(); + break; + /*Set channel*/ + case PHY_EXTENSION_SET_CHANNEL: + break; + /*Read energy on the channel*/ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + // End of the ED measurement is indicated by CCA_ED_DONE + while (!(rf_if_read_register(IRQ_STATUS) & CCA_ED_DONE)); + // RF input power: RSSI base level + 1[db] * PHY_ED_LEVEL + *data_ptr = rf_sensitivity + rf_if_read_register(PHY_ED_LEVEL); + // Read status to clear pending flags. + rf_if_read_register(IRQ_STATUS); + // Next ED measurement is started, next PHY_EXTENSION_READ_CHANNEL_ENERGY call will return the result. + rf_if_write_register(PHY_ED_LEVEL, 0xff); + break; + /*Read status of the link*/ + case PHY_EXTENSION_READ_LINK_STATUS: + break; + default: + break; + } + return 0; +} + +/* + * \brief Function sets the addresses to RF address filters. + * + * \param address_type Type of address + * \param address_ptr Pointer to given address + * + * \return 0 Success + */ +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + int8_t ret_val = 0; + switch (address_type) + { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + break; + /*Set 64-bit address*/ + case PHY_MAC_64BIT: + rf_set_address(address_ptr); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + rf_set_short_adr(address_ptr); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + rf_set_pan_id(address_ptr); + break; + } + return ret_val; +} + +/* + * \brief Function initialises the ACK wait time and returns the used PHY mode. + * + * \param none + * + * \return tmp Used PHY mode + */ +static void rf_init_phy_mode(void) +{ + uint8_t tmp = 0; + uint8_t part = rf_if_read_part_num(); + /*Read used PHY Mode*/ + tmp = rf_if_read_register(TRX_CTRL_2); + /*Set ACK wait time for used data rate*/ + if(part == PART_AT86RF212) + { + if((tmp & 0x1f) == 0x00) + { + rf_sensitivity = -110; + rf_ack_wait_duration = 938; + tmp = BPSK_20; + } + else if((tmp & 0x1f) == 0x04) + { + rf_sensitivity = -108; + rf_ack_wait_duration = 469; + tmp = BPSK_40; + } + else if((tmp & 0x1f) == 0x14) + { + rf_sensitivity = -108; + rf_ack_wait_duration = 469; + tmp = BPSK_40_ALT; + } + else if((tmp & 0x1f) == 0x08) + { + rf_sensitivity = -101; + rf_ack_wait_duration = 50; + tmp = OQPSK_SIN_RC_100; + } + else if((tmp & 0x1f) == 0x09) + { + rf_sensitivity = -99; + rf_ack_wait_duration = 30; + tmp = OQPSK_SIN_RC_200; + } + else if((tmp & 0x1f) == 0x18) + { + rf_sensitivity = -102; + rf_ack_wait_duration = 50; + tmp = OQPSK_RC_100; + } + else if((tmp & 0x1f) == 0x19) + { + rf_sensitivity = -100; + rf_ack_wait_duration = 30; + tmp = OQPSK_RC_200; + } + else if((tmp & 0x1f) == 0x0c) + { + rf_sensitivity = -100; + rf_ack_wait_duration = 20; + tmp = OQPSK_SIN_250; + } + else if((tmp & 0x1f) == 0x0d) + { + rf_sensitivity = -98; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_500; + } + else if((tmp & 0x1f) == 0x0f) + { + rf_sensitivity = -98; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_500_ALT; + } + else if((tmp & 0x1f) == 0x1c) + { + rf_sensitivity = -101; + rf_ack_wait_duration = 20; + tmp = OQPSK_RC_250; + } + else if((tmp & 0x1f) == 0x1d) + { + rf_sensitivity = -99; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_500; + } + else if((tmp & 0x1f) == 0x1f) + { + rf_sensitivity = -99; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_500_ALT; + } + else if((tmp & 0x3f) == 0x2A) + { + rf_sensitivity = -91; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_RC_400_SCR_ON; + } + else if((tmp & 0x3f) == 0x0A) + { + rf_sensitivity = -91; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_RC_400_SCR_OFF; + } + else if((tmp & 0x3f) == 0x3A) + { + rf_sensitivity = -97; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_400_SCR_ON; + } + else if((tmp & 0x3f) == 0x1A) + { + rf_sensitivity = -97; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_400_SCR_OFF; + } + else if((tmp & 0x3f) == 0x2E) + { + rf_sensitivity = -93; + rf_ack_wait_duration = 13; + tmp = OQPSK_SIN_1000_SCR_ON; + } + else if((tmp & 0x3f) == 0x0E) + { + rf_sensitivity = -93; + rf_ack_wait_duration = 13; + tmp = OQPSK_SIN_1000_SCR_OFF; + } + else if((tmp & 0x3f) == 0x3E) + { + rf_sensitivity = -95; + rf_ack_wait_duration = 13; + tmp = OQPSK_RC_1000_SCR_ON; + } + else if((tmp & 0x3f) == 0x1E) + { + rf_sensitivity = -95; + rf_ack_wait_duration = 13; + tmp = OQPSK_RC_1000_SCR_OFF; + } + } + else + { + rf_sensitivity = -101; + rf_ack_wait_duration = 20; + } + /*Board design might reduces the sensitivity*/ + //rf_sensitivity += RF_SENSITIVITY_CALIBRATION; +} + + +static uint8_t rf_scale_lqi(int8_t rssi) +{ + uint8_t scaled_lqi; + + /*rssi < RF sensitivity*/ + if(rssi < rf_sensitivity) + scaled_lqi=0; + /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/ + /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 10)) + scaled_lqi=31; + /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/ + /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 20)) + scaled_lqi=207; + /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/ + /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 30)) + scaled_lqi=255; + /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/ + /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 40)) + scaled_lqi=255; + /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/ + /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 50)) + scaled_lqi=255; + /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/ + /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 60)) + scaled_lqi=255; + /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/ + /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 70)) + scaled_lqi=255; + /*rssi > RF saturation*/ + else if(rssi > (rf_sensitivity + 80)) + scaled_lqi=111; + /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/ + /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/ + else + scaled_lqi=255; + + return scaled_lqi; +} + +NanostackRfPhyAtmel::NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, + PinName i2c_sda, PinName i2c_scl) + : _mac(i2c_sda, i2c_scl), _mac_addr(), _rf(NULL), _mac_set(false), + _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk), + _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq) +{ + _rf = new RFBits(_spi_mosi, _spi_miso, _spi_sclk, _spi_cs, _spi_rst, _spi_slp, _spi_irq); +} + +NanostackRfPhyAtmel::~NanostackRfPhyAtmel() +{ + delete _rf; +} + +int8_t NanostackRfPhyAtmel::rf_register() +{ + if (NULL == _rf) { + return -1; + } + + rf_if_lock(); + + if (rf != NULL) { + rf_if_unlock(); + error("Multiple registrations of NanostackRfPhyAtmel not supported"); + return -1; + } + + // Read the mac address if it hasn't been set by a user + rf = _rf; + if (!_mac_set) { + int ret = _mac.read_eui64((void*)_mac_addr); + if (ret < 0) { + rf = NULL; + rf_if_unlock(); + return -1; + } + } + + int8_t radio_id = rf_device_register(_mac_addr); + if (radio_id < 0) { + rf = NULL; + } + + rf_if_unlock(); + return radio_id; +} + +void NanostackRfPhyAtmel::rf_unregister() +{ + rf_if_lock(); + + if (NULL == rf) { + rf_if_unlock(); + return; + } + + rf_device_unregister(); + rf = NULL; + + rf_if_unlock(); +} + +void NanostackRfPhyAtmel::get_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL == rf) { + error("NanostackRfPhyAtmel Must be registered to read mac address"); + rf_if_unlock(); + return; + } + memcpy((void*)mac, (void*)_mac_addr, sizeof(_mac_addr)); + + rf_if_unlock(); +} + +void NanostackRfPhyAtmel::set_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL != rf) { + error("NanostackRfPhyAtmel cannot change mac address when running"); + rf_if_unlock(); + return; + } + memcpy((void*)_mac_addr, (void*)mac, sizeof(_mac_addr)); + _mac_set = true; + + rf_if_unlock(); +} +
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/source/at24mac.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/at24mac.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016-2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "at24mac.h" + +/* Device addressing */ +#define AT24MAC_EEPROM_ADDRESS (0x0A<<4) +#define AT24MAC_RW_PROTECT_ADDRESS (0x06<<4) +#define AT24MAC_SERIAL_ADDRESS (0x0B<<4) + +/* Known memory blocks */ +#define AT24MAC_SERIAL_OFFSET (0x80) +#define AT24MAC_EUI64_OFFSET (0x98) +#define AT24MAC_EUI48_OFFSET (0x9A) + +#define SERIAL_LEN 16 +#define EUI64_LEN 8 +#define EUI48_LEN 6 + +AT24Mac::AT24Mac(PinName sda, PinName scl) : _i2c(sda, scl) +{ + // Do nothing +} + +int AT24Mac::read_serial(void *buf) +{ + char offset = AT24MAC_SERIAL_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) + return -1; //No ACK + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, SERIAL_LEN); +} + +int AT24Mac::read_eui64(void *buf) +{ + char offset = AT24MAC_EUI64_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) + return -1; //No ACK + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, EUI64_LEN); +} + +int AT24Mac::read_eui48(void *buf) +{ + char offset = AT24MAC_EUI48_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) + return -1; //No ACK + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, EUI48_LEN); +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/atmel-rf-driver/source/at24mac.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/at24mac.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AT24MAC_H +#define AT24MAC_H + +#include "PinNames.h" +#include "I2C.h" + +/* + * AT24MAC drivers. + * + * This is a EEPROM chip designed to contain factory programmed read-only EUI-64 or EUI-48, + * a 128bit serial number and some user programmable EEPROM. + * + * AT24MAC602 contains EUI-64, use read_eui64() + * AT24MAC402 contains EUI-64, use read_eui48() + * + * NOTE: You cannot use both EUI-64 and EUI-48. Chip contains only one of those. + */ + +class AT24Mac { +public: + AT24Mac(PinName sda, PinName scl); + + /** + * Read unique serial number from chip. + * \param buf pointer to write serial number to. Must have space for 16 bytes. + * \return zero on success, negative number on failure + */ + int read_serial(void *buf); + + /** + * Read EUI-64 from chip. + * \param buf pointer to write EUI-64 to. Must have space for 8 bytes. + * \return zero on success, negative number on failure + */ + int read_eui64(void *buf); + + /** + * Read EUI-48 from chip. + * \param buf pointer to write EUI-48 to. Must have space for 6 bytes. + * \return zero on success, negative number on failure + */ + int read_eui48(void *buf); + +private: + mbed::I2C _i2c; +}; + +#endif /* AT24MAC_H */
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/easy-connect.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/easy-connect.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,135 @@ +#ifndef __MAGIC_CONNECT_H__ +#define __MAGIC_CONNECT_H__ + +#include "mbed.h" + +Serial pc(USBTX, USBRX); + +/*#if USE_LCD + +#include "C12832.h" +// the actual pins are defined in mbed_app.json and can be overridden per target +//C12832 lcd(LCD_MOSI, LCD_SCK, LCD_MISO, LCD_A0, LCD_NCS); +C12832 lcd(p5, p7, p6, p8, p11); + +#define logMessage1 wait(2);lcd.cls();lcd.locate(0,3);lcd.printf +#define logMessage2 wait(2);lcd.cls();lcd.locate(0,15);lcd.printf + +#else //use serial printf + +#define logMessage1 pc.printf +#define logMessage2 pc.printf + +#endif +*/ + +#define ETHERNET 1 +#define WIFI_ESP8266 2 +#define MESH_LOWPAN_ND 3 +#define MESH_THREAD 4 + +#if MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ESP8266 +#include "ESP8266Interface.h" + +#ifdef MBED_CONF_APP_ESP8266_DEBUG +ESP8266Interface esp(MBED_CONF_APP_ESP8266_TX, MBED_CONF_APP_ESP8266_RX, MBED_CONF_APP_ESP8266_DEBUG); +#else +ESP8266Interface esp(MBED_CONF_APP_ESP8266_TX, MBED_CONF_APP_ESP8266_RX); +#endif + +#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET +#include "EthernetInterface.h" +EthernetInterface eth; +#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_LOWPAN_ND +#define MESH +#include "NanostackInterface.h" +LoWPANNDInterface mesh; +#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_THREAD +#define MESH +#include "NanostackInterface.h" +ThreadInterface mesh; +#else +#error "No connectivity method chosen. Please add 'config.network-interfaces.value' to your mbed_app.json (see README.md for more information)." +#endif + +#if defined(MESH) +#if MBED_CONF_APP_MESH_RADIO_TYPE == ATMEL +#include "NanostackRfPhyAtmel.h" +NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS, + ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL); +#elif MBED_CONF_APP_MESH_RADIO_TYPE == MCR20 +#include "NanostackRfPhyMcr20a.h" +NanostackRfPhyMcr20a rf_phy(MCR20A_SPI_MOSI, MCR20A_SPI_MISO, MCR20A_SPI_SCLK, MCR20A_SPI_CS, MCR20A_SPI_RST, MCR20A_SPI_IRQ); +#endif //MBED_CONF_APP_RADIO_TYPE +#endif //MESH + +#ifndef MESH +// This is address to mbed Device Connector +#define MBED_SERVER_ADDRESS "coap://api.connector.mbed.com:5684" +#else +// This is address to mbed Device Connector +#define MBED_SERVER_ADDRESS "coaps://[2607:f0d0:2601:52::20]:5684" +#endif + +const char *ip_addr1 = 0; + +NetworkInterface* easy_connect(bool log_messages = false) { + NetworkInterface* network_interface = 0; + int connect_success = -1; +#if MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ESP8266 + if (log_messages) { + pc.printf("[EasyConnect] Using WiFi (ESP8266) \r\n"); + pc.printf("[EasyConnect] Connecting to WiFi..\r\n"); + logMessage1("Using WiFi (ESP8266) \r\n"); + logMessage2("Connecting to WiFi..\r\n"); + } + + //connect_success = esp.connect(NETWORK_ID,NETWORK_PASSWORD); + connect_success = esp.connect(NETWORK_ID,NETWORK_PASSWORD);//(MBED_CONF_APP_ESP8266_SSID, MBED_CONF_APP_ESP8266_PASSWORD); + //connect_success = esp.connect("eir89748912-2.4G","38rb44zb");//(MBED_CONF_APP_ESP8266_SSID, MBED_CONF_APP_ESP8266_PASSWORD); + network_interface = &esp; +#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET + if (log_messages) { + pc.printf("[EasyConnect] Using Ethernet\r\n"); + } + connect_success = eth.connect(); + network_interface = ð +#endif +#ifdef MESH + if (log_messages) { + pc.printf("[EasyConnect] Using Mesh\r\n"); + pc.printf("[EasyConnect] Connecting to Mesh..\r\n"); + } + connect_success = mesh.connect(); + network_interface = &mesh; +#endif + if(connect_success == 0) { + const char *ip_addr = network_interface->get_ip_address(); + ip_addr1 = ip_addr; + + if (log_messages) { + pc.printf("[EasyConnect] Connected to Network successfully\r\n"); + logMessage1("Connected successfully\r\n"); + } + } else { + if (log_messages) { + pc.printf("[EasyConnect] Connection to Network Failed %d!\r\n", connect_success); + } + return NULL; + } + if (log_messages) { + const char *ip_addr = network_interface->get_ip_address(); + ip_addr1 = ip_addr; + + if (ip_addr) { + pc.printf("[EasyConnect] IP address %s\r\n", ip_addr); + logMessage2("IP address %s\r\n", ip_addr); + ip_addr1 = ip_addr; + } else { + pc.printf("[EasyConnect] No IP address\r\n"); + } + } + return network_interface; +} + +#endif // __MAGIC_CONNECT_H__
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/ATParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/ATParser.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,333 @@ +/* Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @section DESCRIPTION + * + * Parser for the AT command syntax + * + */ + +#include "ATParser.h" +#include "mbed_debug.h" + + +// getc/putc handling with timeouts +int ATParser::putc(char c) +{ + Timer timer; + timer.start(); + + while (true) { + if (_serial->writeable()) { + return _serial->putc(c); + } + if (timer.read_ms() > _timeout) { + return -1; + } + } +} + +int ATParser::getc() +{ + Timer timer; + timer.start(); + + while (true) { + if (_serial->readable()) { + return _serial->getc(); + } + if (timer.read_ms() > _timeout) { + return -1; + } + } +} + +void ATParser::flush() +{ + while (_serial->readable()) { + _serial->getc(); + } +} + + +// read/write handling with timeouts +int ATParser::write(const char *data, int size) +{ + int i = 0; + for ( ; i < size; i++) { + if (putc(data[i]) < 0) { + return -1; + } + } + return i; +} + +int ATParser::read(char *data, int size) +{ + int i = 0; + for ( ; i < size; i++) { + int c = getc(); + if (c < 0) { + return -1; + } + data[i] = c; + } + return i; +} + + +// printf/scanf handling +int ATParser::vprintf(const char *format, va_list args) +{ + if (vsprintf(_buffer, format, args) < 0) { + return false; + } + int i = 0; + for ( ; _buffer[i]; i++) { + if (putc(_buffer[i]) < 0) { + return -1; + } + } + return i; +} + +int ATParser::vscanf(const char *format, va_list args) +{ + // Since format is const, we need to copy it into our buffer to + // add the line's null terminator and clobber value-matches with asterisks. + // + // We just use the beginning of the buffer to avoid unnecessary allocations. + int i = 0; + int offset = 0; + + while (format[i]) { + if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _buffer[offset++] = format[i++]; + } + } + + // Scanf has very poor support for catching errors + // fortunately, we can abuse the %n specifier to determine + // if the entire string was matched. + _buffer[offset++] = '%'; + _buffer[offset++] = 'n'; + _buffer[offset++] = 0; + + // To workaround scanf's lack of error reporting, we actually + // make two passes. One checks the validity with the modified + // format string that only stores the matched characters (%n). + // The other reads in the actual matched values. + // + // We keep trying the match until we succeed or some other error + // derails us. + int j = 0; + + while (true) { + // Ran out of space + if (j+1 >= _buffer_size - offset) { + return false; + } + // Recieve next character + int c = getc(); + if (c < 0) { + return -1; + } + _buffer[offset + j++] = c; + _buffer[offset + j] = 0; + + // Check for match + int count = -1; + sscanf(_buffer+offset, _buffer, &count); + + // We only succeed if all characters in the response are matched + if (count == j) { + // Store the found results + vsscanf(_buffer+offset, format, args); + return j; + } + } +} + + +// Command parsing with line handling +bool ATParser::vsend(const char *command, va_list args) +{ + // Create and send command + if (vsprintf(_buffer, command, args) < 0) { + return false; + } + for (int i = 0; _buffer[i]; i++) { + if (putc(_buffer[i]) < 0) { + return false; + } + } + + // Finish with newline + for (int i = 0; _delimiter[i]; i++) { + if (putc(_delimiter[i]) < 0) { + return false; + } + } + + debug_if(dbg_on, "AT> %s\r\n", _buffer); + return true; +} + +bool ATParser::vrecv(const char *response, va_list args) +{ + // Iterate through each line in the expected response + while (response[0]) { + // Since response is const, we need to copy it into our buffer to + // add the line's null terminator and clobber value-matches with asterisks. + // + // We just use the beginning of the buffer to avoid unnecessary allocations. + int i = 0; + int offset = 0; + + while (response[i]) { + if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) { + i++; + break; + } else if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _buffer[offset++] = response[i++]; + } + } + + // Scanf has very poor support for catching errors + // fortunately, we can abuse the %n specifier to determine + // if the entire string was matched. + _buffer[offset++] = '%'; + _buffer[offset++] = 'n'; + _buffer[offset++] = 0; + + // To workaround scanf's lack of error reporting, we actually + // make two passes. One checks the validity with the modified + // format string that only stores the matched characters (%n). + // The other reads in the actual matched values. + // + // We keep trying the match until we succeed or some other error + // derails us. + int j = 0; + + while (true) { + // Recieve next character + int c = getc(); + if (c < 0) { + return false; + } + _buffer[offset + j++] = c; + _buffer[offset + j] = 0; + + // Check for oob data + for (int k = 0; k < _oobs.size(); k++) { + if (j == _oobs[k].len && memcmp( + _oobs[k].prefix, _buffer+offset, _oobs[k].len) == 0) { + debug_if(dbg_on, "AT! %s\r\n", _oobs[k].prefix); + _oobs[k].cb(); + + // oob may have corrupted non-reentrant buffer, + // so we need to set it up again + return vrecv(response, args); + } + } + + // Check for match + int count = -1; + sscanf(_buffer+offset, _buffer, &count); + + // We only succeed if all characters in the response are matched + if (count == j) { + debug_if(dbg_on, "AT= %s\r\n", _buffer+offset); + // Reuse the front end of the buffer + memcpy(_buffer, response, i); + _buffer[i] = 0; + + // Store the found results + vsscanf(_buffer+offset, _buffer, args); + + // Jump to next line and continue parsing + response += i; + break; + } + + // Clear the buffer when we hit a newline or ran out of space + // running out of space usually means we ran into binary data + if (j+1 >= _buffer_size - offset || + strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { + + debug_if(dbg_on, "AT< %s", _buffer+offset); + j = 0; + } + } + } + + return true; +} + + +// Mapping to vararg functions +int ATParser::printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int res = vprintf(format, args); + va_end(args); + return res; +} + +int ATParser::scanf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int res = vscanf(format, args); + va_end(args); + return res; +} + +bool ATParser::send(const char *command, ...) +{ + va_list args; + va_start(args, command); + bool res = vsend(command, args); + va_end(args); + return res; +} + +bool ATParser::recv(const char *response, ...) +{ + va_list args; + va_start(args, response); + bool res = vrecv(response, args); + va_end(args); + return res; +} + + +// oob registration +void ATParser::oob(const char *prefix, Callback<void()> cb) +{ + struct oob oob; + oob.len = strlen(prefix); + oob.prefix = prefix; + oob.cb = cb; + _oobs.push_back(oob); +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/ATParser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/ATParser.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,232 @@ +/* Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @section DESCRIPTION + * + * Parser for the AT command syntax + * + */ + +#include "mbed.h" +#include <cstdarg> +#include <vector> +#include "BufferedSerial.h" +#include "Callback.h" + + +/** +* Parser class for parsing AT commands +* +* Here are some examples: +* @code +* ATParser at = ATParser(serial, "\r\n"); +* int value; +* char buffer[100]; +* +* at.send("AT") && at.recv("OK"); +* at.send("AT+CWMODE=%d", 3) && at.recv("OK"); +* at.send("AT+CWMODE?") && at.recv("+CWMODE:%d\r\nOK", &value); +* at.recv("+IPD,%d:", &value); +* at.read(buffer, value); +* at.recv("OK"); +* @endcode +*/ +class ATParser +{ +private: + // Serial information + BufferedSerial *_serial; + int _buffer_size; + char *_buffer; + int _timeout; + + // Parsing information + const char *_delimiter; + int _delim_size; + bool dbg_on; + + struct oob { + unsigned len; + const char *prefix; + mbed::Callback<void()> cb; + }; + std::vector<oob> _oobs; + +public: + /** + * Constructor + * + * @param serial serial interface to use for AT commands + * @param buffer_size size of internal buffer for transaction + * @param timeout timeout of the connection + * @param delimiter string of characters to use as line delimiters + */ + ATParser(BufferedSerial &serial, const char *delimiter = "\r\n", int buffer_size = 256, int timeout = 8000, bool debug = false) : + _serial(&serial), + _buffer_size(buffer_size) { + _buffer = new char[buffer_size]; + setTimeout(timeout); + setDelimiter(delimiter); + debugOn(debug); + } + + /** + * Destructor + */ + ~ATParser() { + delete [] _buffer; + } + + /** + * Allows timeout to be changed between commands + * + * @param timeout timeout of the connection + */ + void setTimeout(int timeout) { + _timeout = timeout; + } + + /** + * Sets string of characters to use as line delimiters + * + * @param delimiter string of characters to use as line delimiters + */ + void setDelimiter(const char *delimiter) { + _delimiter = delimiter; + _delim_size = strlen(delimiter); + } + + /** + * Allows echo to be on or off + * + * @param echo 1 for echo and 0 turns it off + */ + void debugOn(uint8_t on) { + dbg_on = (on) ? 1 : 0; + } + + /** + * Sends an AT command + * + * Sends a formatted command using printf style formatting + * @see ::printf + * + * @param command printf-like format string of command to send which + * is appended with the specified delimiter + * @param ... all printf-like arguments to insert into command + * @return true only if command is successfully sent + */ + bool send(const char *command, ...); + bool vsend(const char *command, va_list args); + + /** + * Recieve an AT response + * + * Recieves a formatted response using scanf style formatting + * @see ::scanf + * + * Responses are parsed line at a time using the specified delimiter. + * Any recieved data that does not match the response is ignored until + * a timeout occurs. + * + * @param response scanf-like format string of response to expect + * @param ... all scanf-like arguments to extract from response + * @return true only if response is successfully matched + */ + bool recv(const char *response, ...); + bool vrecv(const char *response, va_list args); + + /** + * Write a single byte to the underlying stream + * + * @param c The byte to write + * @return The byte that was written or -1 during a timeout + */ + int putc(char c); + + /** + * Get a single byte from the underlying stream + * + * @return The byte that was read or -1 during a timeout + */ + int getc(); + + /** + * Write an array of bytes to the underlying stream + * + * @param data the array of bytes to write + * @param size number of bytes to write + * @return number of bytes written or -1 on failure + */ + int write(const char *data, int size); + + /** + * Read an array of bytes from the underlying stream + * + * @param data the destination for the read bytes + * @param size number of bytes to read + * @return number of bytes read or -1 on failure + */ + int read(char *data, int size); + + /** + * Direct printf to underlying stream + * @see ::printf + * + * @param format format string to pass to printf + * @param ... arguments to printf + * @return number of bytes written or -1 on failure + */ + int printf(const char *format, ...); + int vprintf(const char *format, va_list args); + + /** + * Direct scanf on underlying stream + * @see ::scanf + * + * @param format format string to pass to scanf + * @param ... arguments to scanf + * @return number of bytes read or -1 on failure + */ + int scanf(const char *format, ...); + int vscanf(const char *format, va_list args); + + /** + * Attach a callback for out-of-band data + * + * @param prefix string on when to initiate callback + * @param func callback to call when string is read + * @note out-of-band data is only processed during a scanf call + */ + void oob(const char *prefix, mbed::Callback<void()> func); + + /** + * Attach a callback for out-of-band data + * + * @param prefix string on when to initiate callback + * @param obj pointer to object to call member function on + * @param method callback to call when string is read + * @note out-of-band data is only processed during a scanf call + */ + template <typename T, typename M> + void oob(const char *prefix, T *obj, M method) { + return oob(prefix, mbed::Callback<void()>(obj, method)); + } + + /** + * Flushes the underlying stream + */ + void flush(); +}; +
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/Buffer/MyBuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/Buffer/MyBuffer.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,76 @@ + +/** + * @file Buffer.cpp + * @brief Software Buffer - Templated Ring Buffer for most data types + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MyBuffer.h" + +template <class T> +MyBuffer<T>::MyBuffer(uint32_t size) +{ + _buf = new T [size]; + _size = size; + clear(); + + return; +} + +template <class T> +MyBuffer<T>::~MyBuffer() +{ + delete [] _buf; + + return; +} + +template <class T> +uint32_t MyBuffer<T>::getSize() +{ + return this->_size; +} + +template <class T> +void MyBuffer<T>::clear(void) +{ + _wloc = 0; + _rloc = 0; + memset(_buf, 0, _size); + + return; +} + +template <class T> +uint32_t MyBuffer<T>::peek(char c) +{ + return 1; +} + +// make the linker aware of some possible types +template class MyBuffer<uint8_t>; +template class MyBuffer<int8_t>; +template class MyBuffer<uint16_t>; +template class MyBuffer<int16_t>; +template class MyBuffer<uint32_t>; +template class MyBuffer<int32_t>; +template class MyBuffer<uint64_t>; +template class MyBuffer<int64_t>; +template class MyBuffer<char>; +template class MyBuffer<wchar_t>;
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/Buffer/MyBuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/Buffer/MyBuffer.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,163 @@ + +/** + * @file Buffer.h + * @brief Software Buffer - Templated Ring Buffer for most data types + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYBUFFER_H +#define MYBUFFER_H + +#include <stdint.h> +#include <string.h> + +/** A templated software ring buffer + * + * Example: + * @code + * #include "mbed.h" + * #include "MyBuffer.h" + * + * MyBuffer <char> buf; + * + * int main() + * { + * buf = 'a'; + * buf.put('b'); + * char *head = buf.head(); + * puts(head); + * + * char whats_in_there[2] = {0}; + * int pos = 0; + * + * while(buf.available()) + * { + * whats_in_there[pos++] = buf; + * } + * printf("%c %c\n", whats_in_there[0], whats_in_there[1]); + * buf.clear(); + * error("done\n\n\n"); + * } + * @endcode + */ + +template <typename T> +class MyBuffer +{ +private: + T *_buf; + volatile uint32_t _wloc; + volatile uint32_t _rloc; + uint32_t _size; + +public: + /** Create a Buffer and allocate memory for it + * @param size The size of the buffer + */ + MyBuffer(uint32_t size = 0x100); + + /** Get the size of the ring buffer + * @return the size of the ring buffer + */ + uint32_t getSize(); + + /** Destry a Buffer and release it's allocated memory + */ + ~MyBuffer(); + + /** Add a data element into the buffer + * @param data Something to add to the buffer + */ + void put(T data); + + /** Remove a data element from the buffer + * @return Pull the oldest element from the buffer + */ + T get(void); + + /** Get the address to the head of the buffer + * @return The address of element 0 in the buffer + */ + T *head(void); + + /** Reset the buffer to 0. Useful if using head() to parse packeted data + */ + void clear(void); + + /** Determine if anything is readable in the buffer + * @return 1 if something can be read, 0 otherwise + */ + uint32_t available(void); + + /** Overloaded operator for writing to the buffer + * @param data Something to put in the buffer + * @return + */ + MyBuffer &operator= (T data) + { + put(data); + return *this; + } + + /** Overloaded operator for reading from the buffer + * @return Pull the oldest element from the buffer + */ + operator int(void) + { + return get(); + } + + uint32_t peek(char c); + +}; + +template <class T> +inline void MyBuffer<T>::put(T data) +{ + _buf[_wloc++] = data; + _wloc %= (_size-1); + + return; +} + +template <class T> +inline T MyBuffer<T>::get(void) +{ + T data_pos = _buf[_rloc++]; + _rloc %= (_size-1); + + return data_pos; +} + +template <class T> +inline T *MyBuffer<T>::head(void) +{ + T *data_pos = &_buf[0]; + + return data_pos; +} + +template <class T> +inline uint32_t MyBuffer<T>::available(void) +{ + return (_wloc == _rloc) ? 0 : 1; +} + +#endif +
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/BufferedPrint.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/BufferedPrint.c Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "mbed_error.h" + +size_t BufferedSerialThunk(void *buf_serial, const void *s, size_t length); + +int BufferedPrintfC(void *stream, int size, const char* format, va_list arg) +{ + int r; + char buffer[512]; + if (size >= 512) { + return -1; + } + memset(buffer, 0, size); + r = vsprintf(buffer, format, arg); + // this may not hit the heap but should alert the user anyways + if(r > (int32_t) size) { + error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__, size, r); + return 0; + } + if ( r > 0 ) { + BufferedSerialThunk(stream, buffer, r); + } + return r; +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/BufferedSerial.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/BufferedSerial.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,166 @@ +/** + * @file BufferedSerial.cpp + * @brief Software Buffer - Extends mbed Serial functionallity adding irq driven TX and RX + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BufferedSerial.h" +#include <stdarg.h> + +extern "C" int BufferedPrintfC(void *stream, int size, const char* format, va_list arg); + +BufferedSerial::BufferedSerial(PinName tx, PinName rx, uint32_t buf_size, uint32_t tx_multiple, const char* name) + : RawSerial(tx, rx) , _rxbuf(buf_size), _txbuf((uint32_t)(tx_multiple*buf_size)) +{ + RawSerial::attach(this, &BufferedSerial::rxIrq, Serial::RxIrq); + this->_buf_size = buf_size; + this->_tx_multiple = tx_multiple; + return; +} + +BufferedSerial::~BufferedSerial(void) +{ + RawSerial::attach(NULL, RawSerial::RxIrq); + RawSerial::attach(NULL, RawSerial::TxIrq); + + return; +} + +int BufferedSerial::readable(void) +{ + return _rxbuf.available(); // note: look if things are in the buffer +} + +int BufferedSerial::writeable(void) +{ + return 1; // buffer allows overwriting by design, always true +} + +int BufferedSerial::getc(void) +{ + return _rxbuf; +} + +int BufferedSerial::putc(int c) +{ + _txbuf = (char)c; + BufferedSerial::prime(); + + return c; +} + +int BufferedSerial::puts(const char *s) +{ + if (s != NULL) { + const char* ptr = s; + + while(*(ptr) != 0) { + _txbuf = *(ptr++); + } + _txbuf = '\n'; // done per puts definition + BufferedSerial::prime(); + + return (ptr - s) + 1; + } + return 0; +} + +extern "C" size_t BufferedSerialThunk(void *buf_serial, const void *s, size_t length) +{ + BufferedSerial *buffered_serial = (BufferedSerial *)buf_serial; + return buffered_serial->write(s, length); +} + +int BufferedSerial::printf(const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int r = BufferedPrintfC((void*)this, this->_buf_size, format, arg); + va_end(arg); + return r; +} + +ssize_t BufferedSerial::write(const void *s, size_t length) +{ + if (s != NULL && length > 0) { + const char* ptr = (const char*)s; + const char* end = ptr + length; + + while (ptr != end) { + _txbuf = *(ptr++); + } + BufferedSerial::prime(); + + return ptr - (const char*)s; + } + return 0; +} + + +void BufferedSerial::rxIrq(void) +{ + // read from the peripheral and make sure something is available + if(serial_readable(&_serial)) { + _rxbuf = serial_getc(&_serial); // if so load them into a buffer + // trigger callback if necessary + if (_cbs[RxIrq]) { + _cbs[RxIrq](); + } + } + + return; +} + +void BufferedSerial::txIrq(void) +{ + // see if there is room in the hardware fifo and if something is in the software fifo + while(serial_writable(&_serial)) { + if(_txbuf.available()) { + serial_putc(&_serial, (int)_txbuf.get()); + } else { + // disable the TX interrupt when there is nothing left to send + RawSerial::attach(NULL, RawSerial::TxIrq); + // trigger callback if necessary + if (_cbs[TxIrq]) { + _cbs[TxIrq](); + } + break; + } + } + + return; +} + +void BufferedSerial::prime(void) +{ + // if already busy then the irq will pick this up + if(serial_writable(&_serial)) { + RawSerial::attach(NULL, RawSerial::TxIrq); // make sure not to cause contention in the irq + BufferedSerial::txIrq(); // only write to hardware in one place + RawSerial::attach(this, &BufferedSerial::txIrq, RawSerial::TxIrq); + } + + return; +} + +void BufferedSerial::attach(Callback<void()> func, IrqType type) +{ + _cbs[type] = func; +} +
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/BufferedSerial.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ATParser/BufferedSerial/BufferedSerial.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,168 @@ + +/** + * @file BufferedSerial.h + * @brief Software Buffer - Extends mbed Serial functionallity adding irq driven TX and RX + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BUFFEREDSERIAL_H +#define BUFFEREDSERIAL_H + +#include "mbed.h" +#include "MyBuffer.h" + +/** A serial port (UART) for communication with other serial devices + * + * Can be used for Full Duplex communication, or Simplex by specifying + * one pin as NC (Not Connected) + * + * Example: + * @code + * #include "mbed.h" + * #include "BufferedSerial.h" + * + * BufferedSerial pc(USBTX, USBRX); + * + * int main() + * { + * while(1) + * { + * Timer s; + * + * s.start(); + * pc.printf("Hello World - buffered\n"); + * int buffered_time = s.read_us(); + * wait(0.1f); // give time for the buffer to empty + * + * s.reset(); + * printf("Hello World - blocking\n"); + * int polled_time = s.read_us(); + * s.stop(); + * wait(0.1f); // give time for the buffer to empty + * + * pc.printf("printf buffered took %d us\n", buffered_time); + * pc.printf("printf blocking took %d us\n", polled_time); + * wait(0.5f); + * } + * } + * @endcode + */ + +/** + * @class BufferedSerial + * @brief Software buffers and interrupt driven tx and rx for Serial + */ +class BufferedSerial : public RawSerial +{ +private: + MyBuffer <char> _rxbuf; + MyBuffer <char> _txbuf; + uint32_t _buf_size; + uint32_t _tx_multiple; + + void rxIrq(void); + void txIrq(void); + void prime(void); + + Callback<void()> _cbs[2]; + +public: + /** Create a BufferedSerial port, connected to the specified transmit and receive pins + * @param tx Transmit pin + * @param rx Receive pin + * @param buf_size printf() buffer size + * @param tx_multiple amount of max printf() present in the internal ring buffer at one time + * @param name optional name + * @note Either tx or rx may be specified as NC if unused + */ + BufferedSerial(PinName tx, PinName rx, uint32_t buf_size = 256, uint32_t tx_multiple = 4,const char* name=NULL); + + /** Destroy a BufferedSerial port + */ + virtual ~BufferedSerial(void); + + /** Check on how many bytes are in the rx buffer + * @return 1 if something exists, 0 otherwise + */ + virtual int readable(void); + + /** Check to see if the tx buffer has room + * @return 1 always has room and can overwrite previous content if too small / slow + */ + virtual int writeable(void); + + /** Get a single byte from the BufferedSerial Port. + * Should check readable() before calling this. + * @return A byte that came in on the Serial Port + */ + virtual int getc(void); + + /** Write a single byte to the BufferedSerial Port. + * @param c The byte to write to the Serial Port + * @return The byte that was written to the Serial Port Buffer + */ + virtual int putc(int c); + + /** Write a string to the BufferedSerial Port. Must be NULL terminated + * @param s The string to write to the Serial Port + * @return The number of bytes written to the Serial Port Buffer + */ + virtual int puts(const char *s); + + /** Write a formatted string to the BufferedSerial Port. + * @param format The string + format specifiers to write to the Serial Port + * @return The number of bytes written to the Serial Port Buffer + */ + virtual int printf(const char* format, ...); + + /** Write data to the Buffered Serial Port + * @param s A pointer to data to send + * @param length The amount of data being pointed to + * @return The number of bytes written to the Serial Port Buffer + */ + virtual ssize_t write(const void *s, std::size_t length); + + /** Attach a function to call whenever a serial interrupt is generated + * @param func A pointer to a void function, or 0 to set as none + * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty) + */ + virtual void attach(Callback<void()> func, IrqType type=RxIrq); + + /** Attach a member function to call whenever a serial interrupt is generated + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template <typename T> + void attach(T *obj, void (T::*method)(), IrqType type=RxIrq) { + attach(Callback<void()>(obj, method), type); + } + + /** Attach a member function to call whenever a serial interrupt is generated + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template <typename T> + void attach(T *obj, void (*method)(T*), IrqType type=RxIrq) { + attach(Callback<void()>(obj, method), type); + } +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ESP8266.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ESP8266.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,306 @@ +/* ESP8266 Example + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ESP8266.h" + +ESP8266::ESP8266(PinName tx, PinName rx, bool debug) + : _serial(tx, rx, 1024), _parser(_serial) + , _packets(0), _packets_end(&_packets) +{ + _serial.baud(115200); + _parser.debugOn(debug); +} + +bool ESP8266::startup(int mode) +{ + //only 3 valid modes + if(mode < 1 || mode > 3) { + return false; + } + + bool success = reset() + && _parser.send("AT+CWMODE=%d", mode) + && _parser.recv("OK") + && _parser.send("AT+CIPMUX=1") + && _parser.recv("OK"); + + _parser.oob("+IPD", this, &ESP8266::_packet_handler); + + return success; +} + +bool ESP8266::reset(void) +{ + for (int i = 0; i < 2; i++) { + if (_parser.send("AT+RST") + && _parser.recv("OK\r\nready")) { + return true; + } + } + + return false; +} + +bool ESP8266::dhcp(bool enabled, int mode) +{ + //only 3 valid modes + if(mode < 0 || mode > 2) { + return false; + } + + return _parser.send("AT+CWDHCP=%d,%d", enabled?1:0, mode) + && _parser.recv("OK"); +} + +bool ESP8266::connect(const char *ap, const char *passPhrase) +{ + return _parser.send("AT+CWJAP=\"%s\",\"%s\"", ap, passPhrase) + && _parser.recv("OK"); +} + +bool ESP8266::disconnect(void) +{ + return _parser.send("AT+CWQAP") && _parser.recv("OK"); +} + +const char *ESP8266::getIPAddress(void) +{ + if (!(_parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer) + && _parser.recv("OK"))) { + return 0; + } + + return _ip_buffer; +} + +const char *ESP8266::getMACAddress(void) +{ + if (!(_parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer) + && _parser.recv("OK"))) { + return 0; + } + + return _mac_buffer; +} + +const char *ESP8266::getGateway() +{ + if (!(_parser.send("AT+CIPSTA?") + && _parser.recv("+CIPSTA:gateway:\"%15[^\"]\"", _gateway_buffer) + && _parser.recv("OK"))) { + return 0; + } + + return _gateway_buffer; +} + +const char *ESP8266::getNetmask() +{ + if (!(_parser.send("AT+CIPSTA?") + && _parser.recv("+CIPSTA:netmask:\"%15[^\"]\"", _netmask_buffer) + && _parser.recv("OK"))) { + return 0; + } + + return _netmask_buffer; +} + +int8_t ESP8266::getRSSI() +{ + int8_t rssi; + char bssid[18]; + + if (!(_parser.send("AT+CWJAP?") + && _parser.recv("+CWJAP:\"%*[^\"]\",\"%17[^\"]\"", bssid) + && _parser.recv("OK"))) { + return 0; + } + + if (!(_parser.send("AT+CWLAP=\"\",\"%s\",", bssid) + && _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi) + && _parser.recv("OK"))) { + return 0; + } + + return rssi; +} + +bool ESP8266::isConnected(void) +{ + return getIPAddress() != 0; +} + +int ESP8266::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0; + nsapi_wifi_ap_t ap; + + if (!_parser.send("AT+CWLAP")) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + while (recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + cnt++; + if (limit != 0 && cnt >= limit) { + break; + } + } + + return cnt; +} + +bool ESP8266::open(const char *type, int id, const char* addr, int port) +{ + //IDs only 0-4 + if(id > 4) { + return false; + } + + return _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port) + && _parser.recv("OK"); +} + +bool ESP8266::send(int id, const void *data, uint32_t amount) +{ + //May take a second try if device is busy + for (unsigned i = 0; i < 2; i++) { + if (_parser.send("AT+CIPSEND=%d,%d", id, amount) + && _parser.recv(">") + && _parser.write((char*)data, (int)amount) >= 0) { + return true; + } + } + + return false; +} + +void ESP8266::_packet_handler() +{ + int id; + uint32_t amount; + + // parse out the packet + if (!_parser.recv(",%d,%d:", &id, &amount)) { + return; + } + + struct packet *packet = (struct packet*)malloc( + sizeof(struct packet) + amount); + if (!packet) { + return; + } + + packet->id = id; + packet->len = amount; + packet->next = 0; + + if (!(_parser.read((char*)(packet + 1), amount))) { + free(packet); + return; + } + + // append to packet list + *_packets_end = packet; + _packets_end = &packet->next; +} + +int32_t ESP8266::recv(int id, void *data, uint32_t amount) +{ + while (true) { + // check if any packets are ready for us + for (struct packet **p = &_packets; *p; p = &(*p)->next) { + if ((*p)->id == id) { + struct packet *q = *p; + + if (q->len <= amount) { // Return and remove full packet + memcpy(data, q+1, q->len); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + + uint32_t len = q->len; + free(q); + return len; + } else { // return only partial packet + memcpy(data, q+1, amount); + + q->len -= amount; + memmove(q+1, (uint8_t*)(q+1) + amount, q->len); + + return amount; + } + } + } + + // Wait for inbound packet + if (!_parser.recv("OK")) { + return -1; + } + } +} + +bool ESP8266::close(int id) +{ + //May take a second try if device is busy + for (unsigned i = 0; i < 2; i++) { + if (_parser.send("AT+CIPCLOSE=%d", id) + && _parser.recv("OK")) { + return true; + } + } + + return false; +} + +void ESP8266::setTimeout(uint32_t timeout_ms) +{ + _parser.setTimeout(timeout_ms); +} + +bool ESP8266::readable() +{ + return _serial.readable(); +} + +bool ESP8266::writeable() +{ + return _serial.writeable(); +} + +void ESP8266::attach(Callback<void()> func) +{ + _serial.attach(func); +} + +bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap) +{ + int sec; + bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%d", &sec, ap->ssid, + &ap->rssi, &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], + &ap->bssid[5], &ap->channel); + + ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN; + + return ret; +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266/ESP8266.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ESP8266.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,213 @@ +/* ESP8266Interface Example + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ESP8266_H +#define ESP8266_H + +#include "ATParser.h" + +/** ESP8266Interface class. + This is an interface to a ESP8266 radio. + */ +class ESP8266 +{ +public: + ESP8266(PinName tx, PinName rx, bool debug=false); + + /** + * Startup the ESP8266 + * + * @param mode mode of WIFI 1-client, 2-host, 3-both + * @return true only if ESP8266 was setup correctly + */ + bool startup(int mode); + + /** + * Reset ESP8266 + * + * @return true only if ESP8266 resets successfully + */ + bool reset(void); + + /** + * Enable/Disable DHCP + * + * @param enabled DHCP enabled when true + * @param mode mode of DHCP 0-softAP, 1-station, 2-both + * @return true only if ESP8266 enables/disables DHCP successfully + */ + bool dhcp(bool enabled, int mode); + + /** + * Connect ESP8266 to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @return true only if ESP8266 is connected successfully + */ + bool connect(const char *ap, const char *passPhrase); + + /** + * Disconnect ESP8266 from AP + * + * @return true only if ESP8266 is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of ESP8266 + * + * @return null-teriminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + + /** + * Get the MAC address of ESP8266 + * + * @return null-terminated MAC address or null if no MAC address is assigned + */ + const char *getMACAddress(void); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + const char *getGateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + const char *getNetmask(); + + /* Return RSSI for active connection + * + * @return Measured RSSI + */ + int8_t getRSSI(); + + /** + * Check if ESP8266 is conenected + * + * @return true only if the chip has an IP address + */ + bool isConnected(void); + + /** Scan for available networks + * + * @param ap Pointer to allocated array to store discovered AP + * @param limit Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + int scan(WiFiAccessPoint *res, unsigned limit); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "UDP" or "TCP" + * @param id id to give the new socket, valid 0-4 + * @param port port to open connection with + * @param addr the IP address of the destination + * @return true only if socket opened successfully + */ + bool open(const char *type, int id, const char* addr, int port); + + /** + * Sends data to an open socket + * + * @param id id of socket to send to + * @param data data to be sent + * @param amount amount of data to be sent - max 1024 + * @return true only if data sent successfully + */ + bool send(int id, const void *data, uint32_t amount); + + /** + * Receives data from an open socket + * + * @param id id to receive from + * @param data placeholder for returned information + * @param amount number of bytes to be received + * @return the number of bytes received + */ + int32_t recv(int id, void *data, uint32_t amount); + + /** + * Closes a socket + * + * @param id id of socket to close, valid only 0-4 + * @return true only if socket is closed successfully + */ + bool close(int id); + + /** + * Allows timeout to be changed between commands + * + * @param timeout_ms timeout of the connection + */ + void setTimeout(uint32_t timeout_ms); + + /** + * Checks if data is available + */ + bool readable(); + + /** + * Checks if data can be written + */ + bool writeable(); + + /** + * Attach a function to call whenever network state has changed + * + * @param func A pointer to a void function, or 0 to set as none + */ + void attach(Callback<void()> func); + + /** + * Attach a function to call whenever network state has changed + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + */ + template <typename T, typename M> + void attach(T *obj, M method) { + attach(Callback<void()>(obj, method)); + } + +private: + BufferedSerial _serial; + ATParser _parser; + + struct packet { + struct packet *next; + int id; + uint32_t len; + // data follows + } *_packets, **_packets_end; + void _packet_handler(); + bool recv_ap(nsapi_wifi_ap_t *ap); + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266Interface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266Interface.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,282 @@ +/* ESP8266 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include "ESP8266Interface.h" + +// Various timeouts for different ESP8266 operations +#define ESP8266_CONNECT_TIMEOUT 15000//15000 +#define ESP8266_SEND_TIMEOUT 500 +#define ESP8266_RECV_TIMEOUT 0 +#define ESP8266_MISC_TIMEOUT 500 + +// ESP8266Interface implementation +ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug) + : _esp(tx, rx, debug) +{ + memset(_ids, 0, sizeof(_ids)); + memset(_cbs, 0, sizeof(_cbs)); + + _esp.attach(this, &ESP8266Interface::event); +} + +int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + set_credentials(ssid, pass, security); + return connect(); +} + +int ESP8266Interface::connect() +{ + _esp.setTimeout(ESP8266_CONNECT_TIMEOUT); + + if (!_esp.startup(3)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if (!_esp.dhcp(true, 1)) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + if (!_esp.connect(ap_ssid, ap_pass)) { + return NSAPI_ERROR_NO_CONNECTION; + } + + if (!_esp.getIPAddress()) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + return NSAPI_ERROR_OK; +} + +int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + memset(ap_ssid, 0, sizeof(ap_ssid)); + strncpy(ap_ssid, ssid, sizeof(ap_ssid)); + + memset(ap_pass, 0, sizeof(ap_pass)); + strncpy(ap_pass, pass, sizeof(ap_pass)); + + ap_sec = security; + + return 0; +} + +int ESP8266Interface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + + +int ESP8266Interface::disconnect() +{ + _esp.setTimeout(ESP8266_MISC_TIMEOUT); + + if (!_esp.disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return NSAPI_ERROR_OK; +} + +const char *ESP8266Interface::get_ip_address() +{ + return _esp.getIPAddress(); +} + +const char *ESP8266Interface::get_mac_address() +{ + return _esp.getMACAddress(); +} + +const char *ESP8266Interface::get_gateway() +{ + return _esp.getGateway(); +} + +const char *ESP8266Interface::get_netmask() +{ + return _esp.getNetmask(); +} + +int8_t ESP8266Interface::get_rssi() +{ + return _esp.getRSSI(); +} + +int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count) +{ + return _esp.scan(res, count); +} + +struct esp8266_socket { + int id; + nsapi_protocol_t proto; + bool connected; + SocketAddress addr; +}; + +int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto) +{ + // Look for an unused socket + int id = -1; + + for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) { + if (!_ids[i]) { + id = i; + _ids[i] = true; + break; + } + } + + if (id == -1) { + return NSAPI_ERROR_NO_SOCKET; + } + + struct esp8266_socket *socket = new struct esp8266_socket; + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + socket->id = id; + socket->proto = proto; + socket->connected = false; + *handle = socket; + return 0; +} + +int ESP8266Interface::socket_close(void *handle) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + int err = 0; + _esp.setTimeout(ESP8266_MISC_TIMEOUT); + + if (!_esp.close(socket->id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + + _ids[socket->id] = false; + delete socket; + return err; +} + +int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP8266Interface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + _esp.setTimeout(ESP8266_MISC_TIMEOUT); + + const char *proto = (socket->proto == NSAPI_UDP) ? "UDP" : "TCP"; + if (!_esp.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + socket->connected = true; + return 0; +} + +int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + _esp.setTimeout(ESP8266_SEND_TIMEOUT); + + if (!_esp.send(socket->id, data, size)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return size; +} + +int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + _esp.setTimeout(ESP8266_RECV_TIMEOUT); + + int32_t recv = _esp.recv(socket->id, data, size); + if (recv < 0) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + return recv; +} + +int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + if (socket->connected && socket->addr != addr) { + _esp.setTimeout(ESP8266_MISC_TIMEOUT); + if (!_esp.close(socket->id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->connected = false; + } + + if (!socket->connected) { + int err = socket_connect(socket, addr); + if (err < 0) { + return err; + } + socket->addr = addr; + } + + return socket_send(socket, data, size); +} + +int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + int ret = socket_recv(socket, data, size); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + _cbs[socket->id].callback = callback; + _cbs[socket->id].data = data; +} + +void ESP8266Interface::event() { + for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) { + if (_cbs[i].callback) { + _cbs[i].callback(_cbs[i].data); + } + } +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/esp8266-driver/ESP8266Interface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266Interface.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,275 @@ +/* ESP8266 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ESP8266_INTERFACE_H +#define ESP8266_INTERFACE_H + +#include "mbed.h" +#include "ESP8266.h" + + +#define ESP8266_SOCKET_COUNT 5 + +/** ESP8266Interface class + * Implementation of the NetworkStack for the ESP8266 + */ +class ESP8266Interface : public NetworkStack, public WiFiInterface +{ +public: + /** ESP8266Interface lifetime + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + */ + ESP8266Interface(PinName tx, PinName rx, bool debug = false); + + /** Start the interface + * + * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. + * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return 0 on success, negative error code on failure + */ + virtual int connect(); + + /** Start the interface + * + * Attempts to connect to a WiFi network. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE) + * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED + * @return 0 on success, or error code on failure + */ + virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, + uint8_t channel = 0); + + /** Set the WiFi network credentials + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * (defaults to NSAPI_SECURITY_NONE) + * @return 0 on success, or error code on failure + */ + virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); + + /** Set the WiFi network channel - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0) + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual int set_channel(uint8_t channel); + + /** Stop the interface + * @return 0 on success, negative on failure + */ + virtual int disconnect(); + + /** Get the internally stored IP address + * @return IP address of the interface or null if not yet connected + */ + virtual const char *get_ip_address(); + + /** Get the internally stored MAC address + * @return MAC address of the interface + */ + virtual const char *get_mac_address(); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + virtual const char *get_gateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + virtual const char *get_netmask(); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + virtual int8_t get_rssi(); + + /** Scan for available networks + * + * This function will block. + * + * @param ap Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0) + * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + virtual int scan(WiFiAccessPoint *res, unsigned count); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::gethostbyname; + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::add_dns_server; + +protected: + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual int socket_close(void *handle); + + /** Bind a server socket to a specific port + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ + virtual int socket_listen(void *handle, int backlog); + + /** Connects this TCP socket to the server + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ + virtual int socket_connect(void *handle, const SocketAddress &address); + + /** Accept a new connection. + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_accept(void *handle, void **socket, SocketAddress *address); + + /** Send data to the remote host + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_send(void *handle, const void *data, unsigned size); + + /** Receive data from the remote host + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet to a remote endpoint + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive a packet from a remote endpoint + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return The number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + ESP8266 _esp; + bool _ids[ESP8266_SOCKET_COUNT]; + + char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + nsapi_security_t ap_sec; + uint8_t ap_ch; + char ap_pass[64]; /* The longest allowed passphrase */ + + void event(); + + struct { + void (*callback)(void *); + void *data; + } _cbs[ESP8266_SOCKET_COUNT]; +}; + +#endif
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mbed_lib.json Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,9 @@ +{ + "name": "easy-connect", + "target_overrides": { + "*": { + "target.features_add": ["COMMON_PAL"] + } + } +} +
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.gitignore Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,6 @@ +*~ +*.swo +*.swp +build +yotta_modules +yotta_targets
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/LICENSE Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/README.md Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,6 @@ +# Example RF driver for Freescale 802.15.4 transceivers # + +Support for: + * MCR20A + +This driver is used with 6LoWPAN stack. \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/apache-2.0.txt Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/mcr20a-rf-driver/NanostackRfPhyMcr20a.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/mcr20a-rf-driver/NanostackRfPhyMcr20a.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NANOSTACK_PHY_MCR20A_H_ +#define NANOSTACK_PHY_MCR20A_H_ + +#include "mbed.h" +#include "NanostackRfPhy.h" + +// Arduino pin defaults for convenience +#if !defined(MCR20A_SPI_MOSI) +#define MCR20A_SPI_MOSI D11 +#endif +#if !defined(MCR20A_SPI_MISO) +#define MCR20A_SPI_MISO D12 +#endif +#if !defined(MCR20A_SPI_SCLK) +#define MCR20A_SPI_SCLK D13 +#endif +#if !defined(MCR20A_SPI_CS) +#define MCR20A_SPI_CS D10 +#endif +#if !defined(MCR20A_SPI_RST) +#define MCR20A_SPI_RST D5 +#endif +#if !defined(MCR20A_SPI_IRQ) +#define MCR20A_SPI_IRQ D2 +#endif + +class NanostackRfPhyMcr20a : public NanostackRfPhy { +public: + NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, + PinName spi_irq); + ~NanostackRfPhyMcr20a(); + int8_t rf_register(); + void rf_unregister(); + void get_mac_address(uint8_t *mac); + void set_mac_address(uint8_t *mac); + +private: + SPI _spi; + DigitalOut _rf_cs; + DigitalOut _rf_rst; + InterruptIn _rf_irq; + DigitalIn _rf_irq_pin; + + void _pins_set(); + void _pins_clear(); +}; + +#endif /* NANOSTACK_PHY_MCR20A_H_ */
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/module.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/module.json Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,18 @@ +{ + "name": "mcr20a-rf-driver", + "version": "0.0.1", + "description": "RF driver for Freescale MCR20A 2.4GHz 802.15.4 wireless transceiver", + "keywords": [ + "rf", + "driver", + "802.15.4" + ], + "author": "Andrei Kovacs <Andrei.Kovacs@freescale.com>", + "license": "BSD 3-clause", + "dependencies": { + "nanostack-libservice": "^3.0.0", + "sal-stack-nanostack": "^5.0.0", + "mbed-drivers": "^1.0.0" + }, + "targetDependencies": {} +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/source/MCR20Drv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Drv.c Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,675 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Drv.c +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/***************************************************************************** +* INCLUDED HEADERS * +*---------------------------------------------------------------------------* +* Add to this section all the headers that this module needs to include. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +#include "platform/arm_hal_interrupt.h" +#include "MCR20Drv.h" +#include "MCR20Reg.h" +#include "XcvrSpi.h" + + +/***************************************************************************** +* PRIVATE VARIABLES * +*---------------------------------------------------------------------------* +* Add to this section all the variables and constants that have local * +* (file) scope. * +* Each of this declarations shall be preceded by the 'static' keyword. * +* These variables / constants cannot be accessed outside this module. * +*---------------------------------------------------------------------------* +*****************************************************************************/ +uint32_t mPhyIrqDisableCnt = 1; + +/***************************************************************************** +* PUBLIC VARIABLES * +*---------------------------------------------------------------------------* +* Add to this section all the variables and constants that have global * +* (project) scope. * +* These variables / constants can be accessed outside this module. * +* These variables / constants shall be preceded by the 'extern' keyword in * +* the interface header. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +/***************************************************************************** +* PRIVATE FUNCTIONS PROTOTYPES * +*---------------------------------------------------------------------------* +* Add to this section all the functions prototypes that have local (file) * +* scope. * +* These functions cannot be accessed outside this module. * +* These declarations shall be preceded by the 'static' keyword. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +/***************************************************************************** +* PRIVATE FUNCTIONS * +*---------------------------------------------------------------------------* +* Add to this section all the functions that have local (file) scope. * +* These functions cannot be accessed outside this module. * +* These definitions shall be preceded by the 'static' keyword. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + + +/***************************************************************************** +* PUBLIC FUNCTIONS * +*---------------------------------------------------------------------------* +* Add to this section all the functions that have global (project) scope. * +* These functions can be accessed outside this module. * +* These functions shall have their declarations (prototypes) within the * +* interface header file and shall be preceded by the 'extern' keyword. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_Init +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_Init +( +void +) +{ + xcvr_spi_init(gXcvrSpiInstance_c); + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrDeassertCS_d(); + MCR20Drv_RST_B_Deassert(); + RF_IRQ_Init(); + RF_IRQ_Disable(); + mPhyIrqDisableCnt = 1; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIWrite +( +uint8_t address, +uint8_t value +) +{ + uint16_t txData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = (address & TransceiverSPI_DirectRegisterAddressMask); + txData |= value << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t *)&txData, 0, sizeof(txData)); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIMultiByteWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIMultiByteWrite +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = (startAddress & TransceiverSPI_DirectRegisterAddressMask); + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, byteArray, 0, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_PB_SPIByteWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIByteWrite +( +uint8_t address, +uint8_t value +) +{ + uint32_t txData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_WriteSelect | + TransceiverSPI_PacketBuffAccessSelect | + TransceiverSPI_PacketBuffByteModeSelect; + txData |= (address) << 8; + txData |= (value) << 16; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, 3); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_PB_SPIBurstWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIBurstWrite +( +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_WriteSelect | + TransceiverSPI_PacketBuffAccessSelect | + TransceiverSPI_PacketBuffBurstModeSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, 1); + xcvr_spi_transfer(gXcvrSpiInstance_c, byteArray, 0, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ + +uint8_t MCR20Drv_DirectAccessSPIRead +( +uint8_t address +) +{ + uint8_t txData; + uint8_t rxData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = (address & TransceiverSPI_DirectRegisterAddressMask) | + TransceiverSPI_ReadSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, &rxData, sizeof(rxData)); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return rxData; + +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIMultyByteRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_DirectAccessSPIMultiByteRead +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + uint8_t phyIRQSTS1; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return 0; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = (startAddress & TransceiverSPI_DirectRegisterAddressMask) | + TransceiverSPI_ReadSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, &phyIRQSTS1, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return phyIRQSTS1; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_PB_SPIBurstRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_PB_SPIBurstRead +( +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + uint8_t phyIRQSTS1; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return 0; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_ReadSelect | + TransceiverSPI_PacketBuffAccessSelect | + TransceiverSPI_PacketBuffBurstModeSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, &phyIRQSTS1, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return phyIRQSTS1; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIWrite +( +uint8_t address, +uint8_t value +) +{ + uint32_t txData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_IARIndexReg; + txData |= (address) << 8; + txData |= (value) << 16; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, 3); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIMultiByteWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteWrite +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint16_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_IARIndexReg; + txData |= (startAddress) << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)byteArray, 0, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_IndirectAccessSPIRead +( +uint8_t address +) +{ + uint16_t txData; + uint8_t rxData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_IARIndexReg | TransceiverSPI_ReadSelect; + txData |= (address) << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, &rxData, sizeof(rxData)); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return rxData; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIMultiByteRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteRead +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint16_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = (TransceiverSPI_IARIndexReg | TransceiverSPI_ReadSelect); + txData |= (startAddress) << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IsIrqPending +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint32_t MCR20Drv_IsIrqPending +( +void +) +{ + return RF_isIRQ_Pending(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IRQ_Disable +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Disable +( +void +) +{ + platform_enter_critical(); + + if( mPhyIrqDisableCnt == 0 ) + { + RF_IRQ_Disable(); + } + + mPhyIrqDisableCnt++; + + platform_exit_critical(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IRQ_Enable +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Enable +( +void +) +{ + platform_enter_critical(); + + if( mPhyIrqDisableCnt ) + { + mPhyIrqDisableCnt--; + + if( mPhyIrqDisableCnt == 0 ) + { + RF_IRQ_Enable(); + } + } + + platform_exit_critical(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_RST_Assert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Assert +( +void +) +{ + RF_RST_Set(0); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_RST_Deassert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Deassert +( +void +) +{ + RF_RST_Set(1); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_SoftRST_Assert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Assert +( +void +) +{ + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x80)); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_SoftRST_Deassert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Deassert +( +void +) +{ + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x00)); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_Soft_RESET +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_Soft_RESET +( +void +) +{ + //assert SOG_RST + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x80)); + + //deassert SOG_RST + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x00)); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_RESET +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_RESET +( +void +) +{ + volatile uint32_t delay = 1000; + //assert RST_B + MCR20Drv_RST_B_Assert(); + + while(delay--); + + //deassert RST_B + MCR20Drv_RST_B_Deassert(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_Set_CLK_OUT_Freq +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_Set_CLK_OUT_Freq +( +uint8_t freqDiv +) +{ + uint8_t clkOutCtrlReg = (freqDiv & cCLK_OUT_DIV_Mask) | cCLK_OUT_EN | cCLK_OUT_EXTEND; + + if(freqDiv == gCLK_OUT_FREQ_DISABLE) + { + clkOutCtrlReg = (cCLK_OUT_EXTEND | gCLK_OUT_FREQ_4_MHz); //reset value with clock out disabled + } + + MCR20Drv_DirectAccessSPIWrite((uint8_t) CLK_OUT_CTRL, clkOutCtrlReg); +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/source/MCR20Drv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Drv.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,372 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Drv.h +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __MCR20_DRV_H__ +#define __MCR20_DRV_H__ + + +/***************************************************************************** + * INCLUDED HEADERS * + *---------------------------------------------------------------------------* + * Add to this section all the headers that this module needs to include. * + * Note that it is not a good practice to include header files into header * + * files, so use this section only if there is no other better solution. * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/***************************************************************************** + * PRIVATE MACROS * + *---------------------------------------------------------------------------* + * Add to this section all the access macros, registers mappings, bit access * + * macros, masks, flags etc ... + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/* Disable XCVR clock output by default, to reduce power consumption */ +#ifndef gMCR20_ClkOutFreq_d +#define gMCR20_ClkOutFreq_d gCLK_OUT_FREQ_DISABLE +#endif + +/***************************************************************************** + * PUBLIC FUNCTIONS * + *---------------------------------------------------------------------------* + * Add to this section all the global functions prototype preceded (as a * + * good practice) by the keyword 'extern' * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Init + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +extern void MCR20Drv_Init +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_SPI_DMA_Init + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_SPI_DMA_Init +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Start_PB_DMA_SPI_Write + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Start_PB_DMA_SPI_Write +( + uint8_t * srcAddress, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Start_PB_DMA_SPI_Read + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Start_PB_DMA_SPI_Read +( + uint8_t * dstAddress, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIWrite +( + uint8_t address, + uint8_t value +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIMultiByteWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIMultiByteWrite +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_PB_SPIBurstWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIBurstWrite +( + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_DirectAccessSPIRead +( + uint8_t address +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIMultyByteRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ + +uint8_t MCR20Drv_DirectAccessSPIMultiByteRead +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_PB_SPIByteWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIByteWrite +( + uint8_t address, + uint8_t value +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_PB_SPIBurstRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_PB_SPIBurstRead +( + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIWrite +( + uint8_t address, + uint8_t value +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIMultiByteWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteWrite +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_IndirectAccessSPIRead +( + uint8_t address +); +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIMultiByteRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteRead +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IsIrqPending + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint32_t MCR20Drv_IsIrqPending +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IRQ_Disable + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Disable +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IRQ_Enable + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Enable +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RST_PortConfig + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_PortConfig +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RST_Assert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Assert +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RST_Deassert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Deassert +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_SoftRST_Assert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Assert +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_SoftRST_Deassert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Deassert +( + void +); + + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RESET + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RESET +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Soft_RESET + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Soft_RESET +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Set_CLK_OUT_Freq + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Set_CLK_OUT_Freq +( + uint8_t freqDiv +); + +#define ProtectFromMCR20Interrupt() MCR20Drv_IRQ_Disable() +#define UnprotectFromMCR20Interrupt() MCR20Drv_IRQ_Enable() + +#endif /* __MCR20_DRV_H__ */
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/source/MCR20Overwrites.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Overwrites.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,309 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Overwrites.h +* Description: Overwrites header file for MCR20 Register values +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OVERWRITES_H_ +#define OVERWRITES_H_ + +typedef struct overwrites_tag { + char address; + char data; +}overwrites_t; + + +/*****************************************************************************************************************/ +// This file is created exclusively for use with the transceiver 2.0 silicon +// and is provided for the world to use. It contains a list of all +// known overwrite values. Overwrite values are non-default register +// values that configure the transceiver device to a more optimally performing +// posture. It is expected that low level software (i.e. PHY) will +// consume this file as a #include, and transfer the contents to the +// the indicated addresses in the transceiver's memory space. This file has +// at least one required entry, that being its own version current version +// number, to be stored at transceiver's location 0x3B the +// OVERWRITES_VERSION_NUMBER register. The RAM register is provided in +// the transceiver address space to assist in future debug efforts. The +// analyst may read this location (once device has been booted with +// mysterious software) and have a good indication of what register +// overwrites were performed (with all versions of the overwrites.h file +// being archived forever at the Compass location shown above. +// +// The transceiver has an indirect register (IAR) space. Write access to this space +// requires 3 or more writes: +// 1st) the first write is an index value to the indirect (write Bit7=0, register access Bit 6=0) + 0x3E +// 2nd) IAR Register #0x00 - 0xFF. +// 3rd) The data to write +// nth) Burst mode additional data if required. +// +// Write access to direct space requires only a single address, data pair. + +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x0C}, //version 0C: new value for ACKDELAY targeting 198us (23 May, 2013, Larry Roshak) +{0x23, 0x17} //PA_PWR new default Power Step is "23" +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03}, //CHF_PMAGAIN +{0x22, 0x50}, //CCA1_THRESH +{0x4D, 0x13}, //CORR_NVAL moved from 0x14 to 0x13 for 0.5 dB improved Rx Sensitivity +{0x39, 0x3D} //ACKDELAY new value targeting a delay of 198us (23 May, 2013, Larry Roshak) +}; + + +/* begin of deprecated versions + +==VERSION 1== +(version 1 is empty) + +==VERSION 2== +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02} //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +}; + +==VERSION 3== +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +}; + +==VERSION 4== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x04} //version 04 is the current version: update PA_COILTUNING default +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING: override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +}; + +==VERSION 5== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x05} //version 05: updates Channel Filter Register set (21 Dec 2012, on behalf of S. Soca) +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +}; + +==VERSION 6== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x06} //version 06: disable PA calibration +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28} //PA_CAL_DIS=1 Disabled PA calibration +}; + +==VERSION 7== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x07} //version 07: updated registers for ED/RSSI +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x73}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x60}, //RSSI_OFFSET +{0x69, 0x65} //RSSI_SLOPE +}; + + +==VERSION 8== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x08} //version 08: updated registers for ED/RSSI +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x73}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x69, 0x65} //RSSI_SLOPE +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +}; + + +==VERSION 9== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x09} //version 09: updated registers for ED/RSSI and PowerStep +{0x23, 0x17} //PA_PWR new default value +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +}; + +==VERSION A== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x0A} //version 0A: updated registers for CCA +{0x23, 0x17} //PA_PWR new default Power Step is "23" +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +{0x22, 0x50} //CCA1_THRESH +}; + +end of deprecated versions */ + + +#endif //OVERWRITES_H_ +
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/source/MCR20Reg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Reg.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,730 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20reg.h +* MCR20 Registers +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __MCR20_REG_H__ +#define __MCR20_REG_H__ +/***************************************************************************** + * INCLUDED HEADERS * + *---------------------------------------------------------------------------* + * Add to this section all the headers that this module needs to include. * + * Note that it is not a good practice to include header files into header * + * files, so use this section only if there is no other better solution. * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/****************************************************************************/ +/* Transceiver SPI Registers */ +/****************************************************************************/ + +#define TransceiverSPI_IARIndexReg (0x3E) + +#define TransceiverSPI_ReadSelect (1<<7) +#define TransceiverSPI_WriteSelect (0<<7) +#define TransceiverSPI_RegisterAccessSelect (0<<6) +#define TransceiverSPI_PacketBuffAccessSelect (1<<6) +#define TransceiverSPI_PacketBuffBurstModeSelect (0<<5) +#define TransceiverSPI_PacketBuffByteModeSelect (1<<5) + +#define TransceiverSPI_DirectRegisterAddressMask (0x3F) + +#define IRQSTS1 0x00 +#define IRQSTS2 0x01 +#define IRQSTS3 0x02 +#define PHY_CTRL1 0x03 +#define PHY_CTRL2 0x04 +#define PHY_CTRL3 0x05 +#define RX_FRM_LEN 0x06 +#define PHY_CTRL4 0x07 +#define SRC_CTRL 0x08 +#define SRC_ADDRS_SUM_LSB 0x09 +#define SRC_ADDRS_SUM_MSB 0x0A +#define CCA1_ED_FNL 0x0B +#define EVENT_TMR_LSB 0x0C +#define EVENT_TMR_MSB 0x0D +#define EVENT_TMR_USB 0x0E +#define TIMESTAMP_LSB 0x0F +#define TIMESTAMP_MSB 0x10 +#define TIMESTAMP_USB 0x11 +#define T3CMP_LSB 0x12 +#define T3CMP_MSB 0x13 +#define T3CMP_USB 0x14 +#define T2PRIMECMP_LSB 0x15 +#define T2PRIMECMP_MSB 0x16 +#define T1CMP_LSB 0x17 +#define T1CMP_MSB 0x18 +#define T1CMP_USB 0x19 +#define T2CMP_LSB 0x1A +#define T2CMP_MSB 0x1B +#define T2CMP_USB 0x1C +#define T4CMP_LSB 0x1D +#define T4CMP_MSB 0x1E +#define T4CMP_USB 0x1F +#define PLL_INT0 0x20 +#define PLL_FRAC0_LSB 0x21 +#define PLL_FRAC0_MSB 0x22 +#define PA_PWR 0x23 +#define SEQ_STATE 0x24 +#define LQI_VALUE 0x25 +#define RSSI_CCA_CONT 0x26 +//-------------- 0x27 +#define ASM_CTRL1 0x28 +#define ASM_CTRL2 0x29 +#define ASM_DATA_0 0x2A +#define ASM_DATA_1 0x2B +#define ASM_DATA_2 0x2C +#define ASM_DATA_3 0x2D +#define ASM_DATA_4 0x2E +#define ASM_DATA_5 0x2F +#define ASM_DATA_6 0x30 +#define ASM_DATA_7 0x31 +#define ASM_DATA_8 0x32 +#define ASM_DATA_9 0x33 +#define ASM_DATA_A 0x34 +#define ASM_DATA_B 0x35 +#define ASM_DATA_C 0x36 +#define ASM_DATA_D 0x37 +#define ASM_DATA_E 0x38 +#define ASM_DATA_F 0x39 +//------------------- 0x3A +#define OVERWRITE_VER 0x3B +#define CLK_OUT_CTRL 0x3C +#define PWR_MODES 0x3D +#define IAR_INDEX 0x3E +#define IAR_DATA 0x3F + + +#define PART_ID 0x00 +#define XTAL_TRIM 0x01 +#define PMC_LP_TRIM 0x02 +#define MACPANID0_LSB 0x03 +#define MACPANID0_MSB 0x04 +#define MACSHORTADDRS0_LSB 0x05 +#define MACSHORTADDRS0_MSB 0x06 +#define MACLONGADDRS0_0 0x07 +#define MACLONGADDRS0_8 0x08 +#define MACLONGADDRS0_16 0x09 +#define MACLONGADDRS0_24 0x0A +#define MACLONGADDRS0_32 0x0B +#define MACLONGADDRS0_40 0x0C +#define MACLONGADDRS0_48 0x0D +#define MACLONGADDRS0_56 0x0E +#define RX_FRAME_FILTER 0x0F +#define PLL_INT1 0x10 +#define PLL_FRAC1_LSB 0x11 +#define PLL_FRAC1_MSB 0x12 +#define MACPANID1_LSB 0x13 +#define MACPANID1_MSB 0x14 +#define MACSHORTADDRS1_LSB 0x15 +#define MACSHORTADDRS1_MSB 0x16 +#define MACLONGADDRS1_0 0x17 +#define MACLONGADDRS1_8 0x18 +#define MACLONGADDRS1_16 0x19 +#define MACLONGADDRS1_24 0x1A +#define MACLONGADDRS1_32 0x1B +#define MACLONGADDRS1_40 0x1C +#define MACLONGADDRS1_48 0x1D +#define MACLONGADDRS1_56 0x1E +#define DUAL_PAN_CTRL 0x1F +#define DUAL_PAN_DWELL 0x20 +#define DUAL_PAN_STS 0x21 +#define CCA1_THRESH 0x22 +#define CCA1_ED_OFFSET_COMP 0x23 +#define LQI_OFFSET_COMP 0x24 +#define CCA_CTRL 0x25 +#define CCA2_CORR_PEAKS 0x26 +#define CCA2_CORR_THRESH 0x27 +#define TMR_PRESCALE 0x28 +//---------------- 0x29 +#define GPIO_DATA 0x2A +#define GPIO_DIR 0x2B +#define GPIO_PUL_EN 0x2C +#define GPIO_PUL_SEL 0x2D +#define GPIO_DS 0x2E +//-------------- 0x2F +#define ANT_PAD_CTRL 0x30 +#define MISC_PAD_CTRL 0x31 +#define BSM_CTRL 0x32 +//--------------- 0x33 +#define _RNG 0x34 +#define RX_BYTE_COUNT 0x35 +#define RX_WTR_MARK 0x36 +#define SOFT_RESET 0x37 +#define TXDELAY 0x38 +#define ACKDELAY 0x39 +#define SEQ_MGR_CTRL 0x3A +#define SEQ_MGR_STS 0x3B +#define SEQ_T_STS 0x3C +#define ABORT_STS 0x3D +#define CCCA_BUSY_CNT 0x3E +#define SRC_ADDR_CHECKSUM1 0x3F +#define SRC_ADDR_CHECKSUM2 0x40 +#define SRC_TBL_VALID1 0x41 +#define SRC_TBL_VALID2 0x42 +#define FILTERFAIL_CODE1 0x43 +#define FILTERFAIL_CODE2 0x44 +#define SLOT_PRELOAD 0x45 +//---------------- 0x46 +#define CORR_VT 0x47 +#define SYNC_CTRL 0x48 +#define PN_LSB_0 0x49 +#define PN_LSB_1 0x4A +#define PN_MSB_0 0x4B +#define PN_MSB_1 0x4C +#define CORR_NVAL 0x4D +#define TX_MODE_CTRL 0x4E +#define SNF_THR 0x4F +#define FAD_THR 0x50 +#define ANT_AGC_CTRL 0x51 +#define AGC_THR1 0x52 +#define AGC_THR2 0x53 +#define AGC_HYS 0x54 +#define AFC 0x55 +//--------------- 0x56 +//--------------- 0x57 +#define PHY_STS 0x58 +#define RX_MAX_CORR 0x59 +#define RX_MAX_PREAMBLE 0x5A +#define RSSI 0x5B +//--------------- 0x5C +//--------------- 0x5D +#define PLL_DIG_CTRL 0x5E +#define VCO_CAL 0x5F +#define VCO_BEST_DIFF 0x60 +#define VCO_BIAS 0x61 +#define KMOD_CTRL 0x62 +#define KMOD_CAL 0x63 +#define PA_CAL 0x64 +#define PA_PWRCAL 0x65 +#define ATT_RSSI1 0x66 +#define ATT_RSSI2 0x67 +#define RSSI_OFFSET 0x68 +#define RSSI_SLOPE 0x69 +#define RSSI_CAL1 0x6A +#define RSSI_CAL2 0x6B +//--------------- 0x6C +//--------------- 0x6D +#define XTAL_CTRL 0x6E +#define XTAL_COMP_MIN 0x6F +#define XTAL_COMP_MAX 0x70 +#define XTAL_GM 0x71 +//--------------- 0x72 +//--------------- 0x73 +#define LNA_TUNE 0x74 +#define LNA_AGCGAIN 0x75 +//--------------- 0x76 +//--------------- 0x77 +#define CHF_PMA_GAIN 0x78 +#define CHF_IBUF 0x79 +#define CHF_QBUF 0x7A +#define CHF_IRIN 0x7B +#define CHF_QRIN 0x7C +#define CHF_IL 0x7D +#define CHF_QL 0x7E +#define CHF_CC1 0x7F +#define CHF_CCL 0x80 +#define CHF_CC2 0x81 +#define CHF_IROUT 0x82 +#define CHF_QROUT 0x83 +//--------------- 0x84 +//--------------- 0x85 +#define RSSI_CTRL 0x86 +//--------------- 0x87 +//--------------- 0x88 +#define PA_BIAS 0x89 +#define PA_TUNING 0x8A +//--------------- 0x8B +//--------------- 0x8C +#define PMC_HP_TRIM 0x8D +#define VREGA_TRIM 0x8E +//--------------- 0x8F +//--------------- 0x90 +#define VCO_CTRL1 0x91 +#define VCO_CTRL2 0x92 +//--------------- 0x93 +//--------------- 0x94 +#define ANA_SPARE_OUT1 0x95 +#define ANA_SPARE_OUT2 0x96 +#define ANA_SPARE_IN 0x97 +#define MISCELLANEOUS 0x98 +//--------------- 0x99 +#define SEQ_MGR_OVRD0 0x9A +#define SEQ_MGR_OVRD1 0x9B +#define SEQ_MGR_OVRD2 0x9C +#define SEQ_MGR_OVRD3 0x9D +#define SEQ_MGR_OVRD4 0x9E +#define SEQ_MGR_OVRD5 0x9F +#define SEQ_MGR_OVRD6 0xA0 +#define SEQ_MGR_OVRD7 0xA1 +//--------------- 0xA2 +#define TESTMODE_CTRL 0xA3 +#define DTM_CTRL1 0xA4 +#define DTM_CTRL2 0xA5 +#define ATM_CTRL1 0xA6 +#define ATM_CTRL2 0xA7 +#define ATM_CTRL3 0xA8 +//--------------- 0xA9 +#define LIM_FE_TEST_CTRL 0xAA +#define CHF_TEST_CTRL 0xAB +#define VCO_TEST_CTRL 0xAC +#define PLL_TEST_CTRL 0xAD +#define PA_TEST_CTRL 0xAE +#define PMC_TEST_CTRL 0xAF +#define SCAN_DTM_PROTECT_1 0xFE +#define SCAN_DTM_PROTECT_0 0xFF + +// IRQSTS1 bits +#define cIRQSTS1_RX_FRM_PEND (1<<7) +#define cIRQSTS1_PLL_UNLOCK_IRQ (1<<6) +#define cIRQSTS1_FILTERFAIL_IRQ (1<<5) +#define cIRQSTS1_RXWTRMRKIRQ (1<<4) +#define cIRQSTS1_CCAIRQ (1<<3) +#define cIRQSTS1_RXIRQ (1<<2) +#define cIRQSTS1_TXIRQ (1<<1) +#define cIRQSTS1_SEQIRQ (1<<0) + +typedef union regIRQSTS1_tag{ + uint8_t byte; + struct{ + uint8_t SEQIRQ:1; + uint8_t TXIRQ:1; + uint8_t RXIRQ:1; + uint8_t CCAIRQ:1; + uint8_t RXWTRMRKIRQ:1; + uint8_t FILTERFAIL_IRQ:1; + uint8_t PLL_UNLOCK_IRQ:1; + uint8_t RX_FRM_PEND:1; + }bit; +} regIRQSTS1_t; + +// IRQSTS2 bits +#define cIRQSTS2_CRCVALID (1<<7) +#define cIRQSTS2_CCA (1<<6) +#define cIRQSTS2_SRCADDR (1<<5) +#define cIRQSTS2_PI (1<<4) +#define cIRQSTS2_TMRSTATUS (1<<3) +#define cIRQSTS2_ASM_IRQ (1<<2) +#define cIRQSTS2_PB_ERR_IRQ (1<<1) +#define cIRQSTS2_WAKE_IRQ (1<<0) + +typedef union regIRQSTS2_tag{ + uint8_t byte; + struct{ + uint8_t WAKE_IRQ:1; + uint8_t PB_ERR_IRQ:1; + uint8_t ASM_IRQ:1; + uint8_t TMRSTATUS:1; + uint8_t PI:1; + uint8_t SRCADDR:1; + uint8_t CCA:1; + uint8_t CRCVALID:1; + }bit; +} regIRQSTS2_t; + +// IRQSTS3 bits +#define cIRQSTS3_TMR4MSK (1<<7) +#define cIRQSTS3_TMR3MSK (1<<6) +#define cIRQSTS3_TMR2MSK (1<<5) +#define cIRQSTS3_TMR1MSK (1<<4) +#define cIRQSTS3_TMR4IRQ (1<<3) +#define cIRQSTS3_TMR3IRQ (1<<2) +#define cIRQSTS3_TMR2IRQ (1<<1) +#define cIRQSTS3_TMR1IRQ (1<<0) + +typedef union regIRQSTS3_tag{ + uint8_t byte; + struct{ + uint8_t TMR1IRQ:1; + uint8_t TMR2IRQ:1; + uint8_t TMR3IRQ:1; + uint8_t TMR4IRQ:1; + uint8_t TMR1MSK:1; + uint8_t TMR2MSK:1; + uint8_t TMR3MSK:1; + uint8_t TMR4MSK:1; + }bit; +} regIRQSTS3_t; + +// PHY_CTRL1 bits +#define cPHY_CTRL1_TMRTRIGEN (1<<7) +#define cPHY_CTRL1_SLOTTED (1<<6) +#define cPHY_CTRL1_CCABFRTX (1<<5) +#define cPHY_CTRL1_RXACKRQD (1<<4) +#define cPHY_CTRL1_AUTOACK (1<<3) +#define cPHY_CTRL1_XCVSEQ (7<<0) + +typedef union regPHY_CTRL1_tag{ + uint8_t byte; + struct{ + uint8_t XCVSEQ:3; + uint8_t AUTOACK:1; + uint8_t RXACKRQD:1; + uint8_t CCABFRTX:1; + uint8_t SLOTTED:1; + uint8_t TMRTRIGEN:1; + }bit; +} regPHY_CTRL1_t; + +// PHY_CTRL2 bits +#define cPHY_CTRL2_CRC_MSK (1<<7) +#define cPHY_CTRL2_PLL_UNLOCK_MSK (1<<6) +#define cPHY_CTRL2_FILTERFAIL_MSK (1<<5) +#define cPHY_CTRL2_RX_WMRK_MSK (1<<4) +#define cPHY_CTRL2_CCAMSK (1<<3) +#define cPHY_CTRL2_RXMSK (1<<2) +#define cPHY_CTRL2_TXMSK (1<<1) +#define cPHY_CTRL2_SEQMSK (1<<0) + +typedef union regPHY_CTRL2_tag{ + uint8_t byte; + struct{ + uint8_t SEQMSK:1; + uint8_t TXMSK:1; + uint8_t RXMSK:1; + uint8_t CCAMSK:1; + uint8_t RX_WMRK_MSK:1; + uint8_t FILTERFAIL_MSK:1; + uint8_t PLL_UNLOCK_MSK:1; + uint8_t CRC_MSK:1; + }bit; +} regPHY_CTRL2_t; + +// PHY_CTRL3 bits +#define cPHY_CTRL3_TMR4CMP_EN (1<<7) +#define cPHY_CTRL3_TMR3CMP_EN (1<<6) +#define cPHY_CTRL3_TMR2CMP_EN (1<<5) +#define cPHY_CTRL3_TMR1CMP_EN (1<<4) +#define cPHY_CTRL3_ASM_MSK (1<<2) +#define cPHY_CTRL3_PB_ERR_MSK (1<<1) +#define cPHY_CTRL3_WAKE_MSK (1<<0) + +typedef union regPHY_CTRL3_tag{ + uint8_t byte; + struct{ + uint8_t WAKE_MSK:1; + uint8_t PB_ERR_MSK:1; + uint8_t ASM_MSK:1; + uint8_t RESERVED:1; + uint8_t TMR1CMP_EN:1; + uint8_t TMR2CMP_EN:1; + uint8_t TMR3CMP_EN:1; + uint8_t TMR4CMP_EN:1; + }bit; +} regPHY_CTRL3_t; + +// RX_FRM_LEN bits +#define cRX_FRAME_LENGTH (0x7F) + +// PHY_CTRL4 bits +#define cPHY_CTRL4_TRCV_MSK (1<<7) +#define cPHY_CTRL4_TC3TMOUT (1<<6) +#define cPHY_CTRL4_PANCORDNTR0 (1<<5) +#define cPHY_CTRL4_CCATYPE (3<<0) +#define cPHY_CTRL4_CCATYPE_Shift_c (3) +#define cPHY_CTRL4_TMRLOAD (1<<2) +#define cPHY_CTRL4_PROMISCUOUS (1<<1) +#define cPHY_CTRL4_TC2PRIME_EN (1<<0) + +typedef union regPHY_CTRL4_tag{ + uint8_t byte; + struct{ + uint8_t TC2PRIME_EN:1; + uint8_t PROMISCUOUS:1; + uint8_t TMRLOAD:1; + uint8_t CCATYPE:2; + uint8_t PANCORDNTR0:1; + uint8_t TC3TMOUT:1; + uint8_t TRCV_MSK:1; + }bit; +} regPHY_CTRL4_t; + +// SRC_CTRL bits +#define cSRC_CTRL_INDEX (0x0F) +#define cSRC_CTRL_INDEX_Shift_c (4) +#define cSRC_CTRL_ACK_FRM_PND (1<<3) +#define cSRC_CTRL_SRCADDR_EN (1<<2) +#define cSRC_CTRL_INDEX_EN (1<<1) +#define cSRC_CTRL_INDEX_DISABLE (1<<0) + +typedef union regSRC_CTRL_tag{ + uint8_t byte; + struct{ + uint8_t INDEX_DISABLE:1; + uint8_t INDEX_EN:1; + uint8_t SRCADDR_EN:1; + uint8_t ACK_FRM_PND:1; + uint8_t INDEX:4; + }bit; +} regSRC_CTRL_t; + +// ASM_CTRL1 bits +#define cASM_CTRL1_CLEAR (1<<7) +#define cASM_CTRL1_START (1<<6) +#define cASM_CTRL1_SELFTST (1<<5) +#define cASM_CTRL1_CTR (1<<4) +#define cASM_CTRL1_CBC (1<<3) +#define cASM_CTRL1_AES (1<<2) +#define cASM_CTRL1_LOAD_MAC (1<<1) + +// ASM_CTRL2 bits +#define cASM_CTRL2_DATA_REG_TYPE_SEL (7) +#define cASM_CTRL2_DATA_REG_TYPE_SEL_Shift_c (5) +#define cASM_CTRL2_TSTPAS (1<<1) + +// CLK_OUT_CTRL bits +#define cCLK_OUT_CTRL_EXTEND (1<<7) +#define cCLK_OUT_CTRL_HIZ (1<<6) +#define cCLK_OUT_CTRL_SR (1<<5) +#define cCLK_OUT_CTRL_DS (1<<4) +#define cCLK_OUT_CTRL_EN (1<<3) +#define cCLK_OUT_CTRL_DIV (7) + +// PWR_MODES bits +#define cPWR_MODES_XTAL_READY (1<<5) +#define cPWR_MODES_XTALEN (1<<4) +#define cPWR_MODES_ASM_CLK_EN (1<<3) +#define cPWR_MODES_AUTODOZE (1<<1) +#define cPWR_MODES_PMC_MODE (1<<0) + +// RX_FRAME_FILTER bits +#define cRX_FRAME_FLT_FRM_VER (0xC0) +#define cRX_FRAME_FLT_FRM_VER_Shift_c (6) +#define cRX_FRAME_FLT_ACTIVE_PROMISCUOUS (1<<5) +#define cRX_FRAME_FLT_NS_FT (1<<4) +#define cRX_FRAME_FLT_CMD_FT (1<<3) +#define cRX_FRAME_FLT_ACK_FT (1<<2) +#define cRX_FRAME_FLT_DATA_FT (1<<1) +#define cRX_FRAME_FLT_BEACON_FT (1<<0) + +typedef union regRX_FRAME_FILTER_tag{ + uint8_t byte; + struct{ + uint8_t FRAME_FLT_BEACON_FT:1; + uint8_t FRAME_FLT_DATA_FT:1; + uint8_t FRAME_FLT_ACK_FT:1; + uint8_t FRAME_FLT_CMD_FT:1; + uint8_t FRAME_FLT_NS_FT:1; + uint8_t FRAME_FLT_ACTIVE_PROMISCUOUS:1; + uint8_t FRAME_FLT_FRM_VER:2; + }bit; +} regRX_FRAME_FILTER_t; + +// DUAL_PAN_CTRL bits +#define cDUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK (0xF0) +#define cDUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_Shift_c (4) +#define cDUAL_PAN_CTRL_CURRENT_NETWORK (1<<3) +#define cDUAL_PAN_CTRL_PANCORDNTR1 (1<<2) +#define cDUAL_PAN_CTRL_DUAL_PAN_AUTO (1<<1) +#define cDUAL_PAN_CTRL_ACTIVE_NETWORK (1<<0) + +// DUAL_PAN_STS bits +#define cDUAL_PAN_STS_RECD_ON_PAN1 (1<<7) +#define cDUAL_PAN_STS_RECD_ON_PAN0 (1<<6) +#define cDUAL_PAN_STS_DUAL_PAN_REMAIN (0x3F) + +// CCA_CTRL bits +#define cCCA_CTRL_AGC_FRZ_EN (1<<6) +#define cCCA_CTRL_CONT_RSSI_EN (1<<5) +#define cCCA_CTRL_LQI_RSSI_NOT_CORR (1<<4) +#define cCCA_CTRL_CCA3_AND_NOT_OR (1<<3) +#define cCCA_CTRL_POWER_COMP_EN_LQI (1<<2) +#define cCCA_CTRL_POWER_COMP_EN_ED (1<<1) +#define cCCA_CTRL_POWER_COMP_EN_CCA1 (1<<0) + +// GPIO_DATA bits +#define cGPIO_DATA_7 (1<<7) +#define cGPIO_DATA_6 (1<<6) +#define cGPIO_DATA_5 (1<<5) +#define cGPIO_DATA_4 (1<<4) +#define cGPIO_DATA_3 (1<<3) +#define cGPIO_DATA_2 (1<<2) +#define cGPIO_DATA_1 (1<<1) +#define cGPIO_DATA_0 (1<<0) + +// GPIO_DIR bits +#define cGPIO_DIR_7 (1<<7) +#define cGPIO_DIR_6 (1<<6) +#define cGPIO_DIR_5 (1<<5) +#define cGPIO_DIR_4 (1<<4) +#define cGPIO_DIR_3 (1<<3) +#define cGPIO_DIR_2 (1<<2) +#define cGPIO_DIR_1 (1<<1) +#define cGPIO_DIR_0 (1<<0) + +// GPIO_PUL_EN bits +#define cGPIO_PUL_EN_7 (1<<7) +#define cGPIO_PUL_EN_6 (1<<6) +#define cGPIO_PUL_EN_5 (1<<5) +#define cGPIO_PUL_EN_4 (1<<4) +#define cGPIO_PUL_EN_3 (1<<3) +#define cGPIO_PUL_EN_2 (1<<2) +#define cGPIO_PUL_EN_1 (1<<1) +#define cGPIO_PUL_EN_0 (1<<0) + +// GPIO_PUL_SEL bits +#define cGPIO_PUL_SEL_7 (1<<7) +#define cGPIO_PUL_SEL_6 (1<<6) +#define cGPIO_PUL_SEL_5 (1<<5) +#define cGPIO_PUL_SEL_4 (1<<4) +#define cGPIO_PUL_SEL_3 (1<<3) +#define cGPIO_PUL_SEL_2 (1<<2) +#define cGPIO_PUL_SEL_1 (1<<1) +#define cGPIO_PUL_SEL_0 (1<<0) + +// GPIO_DS bits +#define cGPIO_DS_7 (1<<7) +#define cGPIO_DS_6 (1<<6) +#define cGPIO_DS_5 (1<<5) +#define cGPIO_DS_4 (1<<4) +#define cGPIO_DS_3 (1<<3) +#define cGPIO_DS_2 (1<<2) +#define cGPIO_DS_1 (1<<1) +#define cGPIO_DS_0 (1<<0) + +// SPI_CTRL bits +//#define cSPI_CTRL_MISO_HIZ_EN (1<<1) +//#define cSPI_CTRL_PB_PROTECT (1<<0) + +// ANT_PAD_CTRL bits +#define cANT_PAD_CTRL_ANTX_POL (0x0F) +#define cANT_PAD_CTRL_ANTX_POL_Shift_c (4) +#define cANT_PAD_CTRL_ANTX_CTRLMODE (1<<3) +#define cANT_PAD_CTRL_ANTX_HZ (1<<2) +#define cANT_PAD_CTRL_ANTX_EN (3) + +// MISC_PAD_CTRL bits +#define cMISC_PAD_CTRL_MISO_HIZ_EN (1<<3) +#define cMISC_PAD_CTRL_IRQ_B_OD (1<<2) +#define cMISC_PAD_CTRL_NON_GPIO_DS (1<<1) +#define cMISC_PAD_CTRL_ANTX_CURR (1<<0) + +// ANT_AGC_CTRL bits +#define cANT_AGC_CTRL_FAD_EN_Shift_c (0) +#define cANT_AGC_CTRL_FAD_EN_Mask_c (1<<cANT_AGC_CTRL_FAD_EN_Shift_c) +#define cANT_AGC_CTRL_ANTX_Shift_c (1) +#define cANT_AGC_CTRL_ANTX_Mask_c (1<<cANT_AGC_CTRL_ANTX_Shift_c) + +// BSM_CTRL bits +#define cBSM_CTRL_BSM_EN (1<<0) + +// SOFT_RESET bits +#define cSOFT_RESET_SOG_RST (1<<7) +#define cSOFT_RESET_REGS_RST (1<<4) +#define cSOFT_RESET_PLL_RST (1<<3) +#define cSOFT_RESET_TX_RST (1<<2) +#define cSOFT_RESET_RX_RST (1<<1) +#define cSOFT_RESET_SEQ_MGR_RST (1<<0) + +// SEQ_MGR_CTRL bits +#define cSEQ_MGR_CTRL_SEQ_STATE_CTRL (3) +#define cSEQ_MGR_CTRL_SEQ_STATE_CTRL_Shift_c (6) +#define cSEQ_MGR_CTRL_NO_RX_RECYCLE (1<<5) +#define cSEQ_MGR_CTRL_LATCH_PREAMBLE (1<<4) +#define cSEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH (1<<3) +#define cSEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT (1<<2) +#define cSEQ_MGR_CTRL_PSM_LOCK_DIS (1<<1) +#define cSEQ_MGR_CTRL_PLL_ABORT_OVRD (1<<0) + +// SEQ_MGR_STS bits +#define cSEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED (1<<7) +#define cSEQ_MGR_STS_RX_MODE (1<<6) +#define cSEQ_MGR_STS_RX_TIMEOUT_PENDING (1<<5) +#define cSEQ_MGR_STS_NEW_SEQ_INHIBIT (1<<4) +#define cSEQ_MGR_STS_SEQ_IDLE (1<<3) +#define cSEQ_MGR_STS_XCVSEQ_ACTUAL (7) + +// ABORT_STS bits +#define cABORT_STS_PLL_ABORTED (1<<2) +#define cABORT_STS_TC3_ABORTED (1<<1) +#define cABORT_STS_SW_ABORTED (1<<0) + +// FILTERFAIL_CODE2 bits +#define cFILTERFAIL_CODE2_PAN_SEL (1<<7) +#define cFILTERFAIL_CODE2_9_8 (3) + +// PHY_STS bits +#define cPHY_STS_PLL_UNLOCK (1<<7) +#define cPHY_STS_PLL_LOCK_ERR (1<<6) +#define cPHY_STS_PLL_LOCK (1<<5) +#define cPHY_STS_CRCVALID (1<<3) +#define cPHY_STS_FILTERFAIL_FLAG_SEL (1<<2) +#define cPHY_STS_SFD_DET (1<<1) +#define cPHY_STS_PREAMBLE_DET (1<<0) + +// TESTMODE_CTRL bits +#define cTEST_MODE_CTRL_HOT_ANT (1<<4) +#define cTEST_MODE_CTRL_IDEAL_RSSI_EN (1<<3) +#define cTEST_MODE_CTRL_IDEAL_PFC_EN (1<<2) +#define cTEST_MODE_CTRL_CONTINUOUS_EN (1<<1) +#define cTEST_MODE_CTRL_FPGA_EN (1<<0) + +// DTM_CTRL1 bits +#define cDTM_CTRL1_ATM_LOCKED (1<<7) +#define cDTM_CTRL1_DTM_EN (1<<6) +#define cDTM_CTRL1_PAGE5 (1<<5) +#define cDTM_CTRL1_PAGE4 (1<<4) +#define cDTM_CTRL1_PAGE3 (1<<3) +#define cDTM_CTRL1_PAGE2 (1<<2) +#define cDTM_CTRL1_PAGE1 (1<<1) +#define cDTM_CTRL1_PAGE0 (1<<0) + +// TX_MODE_CTRL +#define cTX_MODE_CTRL_TX_INV (1<<4) +#define cTX_MODE_CTRL_BT_EN (1<<3) +#define cTX_MODE_CTRL_DTS2 (1<<2) +#define cTX_MODE_CTRL_DTS1 (1<<1) +#define cTX_MODE_CTRL_DTS0 (1<<0) + +#define cTX_MODE_CTRL_DTS_MASK (7) + +// CLK_OUT_CTRL bits +#define cCLK_OUT_EXTEND (1<<7) +#define cCLK_OUT_HIZ (1<<6) +#define cCLK_OUT_SR (1<<5) +#define cCLK_OUT_DS (1<<4) +#define cCLK_OUT_EN (1<<3) +#define cCLK_OUT_DIV_Mask (7<<0) + +#define gCLK_OUT_FREQ_32_MHz (0) +#define gCLK_OUT_FREQ_16_MHz (1) +#define gCLK_OUT_FREQ_8_MHz (2) +#define gCLK_OUT_FREQ_4_MHz (3) +#define gCLK_OUT_FREQ_1_MHz (4) +#define gCLK_OUT_FREQ_250_KHz (5) +#define gCLK_OUT_FREQ_62_5_KHz (6) +#define gCLK_OUT_FREQ_32_78_KHz (7) +#define gCLK_OUT_FREQ_DISABLE (8) + + + + +#endif /* __MCR20_REG_H__ */
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,1782 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NanostackRfPhyMcr20a.h" +#include "ns_types.h" +#include "platform/arm_hal_interrupt.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "toolchain.h" +#include <string.h> + +/* Freescale headers which are for C files */ +extern "C" { +#include "MCR20Drv.h" +#include "MCR20Reg.h" +#include "MCR20Overwrites.h" +} + + +#define RF_BUFFER_SIZE 128 + +/*Radio RX and TX state definitions*/ +#define RFF_ON 0x01 +#define RFF_RX 0x02 +#define RFF_TX 0x04 +#define RFF_CCA 0x08 + +#define RF_MODE_NORMAL 0 +#define RF_MODE_SNIFFER 1 + +#define RF_CCA_THRESHOLD 75 /* -75 dBm */ + +#define RF_TX_POWER_MAX 0 + +/* PHY constants in symbols */ +#define gPhyWarmUpTime_c 9 +#define gPhySHRDuration_c 10 +#define gPhySymbolsPerOctet_c 2 +#define gPhyAckWaitDuration_c 54 + +#define gCcaED_c 0 +#define gCcaCCA_MODE1_c 1 + +#define gXcvrRunState_d gXcvrPwrAutodoze_c +#define gXcvrLowPowerState_d gXcvrPwrHibernate_c + + +/* MCR20A XCVR states */ +typedef enum xcvrState_tag{ + gIdle_c, + gRX_c, + gTX_c, + gCCA_c, + gTR_c, + gCCCA_c, +}xcvrState_t; + +/* MCR20A XCVR low power states */ +typedef enum xcvrPwrMode_tag{ + gXcvrPwrIdle_c, + gXcvrPwrAutodoze_c, + gXcvrPwrDoze_c, + gXcvrPwrHibernate_c +}xcvrPwrMode_t; + + +/*RF Part Type*/ +typedef enum +{ + FREESCALE_UNKNOW_DEV = 0, + FREESCALE_MCR20A +}rf_trx_part_e; + +/*Atmel RF states*/ +typedef enum +{ + NOP = 0x00, + BUSY_RX = 0x01, + RF_TX_START = 0x02, + FORCE_TRX_OFF = 0x03, + FORCE_PLL_ON = 0x04, + RX_ON = 0x06, + TRX_OFF = 0x08, + PLL_ON = 0x09, + BUSY_RX_AACK = 0x11, + SLEEP = 0x0F, + RX_AACK_ON = 0x16, + TX_ARET_ON = 0x19 +}rf_trx_states_t; + +/*RF receive buffer*/ +static uint8_t rf_buffer[RF_BUFFER_SIZE]; + +/* TX info */ +static uint8_t radio_tx_power = 0x17; /* 0 dBm */ +static uint8_t mac_tx_handle = 0; +static uint8_t need_ack = 0; +static uint16_t tx_len = 0; + +/* RF driver data */ +static xcvrState_t mPhySeqState; +static xcvrPwrMode_t mPwrState; +static phy_device_driver_s device_driver; +static uint8_t mStatusAndControlRegs[8]; +static uint8_t rf_rnd = 0; +static int8_t rf_radio_driver_id = -1; +static uint8_t MAC_address[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + +/* Driver instance handle and hardware */ +static NanostackRfPhyMcr20a *rf = NULL; +static SPI *spi = NULL; +static DigitalOut *cs = NULL; +static DigitalOut *rst = NULL; +static InterruptIn *irq = NULL; +static DigitalIn *irq_pin = NULL; + +/* Channel info */ /* 2405 2410 2415 2420 2425 2430 2435 2440 2445 2450 2455 2460 2465 2470 2475 2480 */ +static const uint8_t pll_int[16] = {0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D}; +static const uint16_t pll_frac[16] = {0x2800, 0x5000, 0x7800, 0xA000, 0xC800, 0xF000, 0x1800, 0x4000, 0x6800, 0x9000, 0xB800, 0xE000, 0x0800, 0x3000, 0x5800, 0x8000}; +static uint8_t rf_phy_channel = 0; + +/* Channel configurations for 2.4 */ +static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_0, NULL} +}; + + +static rf_trx_part_e rf_radio_type_read(void); + +MBED_UNUSED static void rf_ack_wait_timer_start(uint16_t slots); +MBED_UNUSED static void rf_ack_wait_timer_stop(void); +MBED_UNUSED static void rf_handle_cca_ed_done(void); +MBED_UNUSED static void rf_handle_tx_end(void); +MBED_UNUSED static void rf_handle_rx_end(void); +MBED_UNUSED static void rf_on(void); +MBED_UNUSED static void rf_receive(void); +MBED_UNUSED static void rf_poll_trx_state_change(rf_trx_states_t trx_state); +MBED_UNUSED static void rf_init(void); +MBED_UNUSED static void rf_set_mac_address(const uint8_t *ptr); +MBED_UNUSED static int8_t rf_device_register(void); +MBED_UNUSED static void rf_device_unregister(void); +MBED_UNUSED static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); +MBED_UNUSED static void rf_cca_abort(void); +MBED_UNUSED static void rf_read_mac_address(uint8_t *ptr); +MBED_UNUSED static int8_t rf_read_random(void); +MBED_UNUSED static void rf_calibration_cb(void); +MBED_UNUSED static void rf_init_phy_mode(void); +MBED_UNUSED static void rf_ack_wait_timer_interrupt(void); +MBED_UNUSED static void rf_calibration_timer_interrupt(void); +MBED_UNUSED static void rf_calibration_timer_start(uint32_t slots); +MBED_UNUSED static void rf_cca_timer_interrupt(void); +MBED_UNUSED static void rf_cca_timer_start(uint32_t slots); +MBED_UNUSED static uint16_t rf_get_phy_mtu_size(void); +MBED_UNUSED static uint8_t rf_scale_lqi(int8_t rssi); + +/** + * RF output power write + * + * \brief TX power has to be set before network start. + * + * \param power + * See datasheet for TX power settings + * + * \return 0, Supported Value + * \return -1, Not Supported Value + */ +MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power); +MBED_UNUSED static uint8_t rf_tx_power_get(void); +MBED_UNUSED static int8_t rf_enable_antenna_diversity(void); + +/* Private functions */ +MBED_UNUSED static void rf_abort(void); +MBED_UNUSED static void rf_promiscuous(uint8_t mode); +MBED_UNUSED static void rf_get_timestamp(uint32_t *pRetClk); +MBED_UNUSED static void rf_set_timeout(uint32_t *pEndTime); +MBED_UNUSED static void rf_set_power_state(xcvrPwrMode_t newState); +MBED_UNUSED static uint8_t rf_if_read_rnd(void); +MBED_UNUSED static uint8_t rf_convert_LQI(uint8_t hwLqi); +MBED_UNUSED static uint8_t rf_get_channel_energy(void); +MBED_UNUSED static uint8_t rf_convert_energy_level(uint8_t energyLevel); +MBED_UNUSED static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi); +MBED_UNUSED static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +MBED_UNUSED static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr); +MBED_UNUSED static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr); +MBED_UNUSED static void rf_mac64_read(uint8_t *address); + + + +/* + * \brief Read connected radio part. + * + * This function only return valid information when rf_init() is called + * + * \return + */ +static rf_trx_part_e rf_radio_type_read(void) +{ + return FREESCALE_MCR20A; +} + +/* + * \brief Function initialises and registers the RF driver. + * + * \param none + * + * \return rf_radio_driver_id Driver ID given by NET library + */ +static int8_t rf_device_register(void) +{ + rf_trx_part_e radio_type; + + rf_init(); + + + + radio_type = rf_radio_type_read(); + if(radio_type == FREESCALE_MCR20A) + { + /*Set pointer to MAC address*/ + device_driver.PHY_MAC = MAC_address; + device_driver.driver_description = (char*)"FREESCALE_MAC"; + + //Create setup Used Radio chips + /*Type of RF PHY is SubGHz*/ + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + + device_driver.phy_channel_pages = phy_channel_pages; + /*Maximum size of payload is 127*/ + device_driver.phy_MTU = 127; + /*No header in PHY*/ + device_driver.phy_header_length = 0; + /*No tail in PHY*/ + device_driver.phy_tail_length = 0; + /*Set address write function*/ + device_driver.address_write = &rf_address_write; + /*Set RF extension function*/ + device_driver.extension = &rf_extension; + /*Set RF state control function*/ + device_driver.state_control = &rf_interface_state_control; + /*Set transmit function*/ + device_driver.tx = &rf_start_cca; + /*Upper layer callbacks init to NULL*/ + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + /*Virtual upper data callback init to NULL*/ + device_driver.arm_net_virtual_rx_cb = NULL; + device_driver.arm_net_virtual_tx_cb = NULL; + + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + } + + return rf_radio_driver_id; +} + +/* + * \brief Function unregisters the RF driver. + * + * \param none + * + * \return none + */ +static void rf_device_unregister(void) +{ + arm_net_phy_unregister(rf_radio_driver_id); +} + +/* + * \brief Function returns the generated 8-bit random value for seeding Pseudo-random generator. + * + * \param none + * + * \return random value + */ +static int8_t rf_read_random(void) +{ + return rf_rnd; +} + +/* + * \brief Function is a call back for ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_interrupt(void) +{ + /* The packet was transmitted successfully, but no ACK was received */ + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); + } + rf_receive(); +} + +/* + * \brief Function is a call back for calibration interval timer. + * + * \param none + * + * \return none + */ +static void rf_calibration_timer_interrupt(void) +{ +} + +/* + * \brief Function is a call back for cca interval timer. + * + * \param none + * + * \return none + */ +static void rf_cca_timer_interrupt(void) +{ + /* CCA time-out handled by Hardware */ +} + + +/* + * \brief Function starts the ACK wait time-out. + * + * \param slots The ACK wait time-out in [symbols] + * + * \return none + */ +static void rf_ack_wait_timer_start(uint16_t time) +{ + uint32_t timeout; + + rf_get_timestamp(&timeout); + timeout += time; + rf_set_timeout(&timeout); +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_calibration_timer_start(uint32_t slots) +{ + (void)slots; +} + +/* + * \brief Function starts the CCA timout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_cca_timer_start(uint32_t slots) +{ + (void)slots; +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_stop(void) +{ +} + +/* + * \brief Function reads the MAC address array. + * + * \param ptr Pointer to read array + * + * \return none + */ +static void rf_read_mac_address(uint8_t *ptr) +{ + memcpy(ptr, MAC_address, 8); +} + +/* + * \brief Function sets the MAC address array. + * + * \param ptr Pointer to given MAC address array + * + * \return none + */ +static void rf_set_mac_address(const uint8_t *ptr) +{ + memcpy(MAC_address, ptr, 8); +} + +static uint16_t rf_get_phy_mtu_size(void) +{ + return device_driver.phy_MTU; +} + +/* + * \brief Function writes 16-bit address in RF address filter. + * + * \param short_address Given short address + * + * \return none + */ +static void rf_set_short_adr(uint8_t * short_address) +{ + /* Write one register at a time to be accessible from hibernate mode */ + MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_MSB, short_address[0]); + MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_LSB, short_address[1]); +} + +/* + * \brief Function writes PAN Id in RF PAN Id filter. + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_set_pan_id(uint8_t *pan_id) +{ + /* Write one register at a time to be accessible from hibernate mode */ + MCR20Drv_IndirectAccessSPIWrite(MACPANID0_MSB, pan_id[0]); + MCR20Drv_IndirectAccessSPIWrite(MACPANID0_LSB, pan_id[1]); +} + +/* + * \brief Function writes 64-bit address in RF address filter. + * + * \param address Given 64-bit address + * + * \return none + */ +static void rf_set_address(uint8_t *address) +{ + /* Write one register at a time to be accessible from hibernate mode */ + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_0, address[7]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_8, address[6]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_16, address[5]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_24, address[4]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_32, address[3]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_40, address[2]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_48, address[1]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_56, address[0]); +} + +/* + * \brief Function sets the RF channel. + * + * \param ch New channel + * + * \return none + */ +static void rf_channel_set(uint8_t channel) +{ + rf_phy_channel = channel; + MCR20Drv_DirectAccessSPIWrite(PLL_INT0, pll_int[channel - 11]); + MCR20Drv_DirectAccessSPIMultiByteWrite(PLL_FRAC0_LSB, (uint8_t *) &pll_frac[channel - 11], 2); +} + + +/* + * \brief Function initialises the radio driver and resets the radio. + * + * \param none + * + * \return none + */ +static void rf_init(void) +{ + uint32_t index; + mPhySeqState = gIdle_c; + mPwrState = gXcvrPwrIdle_c; + /*Reset RF module*/ + MCR20Drv_RESET(); + /* Initialize the transceiver SPI driver */ + MCR20Drv_Init(); + /* Disable Tristate on MISO for SPI reads */ + MCR20Drv_IndirectAccessSPIWrite(MISC_PAD_CTRL, 0x02); + /* Set XCVR clock output settings */ + MCR20Drv_Set_CLK_OUT_Freq(gMCR20_ClkOutFreq_d); + /* Set default XCVR power state */ + rf_set_power_state(gXcvrRunState_d); + + /* PHY_CTRL1 default HW settings + AUTOACK enabled */ + mStatusAndControlRegs[PHY_CTRL1] = cPHY_CTRL1_AUTOACK; + /* PHY_CTRL2 : mask all PP interrupts */ + mStatusAndControlRegs[PHY_CTRL2] = cPHY_CTRL2_CRC_MSK | \ + cPHY_CTRL2_PLL_UNLOCK_MSK | \ + /*cPHY_CTRL2_FILTERFAIL_MSK | */ \ + cPHY_CTRL2_RX_WMRK_MSK | \ + cPHY_CTRL2_CCAMSK | \ + cPHY_CTRL2_RXMSK | \ + cPHY_CTRL2_TXMSK | \ + cPHY_CTRL2_SEQMSK; + /* PHY_CTRL3 : enable timer 3 and disable remaining interrupts */ + mStatusAndControlRegs[PHY_CTRL3] = cPHY_CTRL3_ASM_MSK | \ + cPHY_CTRL3_PB_ERR_MSK | \ + cPHY_CTRL3_WAKE_MSK | \ + cPHY_CTRL3_TMR3CMP_EN; + /* PHY_CTRL4 unmask global TRX interrupts, enable 16 bit mode for TC2 - TC2 prime EN */ + mStatusAndControlRegs[PHY_CTRL4] = cPHY_CTRL4_TC2PRIME_EN | (gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c); + /* Clear all PP IRQ bits to avoid unexpected interrupts immediately after initialization */ + mStatusAndControlRegs[IRQSTS1] = cIRQSTS1_PLL_UNLOCK_IRQ | \ + cIRQSTS1_FILTERFAIL_IRQ | \ + cIRQSTS1_RXWTRMRKIRQ | \ + cIRQSTS1_CCAIRQ | \ + cIRQSTS1_RXIRQ | \ + cIRQSTS1_TXIRQ | \ + cIRQSTS1_SEQIRQ; + + mStatusAndControlRegs[IRQSTS2] = cIRQSTS2_ASM_IRQ | cIRQSTS2_PB_ERR_IRQ | cIRQSTS2_WAKE_IRQ; + /* Mask and clear all TMR IRQs */ + mStatusAndControlRegs[IRQSTS3] = cIRQSTS3_TMR4MSK | cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2MSK | cIRQSTS3_TMR1MSK | \ + cIRQSTS3_TMR4IRQ | cIRQSTS3_TMR3IRQ | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR1IRQ; + /* Write settings to XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 5); + /* Clear all interrupts */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, &mStatusAndControlRegs[IRQSTS1], 3); + + /* RX_FRAME_FILTER. Accept FrameVersion 0 and 1 packets, reject all others */ + MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, (cRX_FRAME_FLT_FRM_VER | \ + cRX_FRAME_FLT_BEACON_FT | \ + cRX_FRAME_FLT_DATA_FT | \ + cRX_FRAME_FLT_CMD_FT )); + /* Direct register overwrites */ + for (index = 0; index < sizeof(overwrites_direct)/sizeof(overwrites_t); index++) + MCR20Drv_DirectAccessSPIWrite(overwrites_direct[index].address, overwrites_direct[index].data); + /* Indirect register overwrites */ + for (index = 0; index < sizeof(overwrites_indirect)/sizeof(overwrites_t); index++) + MCR20Drv_IndirectAccessSPIWrite(overwrites_indirect[index].address, overwrites_indirect[index].data); + + /* Set the CCA energy threshold value */ + MCR20Drv_IndirectAccessSPIWrite(CCA1_THRESH, RF_CCA_THRESHOLD); + /* Set prescaller to obtain 1 symbol (16us) timebase */ + MCR20Drv_IndirectAccessSPIWrite(TMR_PRESCALE, 0x05); + + MCR20Drv_IRQ_Enable(); + + /*Read random variable. This will be used when seeding pseudo-random generator*/ + rf_rnd = rf_if_read_rnd(); + /*Read eui64*/ + rf_mac64_read(MAC_address); + /*set default channel to 11*/ + rf_channel_set(11); + /*Start receiver*/ + rf_receive(); +} + +/** + * \brief Function gets called when MAC is setting radio off. + * + * \param none + * + * \return none + */ +static void rf_off(void) +{ + /* Abort any ongoing sequences */ + rf_abort(); + /* Set XCVR in a low power state */ + rf_set_power_state(gXcvrLowPowerState_d); +} + +/* + * \brief Function polls the RF state until it has changed to desired state. + * + * \param trx_state RF state + * + * \return none + */ +static void rf_poll_trx_state_change(rf_trx_states_t trx_state) +{ + (void)trx_state; +} + +/* + * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. + * + * \param data_ptr Pointer to TX data + * \param data_length Length of the TX data + * \param tx_handle Handle to transmission + * \return 0 Success + * \return -1 Busy + */ +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ) +{ + uint8_t ccaMode; + + /* Parameter validation */ + if( !data_ptr || (data_length > 125) || (PHY_LAYER_PAYLOAD != data_protocol) ) + { + return -1; + } + + if( mPhySeqState == gRX_c ) + { + uint8_t phyReg = MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F; + /* Check for an Rx in progress. */ + if((phyReg <= 0x06) || (phyReg == 0x15) || (phyReg == 0x16)) + { + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } + return -1; + } + rf_abort(); + } + + /*Check if transmitter is busy*/ + if( mPhySeqState != gIdle_c ) + { + /*Return busy*/ + return -1; + } + + /*Store TX handle*/ + mac_tx_handle = tx_handle; + /*Check if transmitted data needs to be acked*/ + need_ack = (*data_ptr & 0x20) == 0x20; + + /* Set XCVR power state in run mode */ + rf_set_power_state(gXcvrRunState_d); + /* Load data into XCVR */ + tx_len = data_length + 2; + MCR20Drv_PB_SPIBurstWrite(data_ptr - 1, data_length + 1); + MCR20Drv_PB_SPIByteWrite(0,tx_len); + + /* Set CCA mode 1 */ + ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE; + if( ccaMode != gCcaCCA_MODE1_c ) + { + mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); + mStatusAndControlRegs[PHY_CTRL4] |= gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]); + } + + /* Read XCVR registers */ + mStatusAndControlRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[1], 4); + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c; + mPhySeqState = gCCA_c; + + /* Ensure that no spurious interrupts are raised */ + mStatusAndControlRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */ + mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ); + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); + + /* Write XCVR settings */ + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + + /* Unmask SEQ interrupt */ + mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]); + + /*Return success*/ + return 0; +} + +/* + * \brief Function aborts CCA process. + * + * \param none + * + * \return none + */ +static void rf_cca_abort(void) +{ + rf_abort(); +} + +/* + * \brief Function starts the transmission of the frame. Called from ISR context! + * + * \param none + * + * \return none + */ +static void rf_start_tx(void) +{ + /* Perform TxRxAck sequence if required by phyTxMode */ + if( need_ack ) + { + mStatusAndControlRegs[PHY_CTRL1] |= cPHY_CTRL1_RXACKRQD; + mPhySeqState = gTR_c; + } + else + { + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_RXACKRQD); + mPhySeqState = gTX_c; + } + + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + mStatusAndControlRegs[PHY_CTRL1] |= mPhySeqState; + + /* Unmask SEQ interrupt */ + mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); + + /* Start the sequence immediately */ + MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 2); + + if( need_ack ) + { + rf_ack_wait_timer_start(gPhyWarmUpTime_c + gPhySHRDuration_c + tx_len * gPhySymbolsPerOctet_c + gPhyAckWaitDuration_c); + } +} + +/* + * \brief Function sets the RF in RX state. Called from ISR context! + * + * \param none + * + * \return none + */ +static void rf_receive(void) +{ + uint8_t phyRegs[5]; + + /* RX can start only from Idle state */ + if( mPhySeqState != gIdle_c ) + { + return; + } + + /* Set XCVR power state in run mode */ + rf_set_power_state(gXcvrRunState_d); + /* read XVCR settings */ + phyRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[IRQSTS2], 4); + /* unmask SEQ interrupt */ + phyRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); + /* set XcvrSeq to RX */ + phyRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + phyRegs[PHY_CTRL1] |= gRX_c; + mPhySeqState = gRX_c; + /* Ensure that no spurious interrupts are raised */ + phyRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */ + phyRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ; + /* sync settings with XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 5); +} + +/* + * \brief Function calibrates the radio. + * + * \param none + * + * \return none + */ +static void rf_calibration_cb(void) +{ +} + +/* + * \brief Function sets RF_ON flag when radio is powered. + * + * \param none + * + * \return none + */ +static void rf_on(void) +{ +} + +/* + * \brief Function is a call back for RX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_rx_end(void) +{ + uint8_t rf_lqi = MCR20Drv_DirectAccessSPIRead(LQI_VALUE); + int8_t rf_rssi = 0; + uint8_t len = mStatusAndControlRegs[RX_FRM_LEN] - 2; + + + /*Start receiver*/ + rf_receive(); + + /*Check the length is valid*/ + if(len > 1 && len < RF_BUFFER_SIZE) + { + rf_lqi = rf_convert_LQI(rf_lqi); + rf_rssi = rf_convert_LQI_to_RSSI(rf_lqi); + /*gcararu: Scale LQI using received RSSI, to match the LQI reported by the ATMEL radio */ + rf_lqi = rf_scale_lqi(rf_rssi); + + /*Read received packet*/ + MCR20Drv_PB_SPIBurstRead(rf_buffer, len); + if (device_driver.phy_rx_cb) { + device_driver.phy_rx_cb(rf_buffer, len, rf_lqi, rf_rssi, rf_radio_driver_id); + } + } +} + +/* + * \brief Function is called when MAC is shutting down the radio. + * + * \param none + * + * \return none + */ +static void rf_shutdown(void) +{ + /*Call RF OFF*/ + rf_off(); +} + +/* + * \brief Function is a call back for TX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_tx_end(void) +{ + uint8_t rx_frame_pending = mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_RX_FRM_PEND; + + /*Start receiver*/ + rf_receive(); + + if (!device_driver.phy_tx_done_cb) { + return; + } + + /*Call PHY TX Done API*/ + if( need_ack ) + { + if( rx_frame_pending ) + { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE_PENDING, 1, 1); + } + else + { + // arm_net_phy_tx_done(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE, 1, 1); + } + } + else + { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); + } +} + +/* + * \brief Function is a call back for CCA ED done interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_cca_ed_done(void) +{ + /*Check the result of CCA process*/ + if( !(mStatusAndControlRegs[IRQSTS2] & cIRQSTS2_CCA) ) + { + rf_start_tx(); + } + else if (device_driver.phy_tx_done_cb) + { + /*Send CCA fail notification*/ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } +} + +/* + * \brief Function sets the TX power variable. + * + * \param power TX power setting + * + * \return 0 Success + * \return -1 Fail + */ +static int8_t rf_tx_power_set(uint8_t power) +{ + /* gcapraru: Map MCR20A Tx power levels over ATMEL values */ + static uint8_t pwrLevelMapping[16] = {25,25,25,24,24,24,23,23,22,22,21,20,19,18,17,14}; + + if( power > 15 ) + { + return -1; + } + + radio_tx_power = power; + MCR20Drv_DirectAccessSPIWrite(PA_PWR, pwrLevelMapping[power]); + return 0; +} + +/* + * \brief Function returns the TX power variable. + * + * \param none + * + * \return radio_tx_power TX power variable + */ +static uint8_t rf_tx_power_get(void) +{ + return radio_tx_power; +} + +/* + * \brief Function enables the usage of Antenna diversity. + * + * \param none + * + * \return 0 Success + */ +static int8_t rf_enable_antenna_diversity(void) +{ + uint8_t phyReg; + + phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_AGC_CTRL); + phyReg |= cANT_AGC_CTRL_FAD_EN_Mask_c; + MCR20Drv_IndirectAccessSPIWrite(ANT_AGC_CTRL, phyReg); + + phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_PAD_CTRL); + phyReg |= 0x02; + MCR20Drv_IndirectAccessSPIWrite(ANT_PAD_CTRL, phyReg); + + return 0; +} + +/* + * \brief Function gives the control of RF states to MAC. + * + * \param new_state RF state + * \param rf_channel RF channel + * + * \return 0 Success + */ +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) + { + /*Reset PHY driver and set to idle*/ + case PHY_INTERFACE_RESET: + break; + /*Disable PHY Interface driver*/ + case PHY_INTERFACE_DOWN: + rf_shutdown(); + break; + /*Enable PHY Interface driver*/ + case PHY_INTERFACE_UP: + rf_channel_set(rf_channel); + rf_receive(); + break; + /*Enable wireless interface ED scan mode*/ + case PHY_INTERFACE_RX_ENERGY_STATE: + rf_abort(); + rf_channel_set(rf_channel); + break; + case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ + rf_promiscuous(1); + rf_channel_set(rf_channel); + rf_receive(); + break; + } + return ret_val; +} + +/* + * \brief Function controls the ACK pending, channel setting and energy detection. + * + * \param extension_type Type of control + * \param data_ptr Data from NET library + * + * \return 0 Success + */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) + { + /*Control MAC pending bit for Indirect data transmission*/ + case PHY_EXTENSION_CTRL_PENDING_BIT: + { + uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL); + + if(*data_ptr) + { + reg |= cSRC_CTRL_ACK_FRM_PND; + } + else + { + reg &= ~cSRC_CTRL_ACK_FRM_PND; + } + + MCR20Drv_DirectAccessSPIWrite(SRC_CTRL, reg); + break; + + } + /*Return frame pending status*/ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: + *data_ptr = MCR20Drv_DirectAccessSPIRead(IRQSTS1 & cIRQSTS1_RX_FRM_PEND); + break; + /*Set channel*/ + case PHY_EXTENSION_SET_CHANNEL: + break; + /*Read energy on the channel*/ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + *data_ptr = rf_get_channel_energy(); + break; + /*Read status of the link*/ + case PHY_EXTENSION_READ_LINK_STATUS: + break; + case PHY_EXTENSION_CONVERT_SIGNAL_INFO: + break; + } + return 0; +} + +/* + * \brief Function sets the addresses to RF address filters. + * + * \param address_type Type of address + * \param address_ptr Pointer to given address + * + * \return 0 Success + */ +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + int8_t ret_val = 0; + switch (address_type) + { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + break; + /*Set 64-bit address*/ + case PHY_MAC_64BIT: + rf_set_address(address_ptr); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + rf_set_short_adr(address_ptr); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + rf_set_pan_id(address_ptr); + break; + } + return ret_val; +} + +static void rf_mac64_read(uint8_t *address) +{ + /* Write one register at a time to be accessible from hibernate mode */ + address[7] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_0); + address[6] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_8); + address[5] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_16); + address[4] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_24); + address[3] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_32); + address[2] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_40); + address[1] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_48); + address[0] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_56); + +} + +/* + * \brief Function initialises the ACK wait time and returns the used PHY mode. + * + * \param none + * + * \return tmp Used PHY mode + */ +static void rf_init_phy_mode(void) +{ +} + +/* + * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt. + * + * \param none + * + * \return none + */ +static void PHY_InterruptHandler(void) +{ + uint8_t xcvseqCopy; + + /* Disable and clear transceiver(IRQ_B) interrupt */ + MCR20Drv_IRQ_Disable(); + //MCR20Drv_IRQ_Clear(); + + /* Read transceiver interrupt status and control registers */ + mStatusAndControlRegs[IRQSTS1] = + MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 7); + + xcvseqCopy = mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ; + + /* Flter Fail IRQ */ + if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_FILTERFAIL_IRQ) && + !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_FILTERFAIL_MSK) ) + { + if( xcvseqCopy == gRX_c ) + { + /* Abort current SEQ */ + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + /* Wait for Sequence Idle */ + while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0); + /* Clear IRQ flags: */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ); + /* Restart Rx asap */ + mStatusAndControlRegs[PHY_CTRL1] |= gRX_c; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + } + } + + /* TMR3 IRQ: ACK wait time-out */ + if( (mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3IRQ) && + !(mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3MSK) ) + { + /* Disable TMR3 IRQ */ + mStatusAndControlRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK; + + if( xcvseqCopy == gTR_c ) + { + /* Set XCVR to Idle */ + mPhySeqState = gIdle_c; + mStatusAndControlRegs[PHY_CTRL1] &= ~( cPHY_CTRL1_XCVSEQ ); + /* Mask interrupts */ + mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK; + /* Sync settings with XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5); + + rf_ack_wait_timer_interrupt(); + MCR20Drv_IRQ_Enable(); + return; + } + } + + /* Sequencer interrupt, the autosequence has completed */ + if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_SEQIRQ) && + !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_SEQMSK) ) + { + /* Set XCVR to Idle */ + mPhySeqState = gIdle_c; + mStatusAndControlRegs[PHY_CTRL1] &= ~( cPHY_CTRL1_XCVSEQ ); + /* Mask interrupts */ + mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK; + /* Sync settings with XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5); + + /* PLL unlock, the autosequence has been aborted due to PLL unlock */ + if( mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_PLL_UNLOCK_IRQ ) + { + if(xcvseqCopy == gRX_c) + { + rf_receive(); + } + MCR20Drv_IRQ_Enable(); + return; + } + + switch(xcvseqCopy) + { + case gTX_c: + case gTR_c: + rf_handle_tx_end(); + break; + + case gRX_c: + rf_handle_rx_end(); + break; + + case gCCA_c: + rf_handle_cca_ed_done(); + break; + + default: + break; + } + + MCR20Drv_IRQ_Enable(); + return; + } + /* Other IRQ. Clear XCVR interrupt flags */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); + MCR20Drv_IRQ_Enable(); +} + +/* + * \brief Function forces the XCVR to Idle state. + * + * \param none + * + * \return none + */ +static void rf_abort(void) +{ + /* Mask XCVR irq */ + MCR20Drv_IRQ_Disable(); + + mPhySeqState = gIdle_c; + + mStatusAndControlRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 5); + + /* Mask SEQ interrupt */ + mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_SEQMSK; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]); + + if( (mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ) != gIdle_c ) + { + /* Abort current SEQ */ + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + + /* Wait for Sequence Idle (if not already) */ + while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0); + //while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ)); + mStatusAndControlRegs[IRQSTS1] |= cIRQSTS1_SEQIRQ; + } + + /* Clear all PP IRQ bits to avoid unexpected interrupts and mask TMR3 interrupt. + Do not change TMR IRQ status. */ + mStatusAndControlRegs[IRQSTS3] &= 0xF0; + mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ); + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); + + /* Unmask XCVR irq */ + MCR20Drv_IRQ_Enable(); +} + +/* + * \brief Function reads a time-stamp value from XCVR [symbols] + * + * \param pEndTime pointer to location where time-stamp will be stored + * + * \return none + */ +static void rf_get_timestamp(uint32_t *pRetClk) +{ + if(NULL == pRetClk) + { + return; + } + + platform_enter_critical(); + + *pRetClk = 0; + MCR20Drv_DirectAccessSPIMultiByteRead(EVENT_TMR_LSB, (uint8_t *) pRetClk, 3); + + platform_exit_critical(); +} + +/* + * \brief Function set a time-out to an XCVR sequence. + * + * \param pEndTime pointer to the sequence time-out value [symbols] + * + * \return none + */ +static void rf_set_timeout(uint32_t *pEndTime) +{ + uint8_t phyReg; + + if(NULL == pEndTime) + { + return; + } + + platform_enter_critical(); + + phyReg = MCR20Drv_DirectAccessSPIRead(IRQSTS3); + phyReg &= 0xF0; /* do not change IRQ status */ + phyReg |= (cIRQSTS3_TMR3MSK); /* mask TMR3 interrupt */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg); + + MCR20Drv_DirectAccessSPIMultiByteWrite(T3CMP_LSB, (uint8_t *) pEndTime, 3); + + phyReg &= ~(cIRQSTS3_TMR3MSK); /* unmask TMR3 interrupt */ + phyReg |= (cIRQSTS3_TMR3IRQ); /* aknowledge TMR3 IRQ */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg); + + platform_exit_critical(); +} + +/* + * \brief Function reads a random number from RF. + * + * \param none + * + * \return 8-bit random number + */ +static uint8_t rf_if_read_rnd(void) +{ + uint8_t phyReg; + + MCR20Drv_IRQ_Disable(); + /* Check if XCVR is idle */ + phyReg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL1); + + if( (phyReg & cPHY_CTRL1_XCVSEQ) == gIdle_c ) + { + /* Program a new sequence */ + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, phyReg | gCCA_c); + /* Wait for sequence to finish */ + while( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ) ); + /* Clear interrupt flag */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ); + } + + MCR20Drv_IRQ_Enable(); + + return MCR20Drv_IndirectAccessSPIRead(_RNG); +} + +/* + * \brief Function converts LQI into RSSI. + * + * \param LQI + * + * \return RSSI + */ +static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi) +{ + int32_t rssi = (50*lqi - 16820) / 163; + return (int8_t)rssi; +} + +/* + * \brief Function scale the LQI value reported by RF into a 0-255 value. + * + * \param hwLqi - the LQI value reported by RF + * + * \return scaled LQI + */ +static uint8_t rf_convert_LQI(uint8_t hwLqi) +{ + uint32_t tmpLQI; + + /* LQI Saturation Level */ + if (hwLqi >= 230) + { + return 0xFF; + } + else if (hwLqi <= 9) + { + return 0; + } + else + { + /* Rescale the LQI values from min to saturation to the 0x00 - 0xFF range */ + /* The LQI value mst be multiplied by ~1.1087 */ + /* tmpLQI = hwLqi * 7123 ~= hwLqi * 65536 * 0.1087 = hwLqi * 2^16 * 0.1087*/ + tmpLQI = ((uint32_t)hwLqi * (uint32_t)7123 ); + /* tmpLQI = (tmpLQI / 2^16) + hwLqi */ + tmpLQI = (uint32_t)(tmpLQI >> 16) + (uint32_t)hwLqi; + + return (uint8_t)tmpLQI; + } +} + +/* + * \brief Function enables/disables Rx promiscuous mode. + * + * \param state of XCVR promiscuous mode + * + * \return none + */ +static void rf_promiscuous(uint8_t state) +{ + uint8_t rxFrameFltReg, phyCtrl4Reg; + + rxFrameFltReg = MCR20Drv_IndirectAccessSPIRead(RX_FRAME_FILTER); + phyCtrl4Reg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4); + + if( state ) + { + /* FRM_VER[1:0] = b00. 00: Any FrameVersion accepted (0,1,2 & 3) */ + /* All frame types accepted*/ + phyCtrl4Reg |= cPHY_CTRL4_PROMISCUOUS; + rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER); + rxFrameFltReg |= (cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT); + } + else + { + phyCtrl4Reg &= ~cPHY_CTRL4_PROMISCUOUS; + /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets, reject all others */ + /* Beacon, Data and MAC command frame types accepted */ + rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER); + rxFrameFltReg |= (0x03 << cRX_FRAME_FLT_FRM_VER_Shift_c); + rxFrameFltReg &= ~(cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT); + } + + MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, rxFrameFltReg); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, phyCtrl4Reg); +} + +/* + * \brief Function used to switch XCVR power state. + * + * \param state The XCVR power mode + * + * \return none + */ +static void rf_set_power_state(xcvrPwrMode_t newState) +{ + uint8_t pwrMode; + uint8_t xtalState; + + if( mPwrState == newState ) + { + return; + } + + /* Read power settings from RF */ + pwrMode = MCR20Drv_DirectAccessSPIRead(PWR_MODES); + xtalState = pwrMode & cPWR_MODES_XTALEN; + + switch( newState ) + { + case gXcvrPwrIdle_c: + pwrMode &= ~(cPWR_MODES_AUTODOZE); + pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_PMC_MODE); + break; + case gXcvrPwrAutodoze_c: + pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); + break; + case gXcvrPwrDoze_c: + pwrMode &= ~(cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); + pwrMode |= cPWR_MODES_XTALEN; + break; + case gXcvrPwrHibernate_c: + pwrMode &= ~(cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); + break; + default: + return; + } + + mPwrState = newState; + MCR20Drv_DirectAccessSPIWrite(PWR_MODES, pwrMode); + + if( !xtalState && (pwrMode & cPWR_MODES_XTALEN)) + { + /* wait for crystal oscillator to complet its warmup */ + while( ( MCR20Drv_DirectAccessSPIRead(PWR_MODES) & cPWR_MODES_XTAL_READY ) != cPWR_MODES_XTAL_READY); + /* wait for radio wakeup from hibernate interrupt */ + while( ( MCR20Drv_DirectAccessSPIRead(IRQSTS2) & (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ) != (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ); + + MCR20Drv_DirectAccessSPIWrite(IRQSTS2, cIRQSTS2_WAKE_IRQ); + } +} + +/* + * \brief Function reads the energy level on the preselected channel. + * + * \return energy level + */ +static uint8_t rf_get_channel_energy(void) +{ + uint8_t ccaMode; + + MCR20Drv_IRQ_Disable(); + /* RX can start only from Idle state */ + if( mPhySeqState != gIdle_c ) + { + MCR20Drv_IRQ_Enable(); + return 0; + } + + /* Set XCVR power state in run mode */ + rf_set_power_state(gXcvrRunState_d); + + /* Switch to ED mode */ + ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE; + if( ccaMode != gCcaED_c ) + { + mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); + mStatusAndControlRegs[PHY_CTRL4] |= gCcaED_c << cPHY_CTRL4_CCATYPE_Shift_c; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]); + } + + /* Start ED sequence */ + mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c; + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + /* Wait for sequence to finish */ + while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ)); + /* Set XCVR to Idle */ + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ); + + MCR20Drv_IRQ_Enable(); + + return rf_convert_energy_level(MCR20Drv_DirectAccessSPIRead(CCA1_ED_FNL)); +} + +/* + * \brief Function converts the energy level from dBm to a 0-255 value. + * + * \param energyLevel in dBm + * + * \return energy level (0-255) + */ +static uint8_t rf_convert_energy_level(uint8_t energyLevel) +{ + if(energyLevel >= 90) + { + /* ED value is below minimum. Return 0x00. */ + energyLevel = 0x00; + } + else if(energyLevel <= 26) + { + /* ED value is above maximum. Return 0xFF. */ + energyLevel = 0xFF; + } + else + { + /* Energy level (-90 dBm to -26 dBm ) --> varies form 0 to 64 */ + energyLevel = (90 - energyLevel); + /* Rescale the energy level values to the 0x00-0xff range (0 to 64 translates in 0 to 255) */ + /* energyLevel * 3.9844 ~= 4 */ + /* Multiply with 4=2^2 by shifting left. + The multiplication will not overflow beacause energyLevel has values between 0 and 63 */ + energyLevel <<= 2; + } + + return energyLevel; +} + +static uint8_t rf_scale_lqi(int8_t rssi) +{ + uint8_t scaled_lqi; + /*Worst case sensitivity*/ + const int8_t rf_sensitivity = -98; + + /*rssi < RF sensitivity*/ + if(rssi < rf_sensitivity) + scaled_lqi=0; + /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/ + /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 10)) + scaled_lqi=31; + /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/ + /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 20)) + scaled_lqi=207; + /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/ + /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 30)) + scaled_lqi=255; + /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/ + /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 40)) + scaled_lqi=255; + /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/ + /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 50)) + scaled_lqi=255; + /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/ + /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 60)) + scaled_lqi=255; + /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/ + /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 70)) + scaled_lqi=255; + /*rssi > RF saturation*/ + else if(rssi > (rf_sensitivity + 80)) + scaled_lqi=111; + /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/ + /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/ + else + scaled_lqi=255; + + return scaled_lqi; +} + + +/*****************************************************************************/ +/* Layer porting to the Freescale driver */ +/*****************************************************************************/ +extern "C" void xcvr_spi_init(uint32_t instance) +{ + (void)instance; +} + +extern "C" void RF_IRQ_Init(void) { + MBED_ASSERT(irq != NULL); + irq->mode(PullUp); + irq->fall(&PHY_InterruptHandler); +} + +extern "C" void RF_IRQ_Enable(void) { + MBED_ASSERT(irq != NULL); + irq->enable_irq(); +} + +extern "C" void RF_IRQ_Disable(void) { + MBED_ASSERT(irq != NULL); + irq->disable_irq(); +} + +extern "C" uint8_t RF_isIRQ_Pending(void) { + MBED_ASSERT(rf != NULL); + return !irq_pin->read(); +} + +extern "C" void RF_RST_Set(int state) { + MBED_ASSERT(rst != NULL); + *rst = state; +} + +extern "C" void gXcvrAssertCS_d(void) +{ + MBED_ASSERT(cs != NULL); + *cs = 0; +} + +extern "C" void gXcvrDeassertCS_d(void) +{ + MBED_ASSERT(cs != NULL); + *cs = 1; +} + +extern "C" void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq) +{ + MBED_ASSERT(spi != NULL); + (void)instance; + spi->frequency(freq); +} + +extern "C" void xcvr_spi_transfer(uint32_t instance, + uint8_t * sendBuffer, + uint8_t * receiveBuffer, + size_t transferByteCount) +{ + MBED_ASSERT(spi != NULL); + (void)instance; + volatile uint8_t dummy; + + if( !transferByteCount ) + return; + + if( !sendBuffer && !receiveBuffer ) + return; + + while( transferByteCount-- ) + { + if( sendBuffer ) + { + dummy = *sendBuffer; + sendBuffer++; + } + else + { + dummy = 0xFF; + } + + dummy = spi->write(dummy); + + if( receiveBuffer ) + { + *receiveBuffer = dummy; + receiveBuffer++; + } + } +} + +/*****************************************************************************/ +/*****************************************************************************/ + +static void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +NanostackRfPhyMcr20a::NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_irq) + : _spi(spi_mosi, spi_miso, spi_sclk), _rf_cs(spi_cs), _rf_rst(spi_rst), + _rf_irq(spi_irq), _rf_irq_pin(spi_irq) +{ + // Do nothing +} + +NanostackRfPhyMcr20a::~NanostackRfPhyMcr20a() +{ + // Do nothing +} + +int8_t NanostackRfPhyMcr20a::rf_register() +{ + + rf_if_lock(); + + if (rf != NULL) { + rf_if_unlock(); + error("Multiple registrations of NanostackRfPhyMcr20a not supported"); + return -1; + } + + _pins_set(); + int8_t radio_id = rf_device_register(); + if (radio_id < 0) { + _pins_clear(); + rf = NULL; + } + + rf_if_unlock(); + return radio_id; +} + +void NanostackRfPhyMcr20a::rf_unregister() +{ + rf_if_lock(); + + if (rf != this) { + rf_if_unlock(); + return; + } + + rf_device_unregister(); + rf = NULL; + _pins_clear(); + + rf_if_unlock(); +} + +void NanostackRfPhyMcr20a::get_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + memcpy((void*)mac, (void*)MAC_address, sizeof(MAC_address)); + + rf_if_unlock(); +} + +void NanostackRfPhyMcr20a::set_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL != rf) { + error("NanostackRfPhyAtmel cannot change mac address when running"); + rf_if_unlock(); + return; + } + memcpy((void*)MAC_address, (void*)mac, sizeof(MAC_address)); + + rf_if_unlock(); +} + +void NanostackRfPhyMcr20a::_pins_set() +{ + spi = &_spi; + cs = &_rf_cs; + rst = &_rf_rst; + irq = &_rf_irq; + irq_pin = &_rf_irq_pin; +} + +void NanostackRfPhyMcr20a::_pins_clear() +{ + spi = NULL; + cs = NULL; + rst = NULL; + irq = NULL; + irq_pin = NULL; +}
diff -r d2e25cdf9084 -r ca1b1098c77f easy-connect/mcr20a-rf-driver/source/XcvrSpi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/XcvrSpi.h Wed May 05 14:48:01 2021 +0000 @@ -0,0 +1,89 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file XcvrSpi.h +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __XCVR_SPI_H__ +#define __XCVR_SPI_H__ + + +/***************************************************************************** + * INCLUDED HEADERS * + *---------------------------------------------------------------------------* + * Add to this section all the headers that this module needs to include. * + * Note that it is not a good practice to include header files into header * + * files, so use this section only if there is no other better solution. * + *---------------------------------------------------------------------------* + *****************************************************************************/ + + +/***************************************************************************** + * PUBLIC MACROS * + *---------------------------------------------------------------------------* + * Add to this section all the access macros, registers mappings, bit access * + * macros, masks, flags etc ... + *---------------------------------------------------------------------------* + *****************************************************************************/ +#define gXcvrSpiInstance_c 0 + +/***************************************************************************** + * PUBLIC FUNCTIONS * + *---------------------------------------------------------------------------* + * Add to this section all the global functions prototype preceded (as a * + * good practice) by the keyword 'extern' * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +void RF_RST_Set(int state); +void RF_CS_Set(int state); +void RF_IRQ_Init(void); +void RF_IRQ_Disable(void); +void RF_IRQ_Enable(void); +uint8_t RF_isIRQ_Pending(void); + +void gXcvrAssertCS_d(void); +void gXcvrDeassertCS_d(void); + +void xcvr_spi_init(uint32_t instance); +void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq); +void xcvr_spi_transfer(uint32_t instance, + uint8_t * sendBuffer, + uint8_t * receiveBuffer, + uint32_t transferByteCount); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* __XCVR_SPI_H__ */
diff -r d2e25cdf9084 -r ca1b1098c77f main.cpp --- a/main.cpp Thu Mar 11 13:56:02 2021 +0000 +++ b/main.cpp Wed May 05 14:48:01 2021 +0000 @@ -28,6 +28,784 @@ //STARTED WITH IMPORT FROM HERE https://os.mbed.com/teams/mqtt/code/HelloMQTT/ +#include "mbed.h" +#include "string" + +#define USE_LCD 1// change this to 1 to output messages to LCD instead of serial + +#if USE_LCD +#include "C12832.h" +C12832 lcd(p5, p7, p6, p8, p11); +#define logMessage1 wait(2);lcd.cls();lcd.locate(0,3);lcd.printf +#define logMessage2 wait(2);lcd.cls();lcd.locate(0,15);lcd.printf +#else //use serial printf +#include "C12832.h" +C12832 lcd(p5, p7, p6, p8, p11); +#define logMessage1 pc.printf +#define logMessage2 pc.printf +#endif + +#define MQTTCLIENT_QOS2 1 + +#define CLIENTID "JASON_BERRY_BOT" +//#define USERNAME "testuser" +//#define PASSWORD "TUBNO9VEWTIJZ63R" //thingspeak + +#define USERNAME "token_2F8Fe1gxYIbVpZbr" //beebotte mqtt +#define PASSWORD "token_2F8Fe1gxYIbVpZbr" //beebotte mqtt + +//#define HOSTNAME "54.157.36.210" //thingspeak mqtt broker 15 sec limit on messages +//#define HOSTNAME "5.196.95.208" //mosquitto test broker no limit on messages +#define HOSTNAME "54.221.205.80" //beebotte broker, which can be triggered from iffft webhooks + +///STUDENT CHANGE YOUR NETWORK WIFI PASSWORD ETC HERE +#define NETWORK_ID "HUAWEI P30 Pro" +#define NETWORK_PASSWORD "4f54ed7ab852" + +#include "easy-connect.h" +#include "MQTTNetwork.h" +#include "MQTTmbed.h" +#include "MQTTClient.h" +#include "MMA7660.h" +#include "LM75B.h" +#include "Servo.h" + +//funtions prototypes +int boot_up(void); +void messageArrived(MQTT::MessageData& md); +void build_bots_AI_DI_SI_message(char *buf); +void control_bots_AO_DO_SO_message(char *ser_bt_mqtt_rec_mes); + +//hardware mapping +DigitalIn up(p16); +DigitalIn down(p12); +DigitalOut reset(p30); +DigitalOut led1(LED1); //TEST DO +DigitalOut led2(LED2); //SUPERLOOP +DigitalOut led3(LED3); //MQTT +DigitalOut led4(LED4); //SERIAL,BLUE,PC + + +//Serial pc(USBTX, USBRX); setup in easy connect +MMA7660 MMA(p28, p27); //I2C Accelerometer +LM75B sensor(p28,p27); // Temperature +Serial blue(p13,p14); //tx, rx +Servo s1(p21); +Servo s2(p22); + + +int arrivedcount = 0; //number of message received back from mqtt broker +int version = 88; //version number used for test messages to mqtt + +//topics to subscribe +//////////////////////////////////////////////////////////////////////////////////// +//thingspeak channel as topic +//////////////////////////////////////////////////////////////////////////////////// +//char* publish_topic = "channels/1322442/publish/fields/field1/PUWBQJL3X64GWL2P"; +//char* subscribe_topic = "channels/1322442/subscribe/fields/field1/H0P76513L8Z3N555"; + +//mosquitto mbed sample broker topic +/////////////////////////////////////////////////////////////////////////////////// +//char* publish_topic = "mbed-sample/"; +//char* subscribe_topic = "mbed-sample/"; + +//bee_botte mqtt topic +/////////////////////////////////////////////////////////////////////////////////// + +/////this is where you change your bot id..so maybe change to 011, 011do1, o11do2 etc...011so1 +char id[] = "010"; //bot id + +#define DO1 "010do1" +#define DO2 "010do2" +#define DO3 "010do3" +#define DO4 "010do4" + +#define AO1 "010ao1" +#define AO2 "010ao2" +#define AO3 "010ao3" +#define AO4 "010ao4" + +#define SO1 "010so1" +//////end of changes required /////////////////////////////////////////////////////////////////// + +//beebotte topics +char* publish_topic = "jason/text"; +char* subscribe_topic = "jason/text"; +char mqtt_message_received[255]; +char blue_message_received[255]; +char pc_message_received[255]; + +//outputs variables you can assign these to whatever you want leds,servos +long int ao1=0; +long int ao2=0; +long int ao3=0; +long int ao4=0; + +long int do1=0; +long int do2=0; +long int do3=0; +long int do4=0; + +char so1[20] = ".."; + +//input variables +float ai1=0; +float ai2=0; +float ai3=0; +float ai4=0; + +int di1=0; +int di2=0; +int di3=0; +int di4=0; + +char si1[20] = ".."; + +int client_yielding = false; //set yeilding for message to false at startup + +//100ms timer +Ticker _100ms_ticker; +int timer_100ms_count = 0; + +//this funtion runs every 100ms and increments timer_100ms_count by 1 +/////////////////////////////////////////////////////////////////////// +void _100ms_timer(void) +{ +timer_100ms_count = timer_100ms_count+1; + +//stop overflow 1000 secs +if(timer_100ms_count> 10000) + { + timer_100ms_count = 0; + } +} + +// Simon's Watchdog code from +// http://mbed.org/forum/mbed/topic/508/ +class Watchdog { +public: +// Load timeout value in watchdog timer and enable + void kick(float s) { + LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK + uint32_t clk = SystemCoreClock / 16; // WD has a fixed /4 prescaler, PCLK default is /4 + LPC_WDT->WDTC = s * (float)clk; + LPC_WDT->WDMOD = 0x3; // Enabled and Reset + kick(); + } +// reset the watchdog timer +// by writing this required bit pattern + void kick() { + LPC_WDT->WDFEED = 0xAA; + LPC_WDT->WDFEED = 0x55; + } +}; + +// Setup the watchdog timer +Watchdog wdt; + +/////////////////////////////////////start////////////////////////////////////////// +int main(int argc, char* argv[]) +{ +int rc =0; +int superloop_count = 0; +static int watchdog_count; + +//reset +reset = 0; +wait(1); +reset = 1; +wait(3); + +// turn off all leds +led1=0; +led2=0; +led3=0; +led4=0; + +//set servo to halfway +s1 = 0.5; +s2 = 0.5; + +// On reset, indicate a watchdog reset or a pushbutton reset on LED 4 or 3 +if ((LPC_WDT->WDMOD >> 2) & 1) + { + led4 = 1; + watchdog_count = watchdog_count + 1; //not working + } +else + led3 = 1; + +wait(1); + +// setup a 15 second timeout on watchdog timer hardware +// needs to be longer than worst case main loop exection time +wdt.kick(15.0); + +// set up a function to play every 100 msec +_100ms_ticker.attach(&_100ms_timer, 0.1); + +//serial comms at 115200 bluetooth at 9600 +pc.baud(115200); +blue.baud(9600); + +logMessage1("HelloMQTT: version is:%u Watchdog Resets:%u \r\n", + version,watchdog_count); +blue.printf("HelloMQTT: version is:%u Watchdog Resets:%u \r\n", + version,watchdog_count); + +///calibrate servos +//s1.calibrate(0.001, 45.0); +//s2.calibrate(0.001, 45.0); + +//1.0 test if wifi wired +// 1.0 set up a wifi connection +/////////////////////////////////////////////////////////////////////////////////// +NetworkInterface* network = easy_connect(up); //press joystick at boot up for debug +MQTTNetwork mqttNetwork(network); +MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork); + +if(ip_addr1 != 0) + { + logMessage2("IP address %s\r\n", ip_addr1); + + //2.0 set up a MQTT connection + //////////////////////////////////////////////////////////////////// + //MQTTNetwork mqttNetwork(network); + //MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork); + + char* hostname = HOSTNAME; //"54.157.36.210"; //"103.224.182.253"; // + int port = 1883; + + //logMessage1("Conecting to %s:%d\r\n", hostname, port); + rc = mqttNetwork.connect(hostname, port); + if (rc != 0) + logMessage2("rc from TCP connect is %d\r\n", rc); + + //3.0 connect MQTT client + /////////////////////////////////////////////////////////////////// + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + data.MQTTVersion = 3; + data.clientID.cstring = CLIENTID; //Make sure your robot name here..JASON_BERRY_BOT + data.username.cstring = USERNAME; // token from beebotte or anything for thingsspeak + data.password.cstring = PASSWORD; // this thinspeak mqtt api found in thingspeak profiles + + if ((rc = client.connect(data)) != 0) + { + //logMessage2("rc MQTT connect is %d\r\n", rc); + if (rc == 5) + logMessage2("Bad MQTT password or username\r\n"); + } + else + { + //subscribe and read last message posted to mqtt + //////////////////////////////////////////////// + //logMessage1("start of subscribe..\r\n"); + + if ((rc = client.subscribe(subscribe_topic, MQTT::QOS0, messageArrived)) != 0) + logMessage2("rc MQTT subsc is %d\r\n", rc); + } + } + else + { + logMessage1("wifi unsucessful debug!!!"); + rc = 1; + } +//end of wifi and subscibe +/////////////////////////////////////////////////////////////////////// + +// clear lcd of startup messages +lcd.cls(); + + +//superloop +/////////////////////////////////////////////////////////////////////////////////////////////// +while(1) + { + char mqtt_message_send[200]; + + //update your outputs + ///////////////////////////////////////////// + led1=do1; + // =do2; + // =do3; + // =do4; + + s1 = float(ao1)/255; //a01 goes from 0 255 convert to 0.0 to 1.0 fo s1 + s2 = float(ao2)/255; //a01 goes from 0 255 convert to 0.0 to 1.0 fo s1 + // =a03; + // =ao4; + + // =so1; + + + //update your inputs + ///////////////////////////////////////////// + + //analog inputs + /////////////////////////////////////////////////////////////////////////////// + // ai1: assigned to temperature sensor, ai2: accel_x + if (!sensor.open()) + { + pc.printf("Temperature not device not detected!\n\r"); + } + else + { + ai1 = sensor.temp(); + } + + // ai2: assigned to acceration_x + if (!MMA.testConnection()) + { + pc.printf("accelormeter !! spelling j !!!\n\r"); + } + else + { + ai2 = MMA.x(); + ai3 = MMA.y(); + } + + //ai4 tba + ai4=0; + + //digital inputs + ///////////////////////////////////////////////////////////////////////////////// + // di1: assigned to joystick down(pin 12).. + // note cannot use joystick fire used for bluetoothrx + // ai1: assigned to temperature sensor, ai2: accel_x + di1 = down; + + //di12,3,4 tba + di2=0; + di3=0; + di4=0; + + //string inputs + ///////////////////////////////////////////////////////////////////////////////// + //si1 is a string meesage max 20chars, where boards can send text meesages to mqtt + snprintf(si1,20,"jhello world..xxxx"); + + //end of setting inout and ouput variables //////////////////////////////////// + + + ///////////////////////////////////////////// + //create a message with your ai,di and si + build_bots_AI_DI_SI_message(mqtt_message_send); + + + //logMessage1(".start of publish1 yeild=%u\r\n",client_yielding); + //wait(1); + + //publish message every 500 msecs to mqtt with all ai,di and si data + //also as part of publish read back any messages form mqtt subscribe + + if(timer_100ms_count >= 5 && (rc == 0)) + { + //"kick" to reset watchdog timer and avoid a reset + wdt.kick(); + + + timer_100ms_count = 0; + + //create a meesage with your ai,di and si + //build_bots_AI_DI_SI_message(buf); + + //publish and write to mqtt broker..this will then make its way to BEEBOTTE or thinspeak channel + //////////////////////////////////////////////////////////////////////////////////// + // note can only publish every 15 seconds to thingspeak mqtt, as often as you like to beebottte + MQTT::Message message; + + // QoS 0 + //sprintf(buf, "Hello World! QoS 0 message from app version %f\r\n", version); + //sprintf(buf, "%u",arrivedcount); //version); //MMA.x());//test number is version + + message.qos = MQTT::QOS0; + message.retained = false; //false; + message.dup = false; + message.payload = (void*)mqtt_message_send; + message.payloadlen = strlen(mqtt_message_send)+1; + + //logMessage2("mqtt message: %s :: lenght:%d \r\n", message.payload, message.payloadlen); + rc = client.publish(publish_topic, message); + if (rc != 0) + { + logMessage2("rc MQTT publish error is %d %d\r\n", rc, message.payloadlen); + client.yield(10); + } + else + client.yield(10); + //logMessage2(".end of publish..\r\n"); + } + + + //check if any comms from bluetooth, if so send last mqqt message received + if (blue.readable()) + { + blue.gets(blue_message_received,255); + + //send back response + blue.printf("%s\r\n",mqtt_message_received); + blue.printf("%s\r\n",mqtt_message_send); + + //check bluetooth message for drive commands + control_bots_AO_DO_SO_message(blue_message_received); + + strcpy(mqtt_message_send,blue_message_received); + + //publish and write to mqtt broker..this will then make its way to BEEBOTTE or thinspeak channel + //////////////////////////////////////////////////////////////////////////////////// + // note can only publish every 15 seconds to thingspeak mqtt, as often as you like to beebottte + MQTT::Message message; + + // QoS 0 + //sprintf(buf, "Hello World! QoS 0 message from app version %f\r\n", version); + //sprintf(buf, "%u",arrivedcount); //version); //MMA.x());//test number is version + + message.qos = MQTT::QOS0; + message.retained = false; //false; + message.dup = false; + message.payload = (void*)mqtt_message_send; + message.payloadlen = strlen(mqtt_message_send)+1; + + //logMessage2("mqtt message: %s :: lenght:%d \r\n", message.payload, message.payloadlen); + rc = client.publish(publish_topic, message); + if (rc != 0) + { + logMessage2("rc MQTT publish error is %d %d\r\n", rc, message.payloadlen); + client.yield(10); + } + else + client.yield(10); + //logMessage2(".end of publish..\r\n"); + + + led4 = !led4; + }// end of bluetooth read + + //check if any comms from pc, if so send last mqqt message received + if (pc.readable()) + { + pc.gets(pc_message_received,255); + + //send back response + pc.printf("%s\r\n",mqtt_message_received); + pc.printf("%s\r\n",mqtt_message_send); + + //check pc message for drive commands + control_bots_AO_DO_SO_message(pc_message_received); + + strcpy(mqtt_message_send,pc_message_received); + //drive_command_for_another_bot = 0; + + //publish and write to mqtt broker..this will then make its way to BEEBOTTE or thinspeak channel + //////////////////////////////////////////////////////////////////////////////////// + // note can only publish every 15 seconds to thingspeak mqtt, as often as you like to beebottte + MQTT::Message message; + + // QoS 0 + //sprintf(buf, "Hello World! QoS 0 message from app version %f\r\n", version); + //sprintf(buf, "%u",arrivedcount); //version); //MMA.x());//test number is version + + message.qos = MQTT::QOS0; + message.retained = false; //false; + message.dup = false; + message.payload = (void*)mqtt_message_send; + message.payloadlen = strlen(mqtt_message_send)+1; + + //logMessage2("mqtt message: %s :: lenght:%d \r\n", message.payload, message.payloadlen); + rc = client.publish(publish_topic, message); + if (rc != 0) + { + logMessage2("rc MQTT publish error is %d %d\r\n", rc, message.payloadlen); + client.yield(10); + } + else + client.yield(10); + + //toggle serial message received + led4 = !led4; + }//end of pc read + + //toggle heartbeat every 1 loops, + if(superloop_count > 1) + { + superloop_count = 0; + led2 = !led2; + } + else + superloop_count++; + + //diplay variables locally + /////////////////////////////////////// + lcd.locate(0,1); + //lcd.printf(mqtt_message_received,"Payload %s", (char*)ser_bt_mqtt_rec_mes); + lcd.printf("ao1:%ld,:%ld,:%ld,:%ld do1:%ld,%ld,%ld,%ld",ao1,ao2,ao3,ao4,do1,do2,do3,do4);//printf long int slider + lcd.locate(0,11); + lcd.printf("so1: %20s",so1); + //lcd.printf("do1:%ld, do2:%ld, do3:%ld, do4:%ld ",do1,do2,do3,do4);//printf long int slider + lcd.locate(0,21); + lcd.printf("count:%u ip:%s",arrivedcount,ip_addr1); + + }//end of while(1) + +}//end of main, note: no super loop here runs once at reset + +void control_bots_AO_DO_SO_message(char *ser_bt_mqtt_rec_mes) +/////////////////////////////////////////////////////////////////////////////// +// +// control, message in this format {"data":"do1=0","ispublic": true} +// +// +/////////////////////////////////////////////////////////////////////////////// +{ +char *ptr_str; + + +//010do1: mapped to led1 on mbed +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, DO1)) != NULL ) // "010do1" + { + do1 = strtol(ptr_str+8,NULL,10); + } +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, DO2)) != NULL ) + { + do2 = strtol(ptr_str+8,NULL,10); + } +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, DO3)) != NULL ) + { + do3 = strtol(ptr_str+8,NULL,10); + } +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, DO4)) != NULL ) + { + do4 = strtol(ptr_str+8,NULL,10); + } + + +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, AO1)) != NULL ) + { + ao1 = strtol(ptr_str+8,NULL,10); // convert string to a long integer + } +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, AO2)) != NULL ) + { + ao2 = strtol(ptr_str+8,NULL,10); // convert string to a long integer + } +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, AO3)) != NULL ) + { + ao3 = strtol(ptr_str+8,NULL,10); // convert string to a long integer + } +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, AO4)) != NULL ) + { + ao4 = strtol(ptr_str+8,NULL,10); // convert string to a long integer + } + +if((ptr_str = strstr((char*)ser_bt_mqtt_rec_mes, SO1)) != NULL ) + { + strncpy(so1,ptr_str+8,20); //copy 20 chars from messsage to so1 + } + +} + +void build_bots_AI_DI_SI_message(char *buf) +/////////////////////////////////////////////////////////////////////////////// +// +// +// +/////////////////////////////////////////////////////////////////////////////// +{ +//build message store in buf +sprintf(buf,"{\"data\":\"bot_id:%.3s, %5u\",\"%.3sai1\":%.1f,\"%.3sai2\":%.2f,\"%.3sai3\":%.2f,\"%.3sai4\":%.2f,\"%.3sdi1\":%u,\"%.3sdi2\":%u,\"%.3sdi3\":%u,\"%.3sdi4\":%u,\"%.3ssi1\":%.20s,\"is public\":true}", + id,arrivedcount,id,ai1,id,ai2,id,ai3,id,ai4,id,di1,id,di2,id,di3,id,di4,id,si1); +} + + +/*int boot_up(void) +{ +//set up a wifi connection +////////////////////////// + +//connect to wifi network and display ip address..display in serial +NetworkInterface* network = easy_connect(up); //press joystick at boot up for debug + +if(ip_addr1 != 0) + logMessage2("IP address %s\r\n", ip_addr1); +else + logMessage1("wifi unsucessful debug!!!"); + +//set up a MQTT connection +////////////////////////// + +MQTTNetwork mqttNetwork(network); + +MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork); + +char* hostname = HOSTNAME; //"54.157.36.210"; //"103.224.182.253"; // +int port = 1883; + +logMessage1("Conecting to %s:%d\r\n", hostname, port); + +int rc = mqttNetwork.connect(hostname, port); +if (rc != 0) + logMessage2("rc from TCP connect is %d\r\n", rc); + +//connect to client +/////////////////// +MQTTPacket_connectData data = MQTTPacket_connectData_initializer; +data.MQTTVersion = 3; +data.clientID.cstring = CLIENTID; //can be any name,client just dont connect from two different client +data.username.cstring = USERNAME; //with identical name,client +data.password.cstring = PASSWORD; // this thinspeak mqtt api found in thingspeak profiles + +if ((rc = client.connect(data)) != 0) + logMessage2("rc MQTT connect is %d\r\n", rc); + +//subscribe and read last message posted to mqtt +//////////////////////////////////////////////// +//note data received with handled above in + + +logMessage1("start of subscribe..\r\n"); +if ((rc = client.subscribe(subscribe_topic, MQTT::QOS0, messageArrived)) != 0) + logMessage2("rc MQTT subsc is %d\r\n", rc); + + + return 0; +} + +void mqtt_message_publish(void) +{ + //while (1) + // { + + // if(client_yielding == false) + // { + // logMessage1(".start of yeilding1\r\n"); + // client.yield(100); + // client_yielding = true; + // } + + logMessage1(".start of publish1 yeild=%u\r\n",client_yielding); + //wait(1); + if(up == 0) + { + //publish and write to mqtt broker..this will then make its way to thinspeak channel + //////////////////////////////////////////////////////////////////////////////////// + // note can only publish every 15 seconds to thingspeak mqtt + + MQTT::Message message; + + // QoS 0 + char buf[100]; + //sprintf(buf, "Hello World! QoS 0 message from app version %f\r\n", version); + sprintf(buf, "%u",arrivedcount); //version); //MMA.x());//test number is version + message.qos = MQTT::QOS0; + message.retained = false; //false; + message.dup = false; + message.payload = (void*)buf; + message.payloadlen = strlen(buf)+1; + + + logMessage1(".start of publish2\r\n"); + //wait(1); + + int rc = client.publish(publish_topic , message); + //rc = client.publish(publish_topic , message); + + //wait(4); + //while (arrivedcount < 1) + client.yield(10); + + logMessage2(".end of publish..\r\n"); + } + else + { + client.yield(10); + } + not tested on this set up other fields possible + // QoS 1 + sprintf(buf, "Hello World! QoS 1 message from app version %f\r\n", version); + message.qos = MQTT::QOS1; + message.payloadlen = strlen(buf)+1; + rc = client.publish(publish_topic , message); + while (arrivedcount < 2) + client.yield(100); + + // QoS 2 + sprintf(buf, "Hello World! QoS 2 message from app version %f\r\n", version); + message.qos = MQTT::QOS2; + message.payloadlen = strlen(buf)+1; + rc = client.publish(topic, message); + while (arrivedcount < 3) + client.yield(100); +*/ + // }//end of test while + + //unsubscribe + //////////////////////////////////////// + /* + if ((rc = client.unsubscribe(subscribe_topic)) != 0) + logMessage1("rc from unsubscribe was %d\r\n", rc); + + // and disconnect from client + if ((rc = client.disconnect()) != 0) + logMessage1("rc from disconnect was %d\r\n", rc); + + //disconnect from wifi network + ////////////////////////////// + //this would use a lot of current (mA) up battery life, + //if connecting and disconnecting to wifi each time you sent received a message + + mqttNetwork.disconnect(); + wait(1); + + logMessage1("Version %d: finish %d msgs\r\n", version, arrivedcount); + logMessage2("IP address %s\r\n", ip_addr1); + +} +*/ + +// [FINITE_STATE_MACHINE_STATE] [STATE_SCALE_mod] [STATE_FACE_X_mod]<sp><CR><LF> + +//message received handler +void messageArrived(MQTT::MessageData& md) +{ + MQTT::Message &message = md.message; + //logMessage1("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id); + //logMessage2("Payload %.*s :count %u\r\n", message.payloadlen, (char*)message.payload,arrivedcount); + //blue.printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id); + //blue.printf("Payload %.*s :count %u\r\n", message.payloadlen, (char*)message.payload,arrivedcount); + + + + sprintf(mqtt_message_received,"Payload %.*s :count %u\r\n", message.payloadlen, (char*)message.payload,arrivedcount); + //sprintf(str, "hello %s", "world"); + //snprintf(str, 255, "hello %s", "world") + + ++arrivedcount; + + control_bots_AO_DO_SO_message(mqtt_message_received); + + //if message received from mqtt then do not need to send on outputs + //drive_command_for_another_bot = 0; + + + /* + //led1 =1; led1=0; + if( strstr((char*)message.payload, "led1=1") != NULL ) { + led1=1; + // lcd.cls(); + // lcd.locate(0,3); + // lcd.printf("led 1"); + } + if( strstr((char*)message.payload, "led1=0") != NULL ) { + led1=0; + // lcd.cls(); + // lcd.locate(0,3); + // lcd.printf("led 0"); + } + */ + client_yielding = false; //can yeild for a message again + led3 = !led3; + +} + /////////////////////////////////////////////////////////////////// //IFFT TO THINSPEAK TO THINSPEAK MQTT BROKER TO MBED/ESP8266 CLIENT /////////////////////////////////////////////////////////////////// @@ -47,10 +825,10 @@ // check thingspeak channel to see if 89 is plotted // Step3: FIND MQTT.THINGSPEAK.COM FIXED IP ADDRESS -// Find out fixed ip address of mqtt.thinspeak.com using windons command: tracert mqtt.thinspeak.com -// at time of testing it was 34.231.253.113...doesnt seem to change much :-) but check it. +// Find out fixed ip address of mqtt.thingspeak.com using windons command: tracert mqtt.thingspeak.com +// at time of testing it w as 34.231.253.113...doesnt seem to change much :-) but check it. -// Step4: SETUP A DESK MQTT CLIENT TO TEST THINGSPEAK MQTT BROKER +// Step3.1: SETUP A DESK MQTT CLIENT TO TEST THINGSPEAK MQTT BROKER // Set up a desktop client to test thingspeak mqtt broker, I used MQTT.fx 1.71 from // https://mqttfx.jensd.de/index.php/download. // @@ -60,7 +838,7 @@ // In summary from mathswork, // click in droplist and select new profile, // broker type: select mqtt broker, -// broker address: put in ip address for mqtt.thingspeak.com that you found in step 2, 34.231.253.113 +// broker address: put in ip address for mqtt.thingspeak.com that you found in step 2,54.157.36.210 ..(old 34.231.253.113 // broker port: is 1883, // client id: anything, // username: anything @@ -74,6 +852,8 @@ // next put some number in field below.. then press publish go to thingspeak and check channel for plot update, // put another number in field and publish, again check thinspeak channel..hopefully you see data // +// can also use Mosquitto test broker,test.mosquitto.org [5.196.95.208], topic mbed-sample/ +// // SUBSCRIBE // Click on subscribe tab and enter channels/1322442/subscribe/fields/field1/H0P76513L8Z3N555, // click subscribe @@ -81,8 +861,10 @@ // Go to browser and enter some channel data as step 3, // https://api.thingspeak.com/update?api_key=PUWBQJL3X64GWL2P&field1=67 // you should see message in mqtt panel with data 67 - - +// +// Can also suscribe use mosquitto test broker topic mbed-sample +// +// // Step4: CONFIGURE THE CODE WITH WIFI SETTINGS, DEBUG, PINS ETC // In the mbed_app.json file change as required, I wired esp8266 rx to mbed tx pin9, esp8266 tx to mbed rx pin 10 // "esp8266-tx": { @@ -101,11 +883,16 @@ // // If you want to see all the at commands for esp8266, then select debug true in mbed_app.json file // pretty cool to see all the messages and good obviously for debug. - +// +// step4.1: UPDATE LINE 86 in easy-connect.h with netwrok details as follows, +// in easy connect folder, then mcr20a-rf-driver folder...should see it +// connect_success = esp.connect("eir89748912-2.4G","28eb111b"); +// ---------------------------------------------------------------- +// // Step 5: COMPILE // Compile the code should have no errors // famous last words !!!! - +// // Step 6: WIRE UP ESP8266 TO MBED // Wire up the ESP8266 to mbed see following for pinouts esp8266 h // https://circuits4you.com/2016/12/14/esp8266-pin-diagram/ @@ -169,166 +956,13 @@ ////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#include "mbed.h" - // change this to 1 to output messages to LCD instead of serial -#define USE_LCD 0 - -#if USE_LCD -#include "C12832.h" - -// the actual pins are defined in mbed_app.json and can be overridden per target -C12832 lcd(LCD_MOSI, LCD_SCK, LCD_MISO, LCD_A0, LCD_NCS); - -#define logMessage lcd.cls();lcd.printf - -#else //use serial printf - -#define logMessage pc.printf -Serial pc(USBTX, USBRX); -#endif - -#define MQTTCLIENT_QOS2 1 - -#include "easy-connect.h" -#include "MQTTNetwork.h" -#include "MQTTmbed.h" -#include "MQTTClient.h" - -int arrivedcount = 0; //number of message received back from mqtt broker - -//message received handler -void messageArrived(MQTT::MessageData& md) -{ - MQTT::Message &message = md.message; - logMessage("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id); - logMessage("Payload %.*s\r\n", message.payloadlen, (char*)message.payload); - ++arrivedcount; - -} - - -int main(int argc, char* argv[]) -{ - int version = 111; //version number used for test messages to mqtt - - // mqtt publish and subscribe topics linked to mqtt.thinspeak.com, channel api - // and channel read(suscribe) and write(publish) api...these can be used in any mqtt client conection.. - // for pc testing could use mqtt.fx - // the following mathswork shows how to set up a desktop client to test thinspeak channel - // https://uk.mathworks.com/help/thingspeak/use-desktop-mqtt-client-to-publish-to-a-channel.html#d122e3819 - - char* publish_topic = "channels/1322442/publish/fields/field1/PUWBQJL3X64GWL2P"; - char* subscribe_topic = "channels/1322442/subscribe/fields/field1/H0P76513L8Z3N555"; - - //serial comms at 115200 - pc.baud(115200); - - logMessage("HelloMQTT: version is %u\r\n", version); - - //set up a wifi connection - ////////////////////////// - - //connect to wifi network and display ip address..display in serial - NetworkInterface* network = easy_connect(true); - if (!network) { - return -1; - } - - //set up a MQTT connection - ////////////////////////// - - MQTTNetwork mqttNetwork(network); - - MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork); - - // fixed ip for mqtt broker at mqtt.thingspeak.com found using - // windows command: tracert mqtt.thinspeak.com ..note will change keep an eye on it - char* hostname = "34.231.253.113"; - int port = 1883; - - logMessage("Connecting to %s:%d\r\n", hostname, port); - int rc = mqttNetwork.connect(hostname, port); - if (rc != 0) - logMessage("rc from TCP connect is %d\r\n", rc); +// mqtt publish and subscribe topics linked to mqtt.thinspeak.com, channel api +// and channel read(suscribe) and write(publish) api...these can be used in any mqtt client conection.. +// for pc testing could use mqtt.fx +// the following mathswork shows how to set up a desktop client to test thinspeak channel +// https://uk.mathworks.com/help/thingspeak/use-desktop-mqtt-client-to-publish-to-a-channel.html#d122e3819 - //connect to client - MQTTPacket_connectData data = MQTTPacket_connectData_initializer; - data.MQTTVersion = 3; - data.clientID.cstring = "mbed-sample"; //can be any name,client just dont connect from two different client - data.username.cstring = "testuser"; //with identical name,client - data.password.cstring = "HXPY4BZ5Z0OPAH0W"; // this thinspeak mqtt api found in thingspeak profiles - - if ((rc = client.connect(data)) != 0) - logMessage("rc from MQTT connect is %d\r\n", rc); - - //subscribe and read last message posted to mqtt - //////////////////////////////////////////////// - //note data received with handled above in - if ((rc = client.subscribe(subscribe_topic, MQTT::QOS0, messageArrived)) != 0) - logMessage("rc from MQTT subscribe is %d\r\n", rc); - - - //debug test message can be turned off once happy with functioning - logMessage("test point 1..end of subscribe..\r\n"); - - //publish and write to mqtt broker..this will then make its way to thinspeak channel - //////////////////////////////////////////////////////////////////////////////////// - // note can only publish every 15 seconds to thingspeak mqtt - - MQTT::Message message; - - // QoS 0 - char buf[100]; - //sprintf(buf, "Hello World! QoS 0 message from app version %f\r\n", version); - sprintf(buf, "%u",version);//test number is version - message.qos = MQTT::QOS0; - message.retained = false; //false; - message.dup = false; - message.payload = (void*)buf; - message.payloadlen = strlen(buf)+1; - - logMessage("test point 2..start of publish..\r\n"); - rc = client.publish(publish_topic , message); - while (arrivedcount < 1) - client.yield(100); - logMessage("test point 3...end of publish..\r\n"); - -/* not tested on this set up other fields possible - // QoS 1 - sprintf(buf, "Hello World! QoS 1 message from app version %f\r\n", version); - message.qos = MQTT::QOS1; - message.payloadlen = strlen(buf)+1; - rc = client.publish(publish_topic , message); - while (arrivedcount < 2) - client.yield(100); - - // QoS 2 - sprintf(buf, "Hello World! QoS 2 message from app version %f\r\n", version); - message.qos = MQTT::QOS2; - message.payloadlen = strlen(buf)+1; - rc = client.publish(topic, message); - while (arrivedcount < 3) - client.yield(100); -*/ - - //unsubscribe and disconnect from client - //////////////////////////////////////// - if ((rc = client.unsubscribe(subscribe_topic)) != 0) - logMessage("rc from unsubscribe was %d\r\n", rc); - - if ((rc = client.disconnect()) != 0) - logMessage("rc from disconnect was %d\r\n", rc); - - //disconnect from wifi network - ////////////////////////////// - //this would use a lot of current (mA) up battery life, - //if connecting and disconnecting to wifi each time you sent received a message - - mqttNetwork.disconnect(); - wait(1); - - logMessage("Version %d: finish %d msgs\r\n", version, arrivedcount); - - return 0; - -}//end of main, note: no super loop here runs once at reset +//roborealm send +//{"data":"bot_id:110","010ao1":[MOUSE_X],"010so1":[JASONS_S01],"ispublic":true}<CR><LF> +//roborealm receive +//{"data":"bot_id:[MESSAGE_ID], [MESSAGE_COUNT]","[AI_1_BOT]ai1":[AI_1_VALUE],"[AI_2_BOT]ai2":[AI_2_VALUE],"[AI_3_BOT]ai3":[AI_3_VALUE],"[AI_4_BOT]ai4":[AI_4_VALUE],"[DI_1_BOT]di1":[DI_1_VALUE],"[DI_2_BOT]di2":[DI_2_VALUE],"[DI_3_BOT]di3":[DI_3_VALUE],"[DI_4_BOT]di4":[DI_4_VALUE],"[SI_1_BOT]si1":[SI_1_VALUE], \ No newline at end of file
diff -r d2e25cdf9084 -r ca1b1098c77f mbed_app.json --- a/mbed_app.json Thu Mar 11 13:56:02 2021 +0000 +++ b/mbed_app.json Wed May 05 14:48:01 2021 +0000 @@ -26,7 +26,7 @@ "value": false }, "lcd-mosi": { - "value": "D11", + "value": "D11", "macro_name": "LCD_MOSI" }, "lcd-sck": {