├── README.md ├── drivers ├── at24c.c ├── at24c.h ├── ds1307.c ├── ds1307.h ├── ds3231.c ├── ds3231.h └── license.txt ├── mutex ├── license.txt ├── mutex.c └── mutex.h └── ntp ├── license.txt ├── ntp.c ├── ntp.h └── timezone.c /README.md: -------------------------------------------------------------------------------- 1 | github.com/raburton/esp8266 2 | - 3 | 4 | A collection of things I've written for the ESP8266 Wifi SOC. 5 | 6 | Read on for the contents of this repository. 7 | **Note:** rBoot and esptool2 are now in separate repositories! 8 | 9 | Drivers 10 | - 11 | Drivers for: 12 | * AT24xx series I2C eeproms 13 | * DS1307 real time clock 14 | * DS3231 real time clock 15 | 16 | NTP 17 | - 18 | Simple NTP client for ESP8266 and very simple timezone code example. 19 | 20 | Mutex 21 | - 22 | A mutex for the ESP8266. 23 | -------------------------------------------------------------------------------- /drivers/at24c.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////// 2 | // I2C driver for AT24C series eeproms for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | //////////////////////////////////////////////////// 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "at24c.h" 13 | 14 | // set the current data address, this is the start of the write command 15 | // next either send the data to be written, or start a read instead 16 | // returns true to indicate success 17 | static bool ICACHE_FLASH_ATTR at24c_setAddr(uint16 addr) { 18 | 19 | uint8 loop; 20 | uint8 data[2]; 21 | 22 | // signal i2c start 23 | i2c_master_start(); 24 | 25 | // write i2c address & direction 26 | i2c_master_writeByte((uint8)(AT24C_ADDR << 1)); 27 | if (!i2c_master_checkAck()) { 28 | //uart0_send("i2c error\r\n"); 29 | i2c_master_stop(); 30 | return false; 31 | } 32 | 33 | // write data address 34 | data[0] = (uint8)(((unsigned)addr) >> 8); 35 | data[1] = (uint8)(((unsigned)addr) & 0xff); 36 | for (loop = 0; loop < 2; loop++) { 37 | i2c_master_writeByte(data[loop]); 38 | if (!i2c_master_checkAck()) { 39 | //uart0_send("i2c error\r\n"); 40 | i2c_master_stop(); 41 | return false; 42 | } 43 | } 44 | 45 | return true; 46 | } 47 | 48 | // read from the current position 49 | // returns true to indicate success 50 | bool ICACHE_FLASH_ATTR at24c_readNextBytes(uint8 *data, uint16 len) { 51 | 52 | int loop; 53 | 54 | // signal i2c start 55 | i2c_master_start(); 56 | 57 | // write i2c address & direction 58 | i2c_master_writeByte((uint8)((AT24C_ADDR << 1) | 1)); 59 | if (!i2c_master_checkAck()) { 60 | //uart0_send("i2c error\r\n"); 61 | i2c_master_stop(); 62 | return false; 63 | } 64 | 65 | // read bytes 66 | for (loop = 0; loop < len; loop++) { 67 | data[loop] = i2c_master_readByte(); 68 | // send ack (except after last byte, then we send nack) 69 | if (loop < (len - 1)) i2c_master_send_ack(); else i2c_master_send_nack(); 70 | } 71 | 72 | // signal i2c stop 73 | i2c_master_stop(); 74 | 75 | return true; 76 | } 77 | 78 | // read from anywhere 79 | // sets the address then does a normal read 80 | // returns true to indicate success 81 | bool ICACHE_FLASH_ATTR at24c_readBytes(uint16 addr, uint8 *data, uint16 len) { 82 | // set data address 83 | if (!at24c_setAddr(addr)) return false; 84 | // perform the read 85 | return at24c_readNextBytes(data, len); 86 | } 87 | 88 | // wait for a write operation to complete 89 | // by 'acknowledge polling' 90 | void ICACHE_FLASH_ATTR at24c_writeWait() { 91 | do { 92 | i2c_master_start(); 93 | i2c_master_writeByte((uint8)((AT24C_ADDR << 1) | 1)); 94 | } while (!i2c_master_checkAck()); 95 | i2c_master_stop(); 96 | } 97 | 98 | // write within a page 99 | // note if you try to write past a page boundary the write will 100 | // wrap back to the start of the same page, so you need to know 101 | // how much you're writing and where you're writing it to 102 | // you don't need to start writing at the start of a page, but if you 103 | // start in the middle you'll be able to write less before wrapping 104 | // optionally wait for the eeprom to complete the write 105 | // returns true to indicate success 106 | bool ICACHE_FLASH_ATTR at24c_writeInPage(uint16 addr, uint8* data, uint8 len, bool wait) { 107 | 108 | int loop; 109 | 110 | // set data address (includes i2c setup, 111 | // so no need to call i2c_master_start here) 112 | if (!at24c_setAddr(addr)) return false; 113 | 114 | // send the data 115 | for (loop = 0; loop < len; loop++) { 116 | i2c_master_writeByte(data[loop]); 117 | if (!i2c_master_checkAck()) { 118 | //uart0_send("i2c error\r\n"); 119 | i2c_master_stop(); 120 | return false; 121 | } 122 | } 123 | 124 | // signal i2c stop 125 | i2c_master_stop(); 126 | 127 | // optionally, wait until the eeprom signals the write is finished 128 | if (wait) at24c_writeWait(); 129 | 130 | return true; 131 | } 132 | 133 | // writes across pages 134 | // you do not need to worry about how long your data is or where you 135 | // are writing it as it will be written in multiple parts across 136 | // successive pages, optionally waiting for the last write to complete 137 | // (we always have to wait for any earlier writes to complete) 138 | // note: does not check if you are trying to write past the end of the 139 | // eeprom! 140 | // returns true to indicate success 141 | bool ICACHE_FLASH_ATTR at24c_writeAcrossPages(uint16 addr, uint8* data, uint16 len, bool wait) { 142 | 143 | uint8 wlen; 144 | 145 | // work out number of bytes available in starting page 146 | wlen = AT24C_PAGESIZE - (addr % AT24C_PAGESIZE); 147 | // is that more than we actually need? 148 | if (wlen > len) wlen = len; 149 | 150 | while(wlen > 0) { 151 | // reduce remaining length 152 | len -= wlen; 153 | // write the page 154 | if (!at24c_writeInPage(addr, data, wlen, (len > 0 ? true : wait))) { 155 | return false; 156 | } 157 | // advance the eeprom address and our data pointer 158 | addr += wlen; 159 | data += wlen; 160 | // work out how much to write next time 161 | wlen = (len < AT24C_PAGESIZE ? len : AT24C_PAGESIZE); 162 | } 163 | 164 | return true; 165 | } 166 | 167 | // set an area of eeprom to specified value (like memset) 168 | // optionally wait for completion of last write 169 | bool ICACHE_FLASH_ATTR at24c_setBytes(uint16 addr, uint8 val, uint16 len, bool wait) { 170 | 171 | uint8 wlen; 172 | uint8 data[AT24C_PAGESIZE]; 173 | 174 | // set the temp write buffer to user's choice of value 175 | os_memset(data, val, AT24C_PAGESIZE); 176 | 177 | // work out number of bytes available in starting page 178 | wlen = AT24C_PAGESIZE - (addr % AT24C_PAGESIZE); 179 | // is that more than we actually need? 180 | if (wlen > len) wlen = len; 181 | 182 | while(wlen > 0) { 183 | // reduce remaining length 184 | len -= wlen; 185 | // write the page 186 | if (!at24c_writeInPage(addr, data, wlen, (len > 0 ? true : wait))) { 187 | return false; 188 | } 189 | // advance the eeprom address 190 | addr += wlen; 191 | // work out how much to write next time 192 | wlen = (len < AT24C_PAGESIZE ? len : AT24C_PAGESIZE); 193 | } 194 | 195 | return true; 196 | } 197 | -------------------------------------------------------------------------------- /drivers/at24c.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////// 2 | // I2C driver for AT24C series eeproms for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | //////////////////////////////////////////////////// 7 | 8 | #ifndef __AT24C_H__ 9 | #define __AT24C_H__ 10 | 11 | // should work with all atmel 24c series i2c eeproms up to 512Kb 12 | // the 1Mb model uses a 17 bit address, where the most significant 13 | // bit takes the place of the last bit in the device i2c address 14 | // (so it only has A0-A1 for addressing), this driver will work 15 | // fine on this chip but will only be able to access half of it 16 | // (which half depends on the least significant bit of the address 17 | // specified below) 18 | 19 | // address can be from 0x50-0x57 depending on address pins A0-A2 20 | #define AT24C_ADDR 0x57 21 | #define AT24C_PAGESIZE 0x20 22 | 23 | bool ICACHE_FLASH_ATTR at24c_readBytes(uint16 addr, uint8 *data, uint16 len); 24 | bool ICACHE_FLASH_ATTR at24c_readNextBytes(uint8 *data, uint16 len); 25 | void ICACHE_FLASH_ATTR at24c_writeWait(); 26 | bool ICACHE_FLASH_ATTR at24c_writeInPage(uint16 addr, uint8* data, uint8 len, bool wait); 27 | bool ICACHE_FLASH_ATTR at24c_writeAcrossPages(uint16 addr, uint8* data, uint16 len, bool wait); 28 | bool ICACHE_FLASH_ATTR at24c_setBytes(uint16 addr, uint8 val, uint16 len, bool wait); 29 | 30 | // few convenient defines 31 | #define at24c_readByte(addr, outptr) at24c_readBytes(addr, outptr, 1) 32 | #define at24c_readNextByte(outptr) at24c_readNextBytes(outptr, 1) 33 | #define at24c_writeByte(addr, value) at24c_writeInPage(addr, &(value), 1, true) 34 | #define at24c_zero(addr, len) at24c_setBytes(addr, 0x00, len, true) 35 | #define at24c_erase(addr, len) at24c_setBytes(addr, 0xff, len, true) 36 | 37 | #endif -------------------------------------------------------------------------------- /drivers/ds1307.c: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // I2C driver for DS1307 RTC for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #include 9 | #include 10 | 11 | #include "ds1307.h" 12 | 13 | #include 14 | 15 | // convert normal decimal to binary coded decimal 16 | static uint8 ICACHE_FLASH_ATTR decToBcd(uint8 dec) { 17 | return(((dec / 10) * 16) + (dec % 10)); 18 | } 19 | 20 | // convert binary coded decimal to normal decimal 21 | static uint8 ICACHE_FLASH_ATTR bcdToDec(uint8 bcd) { 22 | return(((bcd / 16) * 10) + (bcd % 16)); 23 | } 24 | 25 | // send a number of bytes to the rtc over i2c 26 | // returns true to indicate success 27 | static bool ICACHE_FLASH_ATTR ds1307_send(uint8 *data, uint8 len) { 28 | 29 | int loop; 30 | 31 | // signal i2c start 32 | i2c_master_start(); 33 | 34 | // write address & direction 35 | i2c_master_writeByte((uint8)(DS1307_ADDR << 1)); 36 | if (!i2c_master_checkAck()) { 37 | //uart0_send("i2c error1\r\n"); 38 | i2c_master_stop(); 39 | return false; 40 | } 41 | 42 | // send the data 43 | for (loop = 0; loop < len; loop++) { 44 | i2c_master_writeByte(data[loop]); 45 | if (!i2c_master_checkAck()) { 46 | //uart0_send("i2c error2\r\n"); 47 | i2c_master_stop(); 48 | return false; 49 | } 50 | } 51 | 52 | // signal i2c stop 53 | i2c_master_stop(); 54 | 55 | return true; 56 | 57 | } 58 | 59 | // read a number of bytes from the rtc over i2c 60 | // returns true to indicate success 61 | static bool ICACHE_FLASH_ATTR ds1307_recv(uint8 *data, uint8 len) { 62 | 63 | int loop; 64 | 65 | // signal i2c start 66 | i2c_master_start(); 67 | 68 | // write address & direction 69 | i2c_master_writeByte((uint8)((DS1307_ADDR << 1) | 1)); 70 | if (!i2c_master_checkAck()) { 71 | //uart0_send("i2c error3\r\n"); 72 | i2c_master_stop(); 73 | return false; 74 | } 75 | 76 | // read bytes 77 | for (loop = 0; loop < len; loop++) { 78 | data[loop] = i2c_master_readByte(); 79 | // send ack (except after last byte, then we send nack) 80 | if (loop < (len - 1)) i2c_master_send_ack(); else i2c_master_send_nack(); 81 | } 82 | 83 | // signal i2c stop 84 | i2c_master_stop(); 85 | 86 | return true; 87 | 88 | } 89 | 90 | // set the time on the rtc 91 | // timezone agnostic, pass whatever you like 92 | // I suggest using GMT and applying timezone and DST when read back 93 | // returns true to indicate success 94 | bool ICACHE_FLASH_ATTR ds1307_setTime(struct tm *time) { 95 | 96 | uint8 data[8]; 97 | 98 | // start register 99 | data[0] = DS1307_ADDR_TIME; 100 | // time/date data 101 | data[1] = decToBcd(time->tm_sec); 102 | data[2] = decToBcd(time->tm_min); 103 | data[3] = decToBcd(time->tm_hour); 104 | data[4] = decToBcd(time->tm_wday + 1); 105 | data[5] = decToBcd(time->tm_mday); 106 | data[6] = decToBcd(time->tm_mon + 1); 107 | data[7] = decToBcd(time->tm_year - 100); 108 | 109 | return ds1307_send(data, 8); 110 | 111 | } 112 | 113 | // get a byte containing just the requested bits 114 | // pass the register address to read, a mask to apply to the register and 115 | // an uint* for the output 116 | // you can test this value directly as true/false for specific bit mask 117 | // of use a mask of 0xff to just return the whole register byte 118 | // returns true to indicate success 119 | bool ICACHE_FLASH_ATTR ds1307_getFlag(uint8 addr, uint8 mask, uint8 *flag) { 120 | uint8 data[1]; 121 | // get register 122 | data[0] = addr; 123 | if (ds1307_send(data, 1) && ds1307_recv(data, 1)) { 124 | // return only requested flag 125 | *flag = (data[0] & mask); 126 | return true; 127 | } 128 | return false; 129 | } 130 | 131 | // set/clear bits in a byte register, or replace the byte altogether 132 | // pass the register address to modify, a byte to replace the existing 133 | // value with or containing the bits to set/clear and one of 134 | // DS1307_SET/DS1307_CLEAR/DS1307_REPLACE 135 | // returns true to indicate success 136 | bool ICACHE_FLASH_ATTR ds1307_setFlag(uint8 addr, uint8 bits, uint8 mode) { 137 | uint8 data[2]; 138 | data[0] = addr; 139 | // get status register 140 | if (ds1307_send(data, 1) && ds1307_recv(data+1, 1)) { 141 | // clear the flag 142 | if (mode == DS1307_REPLACE) data[1] = bits; 143 | else if (mode == DS1307_SET) data[1] |= bits; 144 | else data[1] &= ~bits; 145 | if (ds1307_send(data, 2)) { 146 | return true; 147 | } 148 | } 149 | return false; 150 | } 151 | 152 | // enable the squarewave output 153 | // returns true to indicate success 154 | bool ICACHE_FLASH_ATTR ds1307_enableSquarewave() { 155 | return ds1307_setFlag(DS1307_ADDR_CONTROL, DS1307_CTRL_SQUAREWAVE, DS1307_SET); 156 | } 157 | 158 | // disable the squarewave output 159 | // returns true to indicate success 160 | bool ICACHE_FLASH_ATTR ds1307_disableSquarewave() { 161 | return ds1307_setFlag(DS1307_ADDR_CONTROL, DS1307_CTRL_SQUAREWAVE, DS1307_CLEAR); 162 | } 163 | 164 | // enable and set output level (disabled squarewave) 165 | // returns true to indicate success 166 | bool ICACHE_FLASH_ATTR ds1307_enableOutout(uint8 level) { 167 | uint8 flag = 0; 168 | if (ds1307_getFlag(DS1307_ADDR_CONTROL, 0xff, &flag)) { 169 | // clear squarewave flag (to enable output) and current level 170 | flag &= ~(DS1307_CTRL_SQUAREWAVE | DS1307_OUTPUT_LEVEL_1); 171 | // set the output level 172 | flag |= level; 173 | return ds1307_setFlag(DS1307_ADDR_CONTROL, flag, DS1307_REPLACE); 174 | } 175 | return false; 176 | } 177 | 178 | // set the frequency of the squarewave output (but does not enable it) 179 | // pass DS1307_SQUAREWAVE_RATE_1HZ/DS1307_SQUAREWAVE_RATE_1024HZ/DS1307_SQUAREWAVE_RATE_4096HZ/DS1307_SQUAREWAVE_RATE_8192HZ 180 | // returns true to indicate success 181 | bool ICACHE_FLASH_ATTR ds1307_setSquarewaveFreq(uint8 freq) { 182 | uint8 flag = 0; 183 | if (ds1307_getFlag(DS1307_ADDR_CONTROL, 0xff, &flag)) { 184 | // clear current rate 185 | flag &= ~DS1307_CTRL_SQWAVE_32768HZ; 186 | // set new rate 187 | flag |= freq; 188 | return ds1307_setFlag(DS1307_ADDR_CONTROL, flag, DS1307_REPLACE); 189 | } 190 | return false; 191 | } 192 | 193 | // get the time from the rtc, populates a supplied tm struct 194 | // returns true to indicate success 195 | bool ICACHE_FLASH_ATTR ds1307_getTime(struct tm *time) { 196 | 197 | int loop; 198 | uint8 data[7]; 199 | 200 | // start register address 201 | data[0] = DS1307_ADDR_TIME; 202 | if (!ds1307_send(data, 1)) { 203 | return false; 204 | } 205 | 206 | // read time 207 | if (!ds1307_recv(data, 7)) { 208 | return false; 209 | } 210 | 211 | // convert to unix time structure 212 | time->tm_sec = bcdToDec(data[0]); 213 | time->tm_min = bcdToDec(data[1]); 214 | if (data[2] & DS1307_12HOUR_FLAG) { 215 | // 12h 216 | time->tm_hour = bcdToDec(data[2] & DS1307_12HOUR_MASK); 217 | // pm? 218 | if (data[2] & DS1307_PM_FLAG) time->tm_hour += 12; 219 | } else { 220 | // 24h 221 | time->tm_hour = bcdToDec(data[2]); 222 | } 223 | time->tm_wday = bcdToDec(data[3]) - 1; 224 | time->tm_mday = bcdToDec(data[4]); 225 | time->tm_mon = bcdToDec(data[5]) - 1; 226 | time->tm_year = bcdToDec(data[6]) + 100; 227 | time->tm_isdst = 0; 228 | 229 | // apply a time zone (if you are not using localtime on the rtc or you want to check/apply DST) 230 | //applyTZ(time); 231 | 232 | return true; 233 | 234 | } 235 | -------------------------------------------------------------------------------- /drivers/ds1307.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // I2C driver for DS1307 RTC for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #ifndef __DS1307_H__ 9 | #define __DS1307_H__ 10 | 11 | #include 12 | 13 | #define DS1307_ADDR 0x68 14 | 15 | #define DS1307_CTRL_OUTPUT 0x80 16 | #define DS1307_CTRL_SQUAREWAVE 0x10 17 | #define DS1307_CTRL_SQWAVE_32768HZ 0x03 18 | #define DS1307_CTRL_SQWAVE_8192HZ 0x02 19 | #define DS1307_CTRL_SQWAVE_4096HZ 0x01 20 | #define DS1307_CTRL_SQWAVE_1HZ 0x00 21 | 22 | #define DS1307_OUTPUT_LEVEL_1 0x80 23 | #define DS1307_OUTPUT_LEVEL_0 0x00 24 | 25 | #define DS1307_ADDR_TIME 0x00 26 | #define DS1307_ADDR_CONTROL 0x07 27 | 28 | #define DS1307_SET 0 29 | #define DS1307_CLEAR 1 30 | #define DS1307_REPLACE 2 31 | 32 | #define DS1307_12HOUR_FLAG 0x40 33 | #define DS1307_12HOUR_MASK 0x1f 34 | #define DS1307_PM_FLAG 0x20 35 | 36 | bool ICACHE_FLASH_ATTR ds1307_setTime(struct tm *time); 37 | bool ICACHE_FLASH_ATTR ds1307_getOscillatorStopFlag(); 38 | bool ICACHE_FLASH_ATTR ds1307_clearOscillatorStopFlag(); 39 | bool ICACHE_FLASH_ATTR ds1307_enable32khz(); 40 | bool ICACHE_FLASH_ATTR ds1307_disable32khz(); 41 | bool ICACHE_FLASH_ATTR ds1307_enableSquarewave(); 42 | bool ICACHE_FLASH_ATTR ds1307_disableSquarewave(); 43 | bool ICACHE_FLASH_ATTR ds1307_getTime(struct tm *time); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /drivers/ds3231.c: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // I2C driver for DS3231 RTC for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ds3231.h" 13 | 14 | // convert normal decimal to binary coded decimal 15 | static uint8 ICACHE_FLASH_ATTR decToBcd(uint8 dec) { 16 | return(((dec / 10) * 16) + (dec % 10)); 17 | } 18 | 19 | // convert binary coded decimal to normal decimal 20 | static uint8 ICACHE_FLASH_ATTR bcdToDec(uint8 bcd) { 21 | return(((bcd / 16) * 10) + (bcd % 16)); 22 | } 23 | 24 | // send a number of bytes to the rtc over i2c 25 | // returns true to indicate success 26 | static bool ICACHE_FLASH_ATTR ds3231_send(uint8 *data, uint8 len) { 27 | 28 | int loop; 29 | 30 | // signal i2c start 31 | i2c_master_start(); 32 | 33 | // write address & direction 34 | i2c_master_writeByte((uint8)(DS3231_ADDR << 1)); 35 | if (!i2c_master_checkAck()) { 36 | //uart0_send("i2c error\r\n"); 37 | i2c_master_stop(); 38 | return false; 39 | } 40 | 41 | // send the data 42 | for (loop = 0; loop < len; loop++) { 43 | i2c_master_writeByte(data[loop]); 44 | if (!i2c_master_checkAck()) { 45 | //uart0_send("i2c error\r\n"); 46 | i2c_master_stop(); 47 | return false; 48 | } 49 | } 50 | 51 | // signal i2c stop 52 | i2c_master_stop(); 53 | 54 | return true; 55 | 56 | } 57 | 58 | // read a number of bytes from the rtc over i2c 59 | // returns true to indicate success 60 | static bool ICACHE_FLASH_ATTR ds3231_recv(uint8 *data, uint8 len) { 61 | 62 | int loop; 63 | 64 | // signal i2c start 65 | i2c_master_start(); 66 | 67 | // write address & direction 68 | i2c_master_writeByte((uint8)((DS3231_ADDR << 1) | 1)); 69 | if (!i2c_master_checkAck()) { 70 | //uart0_send("i2c error\r\n"); 71 | i2c_master_stop(); 72 | return false; 73 | } 74 | 75 | // read bytes 76 | for (loop = 0; loop < len; loop++) { 77 | data[loop] = i2c_master_readByte(); 78 | // send ack (except after last byte, then we send nack) 79 | if (loop < (len - 1)) i2c_master_send_ack(); else i2c_master_send_nack(); 80 | } 81 | 82 | // signal i2c stop 83 | i2c_master_stop(); 84 | 85 | return true; 86 | 87 | } 88 | 89 | // set the time on the rtc 90 | // timezone agnostic, pass whatever you like 91 | // I suggest using GMT and applying timezone and DST when read back 92 | // returns true to indicate success 93 | bool ICACHE_FLASH_ATTR ds3231_setTime(struct tm *time) { 94 | 95 | uint8 data[8]; 96 | 97 | // start register 98 | data[0] = DS3231_ADDR_TIME; 99 | // time/date data 100 | data[1] = decToBcd(time->tm_sec); 101 | data[2] = decToBcd(time->tm_min); 102 | data[3] = decToBcd(time->tm_hour); 103 | data[4] = decToBcd(time->tm_wday + 1); 104 | data[5] = decToBcd(time->tm_mday); 105 | data[6] = decToBcd(time->tm_mon + 1); 106 | data[7] = decToBcd(time->tm_year - 100); 107 | 108 | return ds3231_send(data, 8); 109 | 110 | } 111 | 112 | // set alarms 113 | // alarm1 works with seconds, minutes, hours and day of week/month, or fires every second 114 | // alarm2 works with minutes, hours and day of week/month, or fires every minute 115 | // not all combinations are supported, see DS3231_ALARM1_* and DS3231_ALARM2_* defines 116 | // for valid options 117 | // you only need to populate the fields you are using in the tm struct, and you can 118 | // set both alarms at the same time (pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH) 119 | // if only setting one alarm just pass 0 for tm struct and option field for the other alarm 120 | // if using DS3231_ALARM1_EVERY_SECOND/DS3231_ALARM2_EVERY_MIN you can pass 0 for tm stuct 121 | // if you want to enable interrupts for the alarms you need to do that separately 122 | // returns true to indicate success 123 | bool ICACHE_FLASH_ATTR ds3231_setAlarm(uint8 alarms, struct tm *time1, uint8 option1, struct tm *time2, uint8 option2) { 124 | 125 | int i = 0; 126 | uint8 data[8]; 127 | 128 | // start register 129 | data[i++] = (alarms == DS3231_ALARM_2 ? DS3231_ADDR_ALARM2 : DS3231_ADDR_ALARM1); 130 | 131 | // alarm 1 data 132 | if (alarms != DS3231_ALARM_2) { 133 | data[i++] = (option1 >= DS3231_ALARM1_MATCH_SEC ? decToBcd(time1->tm_sec) : DS3231_ALARM_NOTSET); 134 | data[i++] = (option1 >= DS3231_ALARM1_MATCH_SECMIN ? decToBcd(time1->tm_min) : DS3231_ALARM_NOTSET); 135 | data[i++] = (option1 >= DS3231_ALARM1_MATCH_SECMINHOUR ? decToBcd(time1->tm_hour) : DS3231_ALARM_NOTSET); 136 | data[i++] = (option1 == DS3231_ALARM1_MATCH_SECMINHOURDAY ? (decToBcd(time1->tm_wday + 1) & DS3231_ALARM_WDAY) : 137 | (option1 == DS3231_ALARM1_MATCH_SECMINHOURDATE ? decToBcd(time1->tm_mday) : DS3231_ALARM_NOTSET)); 138 | } 139 | 140 | // alarm 2 data 141 | if (alarms != DS3231_ALARM_1) { 142 | data[i++] = (option2 >= DS3231_ALARM2_MATCH_MIN ? decToBcd(time2->tm_min) : DS3231_ALARM_NOTSET); 143 | data[i++] = (option2 >= DS3231_ALARM2_MATCH_MINHOUR ? decToBcd(time2->tm_hour) : DS3231_ALARM_NOTSET); 144 | data[i++] = (option2 == DS3231_ALARM2_MATCH_MINHOURDAY ? (decToBcd(time2->tm_wday + 1) & DS3231_ALARM_WDAY) : 145 | (option2 == DS3231_ALARM2_MATCH_MINHOURDATE ? decToBcd(time2->tm_mday) : DS3231_ALARM_NOTSET)); 146 | } 147 | 148 | return ds3231_send(data, i); 149 | 150 | } 151 | 152 | // get a byte containing just the requested bits 153 | // pass the register address to read, a mask to apply to the register and 154 | // an uint* for the output 155 | // you can test this value directly as true/false for specific bit mask 156 | // of use a mask of 0xff to just return the whole register byte 157 | // returns true to indicate success 158 | bool ICACHE_FLASH_ATTR ds3231_getFlag(uint8 addr, uint8 mask, uint8 *flag) { 159 | uint8 data[1]; 160 | // get register 161 | data[0] = addr; 162 | if (ds3231_send(data, 1) && ds3231_recv(data, 1)) { 163 | // return only requested flag 164 | *flag = (data[0] & mask); 165 | return true; 166 | } 167 | return false; 168 | } 169 | 170 | // set/clear bits in a byte register, or replace the byte altogether 171 | // pass the register address to modify, a byte to replace the existing 172 | // value with or containing the bits to set/clear and one of 173 | // DS3231_SET/DS3231_CLEAR/DS3231_REPLACE 174 | // returns true to indicate success 175 | bool ICACHE_FLASH_ATTR ds3231_setFlag(uint8 addr, uint8 bits, uint8 mode) { 176 | uint8 data[2]; 177 | data[0] = addr; 178 | // get status register 179 | if (ds3231_send(data, 1) && ds3231_recv(data+1, 1)) { 180 | // clear the flag 181 | if (mode == DS3231_REPLACE) data[1] = bits; 182 | else if (mode == DS3231_SET) data[1] |= bits; 183 | else data[1] &= ~bits; 184 | if (ds3231_send(data, 2)) { 185 | return true; 186 | } 187 | } 188 | return false; 189 | } 190 | 191 | // check if oscillator has previously stopped, e.g. no power/battery or disabled 192 | // sets flag to true if there has been a stop 193 | // returns true to indicate success 194 | bool ICACHE_FLASH_ATTR ds3231_getOscillatorStopFlag(bool *flag) { 195 | uint8 f; 196 | if (ds3231_getFlag(DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, &f)) { 197 | *flag = (f ? true : false); 198 | return true; 199 | } 200 | return false; 201 | } 202 | 203 | // clear the oscillator stopped flag 204 | // returns true to indicate success 205 | bool ICACHE_FLASH_ATTR ds3231_clearOscillatorStopFlag() { 206 | return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, DS3231_CLEAR); 207 | } 208 | 209 | // check which alarm(s) have past 210 | // sets alarms to DS3231_ALARM_NONE/DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH 211 | // returns true to indicate success 212 | bool ICACHE_FLASH_ATTR ds3231_getAlarmFlags(uint8 *alarms) { 213 | return ds3231_getFlag(DS3231_ADDR_STATUS, DS3231_ALARM_BOTH, alarms); 214 | } 215 | 216 | // clear alarm past flag(s) 217 | // pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH 218 | // returns true to indicate success 219 | bool ICACHE_FLASH_ATTR ds3231_clearAlarmFlags(uint8 alarms) { 220 | return ds3231_setFlag(DS3231_ADDR_STATUS, alarms, DS3231_CLEAR); 221 | } 222 | 223 | // enable alarm interrupts (and disables squarewave) 224 | // pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH 225 | // if you set only one alarm the status of the other is not changed 226 | // you must also clear any alarm past flag(s) for alarms with 227 | // interrupt enabled, else it will trigger immediately 228 | // returns true to indicate success 229 | bool ICACHE_FLASH_ATTR ds3231_enableAlarmInts(uint8 alarms) { 230 | return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS | alarms, DS3231_SET); 231 | } 232 | 233 | // disable alarm interrupts (does not (re-)enable squarewave) 234 | // pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH 235 | // returns true to indicate success 236 | bool ICACHE_FLASH_ATTR ds3231_disableAlarmInts(uint8 alarms) { 237 | // just disable specific alarm(s) requested 238 | // does not disable alarm interrupts generally (which would enable the squarewave) 239 | return ds3231_setFlag(DS3231_ADDR_CONTROL, alarms, DS3231_CLEAR); 240 | } 241 | 242 | // enable the output of 32khz signal 243 | // returns true to indicate success 244 | bool ICACHE_FLASH_ATTR ds3231_enable32khz() { 245 | return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_SET); 246 | } 247 | 248 | // disable the output of 32khz signal 249 | // returns true to indicate success 250 | bool ICACHE_FLASH_ATTR ds3231_disable32khz() { 251 | return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_CLEAR); 252 | } 253 | 254 | // enable the squarewave output (disables alarm interrupt functionality) 255 | // returns true to indicate success 256 | bool ICACHE_FLASH_ATTR ds3231_enableSquarewave() { 257 | return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_CLEAR); 258 | } 259 | 260 | // disable the squarewave output (which re-enables alarm interrupts, but individual 261 | // alarm interrupts also need to be enabled, if not already, before they will trigger) 262 | // returns true to indicate success 263 | bool ICACHE_FLASH_ATTR ds3231_disableSquarewave() { 264 | return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_SET); 265 | } 266 | 267 | // set the frequency of the squarewave output (but does not enable it) 268 | // pass DS3231_SQUAREWAVE_RATE_1HZ/DS3231_SQUAREWAVE_RATE_1024HZ/DS3231_SQUAREWAVE_RATE_4096HZ/DS3231_SQUAREWAVE_RATE_8192HZ 269 | // returns true to indicate success 270 | bool ICACHE_FLASH_ATTR ds3231_setSquarewaveFreq(uint8 freq) { 271 | uint8 flag = 0; 272 | if (ds3231_getFlag(DS3231_ADDR_CONTROL, 0xff, &flag)) { 273 | // clear current rate 274 | flag &= ~DS3231_CTRL_SQWAVE_8192HZ; 275 | // set new rate 276 | flag |= freq; 277 | return ds3231_setFlag(DS3231_ADDR_CONTROL, flag, DS3231_REPLACE); 278 | } 279 | return false; 280 | } 281 | 282 | // get the temperature as an integer (rounded down) 283 | // returns true to indicate success 284 | bool ICACHE_FLASH_ATTR ds3231_getTempInteger(int8 *temp) { 285 | uint8 data[1]; 286 | data[0] = DS3231_ADDR_TEMP; 287 | // get just the integer part of the temp 288 | if (ds3231_send(data, 1) && ds3231_recv(data, 1)) { 289 | *temp = (signed)data[0]; 290 | return true; 291 | } 292 | return false; 293 | } 294 | 295 | // get the temerapture as a float (in quarter degree increments) 296 | // returns true to indicate success 297 | bool ICACHE_FLASH_ATTR ds3231_getTempFloat(float *temp) { 298 | uint8 data[2]; 299 | data[0] = DS3231_ADDR_TEMP; 300 | // get integer part and quarters of the temp 301 | if (ds3231_send(data, 1) && ds3231_recv(data, 2)) { 302 | *temp = ((signed)data[0]) + (((unsigned)(data[1]) >> 6) * 0.25); 303 | return true; 304 | } 305 | return false; 306 | } 307 | 308 | // get the time from the rtc, populates a supplied tm struct 309 | // returns true to indicate success 310 | bool ICACHE_FLASH_ATTR ds3231_getTime(struct tm *time) { 311 | 312 | int loop; 313 | uint8 data[7]; 314 | 315 | // start register address 316 | data[0] = DS3231_ADDR_TIME; 317 | if (!ds3231_send(data, 1)) { 318 | return false; 319 | } 320 | 321 | // read time 322 | if (!ds3231_recv(data, 7)) { 323 | return false; 324 | } 325 | 326 | // convert to unix time structure 327 | time->tm_sec = bcdToDec(data[0]); 328 | time->tm_min = bcdToDec(data[1]); 329 | if (data[2] & DS3231_12HOUR_FLAG) { 330 | // 12h 331 | time->tm_hour = bcdToDec(data[2] & DS3231_12HOUR_MASK); 332 | // pm? 333 | if (data[2] & DS3231_PM_FLAG) time->tm_hour += 12; 334 | } else { 335 | // 24h 336 | time->tm_hour = bcdToDec(data[2]); 337 | } 338 | time->tm_wday = bcdToDec(data[3]) - 1; 339 | time->tm_mday = bcdToDec(data[4]); 340 | time->tm_mon = bcdToDec(data[5] & DS3231_MONTH_MASK) - 1; 341 | time->tm_year = bcdToDec(data[6]) + 100; 342 | time->tm_isdst = 0; 343 | 344 | // apply a time zone (if you are not using localtime on the rtc or you want to check/apply DST) 345 | //applyTZ(time); 346 | 347 | return true; 348 | 349 | } 350 | -------------------------------------------------------------------------------- /drivers/ds3231.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // I2C driver for DS3231 RTC for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #ifndef __DS3231_H__ 9 | #define __DS3231_H__ 10 | 11 | #include 12 | 13 | #define DS3231_ADDR 0x68 14 | 15 | #define DS3231_STAT_OSCILLATOR 0x80 16 | #define DS3231_STAT_32KHZ 0x08 17 | #define DS3231_STAT_BUSY 0x04 18 | #define DS3231_STAT_ALARM_2 0x02 19 | #define DS3231_STAT_ALARM_1 0x01 20 | 21 | #define DS3231_CTRL_OSCILLATOR 0x80 22 | #define DS3231_CTRL_SQUAREWAVE_BB 0x40 23 | #define DS3231_CTRL_TEMPCONV 0x20 24 | #define DS3231_CTRL_SQWAVE_4096HZ 0x10 25 | #define DS3231_CTRL_SQWAVE_1024HZ 0x08 26 | #define DS3231_CTRL_SQWAVE_8192HZ 0x18 27 | #define DS3231_CTRL_SQWAVE_1HZ 0x00 28 | #define DS3231_CTRL_ALARM_INTS 0x04 29 | #define DS3231_CTRL_ALARM2_INT 0x02 30 | #define DS3231_CTRL_ALARM1_INT 0x01 31 | 32 | #define DS3231_ALARM_NONE 0 33 | #define DS3231_ALARM_1 1 34 | #define DS3231_ALARM_2 2 35 | #define DS3231_ALARM_BOTH 3 36 | 37 | #define DS3231_ALARM1_EVERY_SECOND 0 38 | #define DS3231_ALARM1_MATCH_SEC 1 39 | #define DS3231_ALARM1_MATCH_SECMIN 2 40 | #define DS3231_ALARM1_MATCH_SECMINHOUR 3 41 | #define DS3231_ALARM1_MATCH_SECMINHOURDAY 4 42 | #define DS3231_ALARM1_MATCH_SECMINHOURDATE 5 43 | 44 | #define DS3231_ALARM2_EVERY_MIN 0 45 | #define DS3231_ALARM2_MATCH_MIN 1 46 | #define DS3231_ALARM2_MATCH_MINHOUR 2 47 | #define DS3231_ALARM2_MATCH_MINHOURDAY 3 48 | #define DS3231_ALARM2_MATCH_MINHOURDATE 4 49 | 50 | #define DS3231_ALARM_WDAY 0x40 51 | #define DS3231_ALARM_NOTSET 0x80 52 | 53 | #define DS3231_ADDR_TIME 0x00 54 | #define DS3231_ADDR_ALARM1 0x07 55 | #define DS3231_ADDR_ALARM2 0x0b 56 | #define DS3231_ADDR_CONTROL 0x0e 57 | #define DS3231_ADDR_STATUS 0x0f 58 | #define DS3231_ADDR_AGING 0x10 59 | #define DS3231_ADDR_TEMP 0x11 60 | 61 | #define DS3231_SET 0 62 | #define DS3231_CLEAR 1 63 | #define DS3231_REPLACE 2 64 | 65 | #define DS3231_12HOUR_FLAG 0x40 66 | #define DS3231_12HOUR_MASK 0x1f 67 | #define DS3231_PM_FLAG 0x20 68 | #define DS3231_MONTH_MASK 0x1f 69 | 70 | bool ICACHE_FLASH_ATTR ds3231_setTime(struct tm *time); 71 | bool ICACHE_FLASH_ATTR ds3231_setAlarm(uint8 alarms, struct tm *time1, uint8 option1, struct tm *time2, uint8 option2); 72 | bool ICACHE_FLASH_ATTR ds3231_getOscillatorStopFlag(bool *flag); 73 | bool ICACHE_FLASH_ATTR ds3231_clearOscillatorStopFlag(); 74 | bool ICACHE_FLASH_ATTR ds3231_getAlarmFlags(uint8 *alarms); 75 | bool ICACHE_FLASH_ATTR ds3231_clearAlarmFlags(uint8 alarm); 76 | bool ICACHE_FLASH_ATTR ds3231_enableAlarmInts(uint8 alarms); 77 | bool ICACHE_FLASH_ATTR ds3231_disableAlarmInts(uint8 alarms); 78 | bool ICACHE_FLASH_ATTR ds3231_enable32khz(); 79 | bool ICACHE_FLASH_ATTR ds3231_disable32khz(); 80 | bool ICACHE_FLASH_ATTR ds3231_enableSquarewave(); 81 | bool ICACHE_FLASH_ATTR ds3231_disableSquarewave(); 82 | bool ICACHE_FLASH_ATTR ds3231_setSquarewaveFreq(uint8 freq); 83 | bool ICACHE_FLASH_ATTR ds3231_getTempInteger(int8 *temp); 84 | bool ICACHE_FLASH_ATTR ds3231_getTempFloat(float *temp); 85 | bool ICACHE_FLASH_ATTR ds3231_getTime(struct tm *time); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /drivers/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /mutex/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /mutex/mutex.c: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // Mutex support for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #include "mutex.h" 9 | 10 | // setup a new mutex 11 | void ICACHE_FLASH_ATTR CreateMutux(mutex_t *mutex) { 12 | *mutex = 1; 13 | } 14 | 15 | // try to get a mutex 16 | // returns true if successful, false if mutex not free 17 | // as the esp8266 doesn't support the atomic S32C1I instruction 18 | // we have to make the code uninterruptable to produce the 19 | // same overall effect 20 | bool ICACHE_FLASH_ATTR GetMutex(mutex_t *mutex) { 21 | 22 | int iOld = 1, iNew = 0; 23 | 24 | asm volatile ( 25 | "rsil a15, 1\n" // read and set interrupt level to 1 26 | "l32i %0, %1, 0\n" // load value of mutex 27 | "bne %0, %2, 1f\n" // compare with iOld, branch if not equal 28 | "s32i %3, %1, 0\n" // store iNew in mutex 29 | "1:\n" // branch target 30 | "wsr.ps a15\n" // restore program state 31 | "rsync\n" 32 | : "=&r" (iOld) 33 | : "r" (mutex), "r" (iOld), "r" (iNew) 34 | : "a15", "memory" 35 | ); 36 | 37 | return (bool)iOld; 38 | } 39 | 40 | // release a mutex 41 | void ICACHE_FLASH_ATTR ReleaseMutex(mutex_t *mutex) { 42 | *mutex = 1; 43 | } 44 | -------------------------------------------------------------------------------- /mutex/mutex.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // Mutex support for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #ifndef __MUTEX_H__ 9 | #define __MUTEX_H__ 10 | 11 | #include 12 | 13 | typedef int32 mutex_t; 14 | 15 | void ICACHE_FLASH_ATTR CreateMutux(mutex_t *mutex); 16 | bool ICACHE_FLASH_ATTR GetMutex(mutex_t *mutex); 17 | void ICACHE_FLASH_ATTR ReleaseMutex(mutex_t *mutex); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ntp/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ntp/ntp.c: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // Simple NTP client for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "include\ntp.h" 16 | 17 | // list of major public servers http://tf.nist.gov/tf-cgi/servers.cgi 18 | uint8 ntp_server[] = {131, 107, 13, 100}; // microsoft 19 | 20 | static os_timer_t ntp_timeout; 21 | static struct espconn *pCon = 0; 22 | 23 | static void ICACHE_FLASH_ATTR ntp_udp_timeout(void *arg) { 24 | 25 | os_timer_disarm(&ntp_timeout); 26 | uart0_tx_buffer("ntp timout\r\n", 12); 27 | 28 | // clean up connection 29 | if (pCon) { 30 | espconn_delete(pCon); 31 | os_free(pCon->proto.udp); 32 | os_free(pCon); 33 | pCon = 0; 34 | } 35 | } 36 | 37 | static void ICACHE_FLASH_ATTR ntp_udp_recv(void *arg, char *pdata, unsigned short len) { 38 | 39 | struct tm *dt; 40 | time_t timestamp; 41 | ntp_t *ntp; 42 | 43 | os_timer_disarm(&ntp_timeout); 44 | 45 | // extract ntp time 46 | ntp = (ntp_t*)pdata; 47 | timestamp = ntp->trans_time[0] << 24 | ntp->trans_time[1] << 16 |ntp->trans_time[2] << 8 | ntp->trans_time[3]; 48 | // convert to unix time 49 | timestamp -= 2208988800UL; 50 | // create tm struct 51 | dt = gmtime(×tamp); 52 | 53 | // do something with it, like setting an rtc 54 | //ds1307_setTime(dt); 55 | // or just print it out 56 | char timestr[11]; 57 | os_sprintf(timestr, "%02d:%02d:%02d\r\n", dt->tm_hour, dt->tm_min, dt->tm_sec); 58 | uart0_tx_buffer(timestr, 10); 59 | 60 | // clean up connection 61 | if (pCon) { 62 | espconn_delete(pCon); 63 | os_free(pCon->proto.udp); 64 | os_free(pCon); 65 | pCon = 0; 66 | } 67 | } 68 | 69 | void ICACHE_FLASH_ATTR ntp_get_time() { 70 | 71 | ntp_t ntp; 72 | 73 | // set up the udp "connection" 74 | pCon = (struct espconn*)os_zalloc(sizeof(struct espconn)); 75 | pCon->type = ESPCONN_UDP; 76 | pCon->state = ESPCONN_NONE; 77 | pCon->proto.udp = (esp_udp*)os_zalloc(sizeof(esp_udp)); 78 | pCon->proto.udp->local_port = espconn_port(); 79 | pCon->proto.udp->remote_port = 123; 80 | os_memcpy(pCon->proto.udp->remote_ip, ntp_server, 4); 81 | 82 | // create a really simple ntp request packet 83 | os_memset(&ntp, 0, sizeof(ntp_t)); 84 | ntp.options = 0b00100011; // leap = 0, version = 4, mode = 3 (client) 85 | 86 | // set timeout timer 87 | os_timer_disarm(&ntp_timeout); 88 | os_timer_setfn(&ntp_timeout, (os_timer_func_t*)ntp_udp_timeout, pCon); 89 | os_timer_arm(&ntp_timeout, NTP_TIMEOUT_MS, 0); 90 | 91 | // send the ntp request 92 | espconn_create(pCon); 93 | espconn_regist_recvcb(pCon, ntp_udp_recv); 94 | espconn_sent(pCon, (uint8*)&ntp, sizeof(ntp_t)); 95 | } 96 | -------------------------------------------------------------------------------- /ntp/ntp.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // Simple NTP client for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | #ifndef __NTP_H__ 9 | #define __NTP_H__ 10 | 11 | #define NTP_TIMEOUT_MS 5000 12 | 13 | typedef struct { 14 | uint8 options; 15 | uint8 stratum; 16 | uint8 poll; 17 | uint8 precision; 18 | uint32 root_delay; 19 | uint32 root_disp; 20 | uint32 ref_id; 21 | uint8 ref_time[8]; 22 | uint8 orig_time[8]; 23 | uint8 recv_time[8]; 24 | uint8 trans_time[8]; 25 | } ntp_t; 26 | 27 | void ICACHE_FLASH_ATTR ntp_get_time(); 28 | 29 | #endif -------------------------------------------------------------------------------- /ntp/timezone.c: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // Simple timezone example for ESP8266. 3 | // Copyright 2015 Richard A Burton 4 | // richardaburton@gmail.com 5 | // See license.txt for license terms. 6 | ////////////////////////////////////////////////// 7 | 8 | // custom function to apply a timezone to the supplied tm struct 9 | // hard coded rules 10 | static void ICACHE_FLASH_ATTR applyTZ(struct tm *time) { 11 | 12 | bool dst = false; 13 | 14 | // apply base timezone offset 15 | //time->tm_hour += 1; // e.g. central europe 16 | 17 | // call mktime to fix up (needed if applying offset has rolled the date back/forward a day) 18 | // also sets yday and fixes wday (if it was wrong from the rtc) 19 | mktime(time); 20 | 21 | // work out if we should apply dst, modify according to your local rules 22 | if (time->tm_mon < 2 || time->tm_mon > 9) { 23 | // these months are completely out of DST 24 | } else if (time->tm_mon > 2 && time->tm_mon < 9) { 25 | // these months are completely in DST 26 | dst = true; 27 | } else { 28 | // else we must be in one of the change months 29 | // work out when the last sunday was (could be today) 30 | int previousSunday = time->tm_mday - time->tm_wday; 31 | if (time->tm_mon == 2) { // march 32 | // was last sunday (which could be today) the last sunday in march 33 | if (previousSunday >= 25) { 34 | // are we actually on the last sunday today 35 | if (time->tm_wday == 0) { 36 | // if so are we at/past 2am gmt 37 | int s = (time->tm_hour * 3600) + (time->tm_min * 60) + time->tm_sec; 38 | if (s >= 7200) dst = true; 39 | } else { 40 | dst = true; 41 | } 42 | } 43 | } else if (time->tm_mon == 9) { 44 | // was last sunday (which could be today) the last sunday in october 45 | if (previousSunday >= 25) { 46 | // we have reached/passed it, so is it today? 47 | if (time->tm_wday == 0) { 48 | // change day, so are we before 1am gmt (2am localtime) 49 | int s = (time->tm_hour * 3600) + (time->tm_min * 60) + time->tm_sec; 50 | if (s < 3600) dst = true; 51 | } 52 | } else { 53 | // not reached the last sunday yet 54 | dst = true; 55 | } 56 | } 57 | } 58 | 59 | if (dst) { 60 | // add the dst hour 61 | time->tm_hour += 1; 62 | // mktime will fix up the time/date if adding an hour has taken us to the next day 63 | mktime(time); 64 | // don't rely on isdst returned by mktime, it doesn't know about timezones and tends to reset this to 0 65 | time->tm_isdst = 1; 66 | } else { 67 | time->tm_isdst = 0; 68 | } 69 | 70 | } 71 | --------------------------------------------------------------------------------