/* SCKBase.cpp Supports core and data management functions (Power, WiFi, SD storage, RTClock and EEPROM storage) - Modules supported: - WIFI (Microchip RN131 (WiFly)) - RTC (DS1339U and DS1307Z) - EEPROM (24LC256) - POWER MANAGEMENT IC's */ #include "Constants.h" #include "SCKBase.h" #include #include #define debugBASE false void SCKBase::begin() { Wire.begin(); TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; Serial.begin(115200); Serial1.begin(9600); pinMode(IO0, OUTPUT); //VH_MICS5525 pinMode(IO1, OUTPUT); //VH_MICS2710 pinMode(IO2, OUTPUT); //MICS2710_HIGH_IMPEDANCE pinMode(AWAKE, OUTPUT); pinMode(MOSI, OUTPUT); pinMode(SCK, OUTPUT); pinMode(FACTORY, OUTPUT); pinMode(CONTROL, INPUT); digitalWrite(AWAKE, LOW); digitalWrite(FACTORY, LOW); } void SCKBase::config(){ if (!compareData(__TIME__, readData(EE_ADDR_TIME_VERSION, 0, INTERNAL))) { digitalWrite(AWAKE, HIGH); for(uint16_t i=0; i<(DEFAULT_ADDR_ANTENNA + 160); i++) EEPROM.write(i, 0x00); // Memory erasing writeData(EE_ADDR_TIME_VERSION, 0, __TIME__, INTERNAL); writeData(EE_ADDR_SENSOR_MODE, DEFAULT_MODE_SENSOR, INTERNAL); writeData(EE_ADDR_TIME_UPDATE, DEFAULT_TIME_UPDATE, INTERNAL); writeData(EE_ADDR_NUMBER_UPDATES, DEFAULT_MIN_UPDATES, INTERNAL); writeData(EE_ADDR_MAC, 0, MAC(), INTERNAL); #if (networks > 0) for(byte i=0; iRES) data=RES; Wire.beginTransmission(deviceaddress); address=(address<<4)|bitRead(data, 8) ; Wire.write(address); Wire.write(lowByte(data)); Wire.endTransmission(); delay(4); } int SCKBase::readMCP(int deviceaddress, uint16_t address ) { byte rdata = 0xFF; int data = 0x0000; Wire.beginTransmission(deviceaddress); address=(address<<4)|B00001100; Wire.write(address); Wire.endTransmission(); Wire.requestFrom(deviceaddress,2); unsigned long time = millis(); while (!Wire.available()) if ((millis() - time)>500) return 0x00; rdata = Wire.read(); data=rdata<<8; while (!Wire.available()); rdata = Wire.read(); data=data|rdata; return data; } #if F_CPU == 8000000 #define MCP3 0x2D // Direction of the mcp3 Ajust the battary charge float SCKBase::readCharge() { float resistor = kr*readMCP(MCP3, 0x00)/1000; float current = 1000./(1+((resistor * 10)/(resistor + 10))); #if debugBASE Serial.print("Resistor : "); Serial.print(resistor); Serial.print(" kOhm, "); Serial.print("Current : "); Serial.print(current); Serial.println(" mA"); #endif return(current); } void SCKBase::writeCharge(int current) { if (current < 100) current = 100; else if (current > 1000) current = 1000; float Rp = (1000./current)-1; float resistor = Rp*10/(10-Rp); writeMCP(MCP3, 0x00, (uint8_t)(resistor*1000/kr)); #if debugBASE Serial.print("Rc : "); Serial.print(Rp + 2); Serial.print(" kOhm, "); Serial.print("Rpot : "); Serial.print(resistor); Serial.print(" kOhm, "); Serial.print("Current : "); Serial.print(current); Serial.println(" mA"); #endif } #endif void SCKBase::writeEEPROM(uint16_t eeaddress, uint8_t data) { uint8_t retry = 0; while ((readEEPROM(eeaddress)!=data)&&(retry<10)) { Wire.beginTransmission(E2PROM); Wire.write((byte)(eeaddress >> 8)); // MSB Wire.write((byte)(eeaddress & 0xFF)); // LSB Wire.write(data); Wire.endTransmission(); delay(6); retry++; } } byte SCKBase::readEEPROM(uint16_t eeaddress) { byte rdata = 0xFF; Wire.beginTransmission(E2PROM); Wire.write((byte)(eeaddress >> 8)); // MSB Wire.write((byte)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(E2PROM,1); while (!Wire.available()); rdata = Wire.read(); return rdata; } void SCKBase::writeData(uint32_t eeaddress, long data, uint8_t location) { for (int i =0; i<4; i++) { if (location == EXTERNAL) writeEEPROM(eeaddress + (3 -i) , data>>(i*8)); else EEPROM.write(eeaddress + (3 -i), data>>(i*8)); } } void SCKBase::writeData(uint32_t eeaddress, uint16_t pos, char* text, uint8_t location) { uint16_t eeaddressfree = eeaddress + buffer_length * pos; if (location == EXTERNAL) { for (uint16_t i = eeaddressfree; i< (eeaddressfree + buffer_length); i++) writeEEPROM(i, 0x00); for (uint16_t i = eeaddressfree; text[i - eeaddressfree]!= 0x00; i++) writeEEPROM(i, text[i - eeaddressfree]); } else { for (uint16_t i = eeaddressfree; i< (eeaddressfree + buffer_length); i++) EEPROM.write(i, 0x00); for (uint16_t i = eeaddressfree; text[i - eeaddressfree]!= 0x00; i++) { if (eeaddressfree>=DEFAULT_ADDR_SSID) if (text[i - eeaddressfree]==' ') text[i - eeaddressfree]='$'; EEPROM.write(i, text[i - eeaddressfree]); } } } uint32_t SCKBase::readData(uint16_t eeaddress, uint8_t location) { uint32_t data = 0; for (int i =0; i<4; i++) { if (location == EXTERNAL) data = data + (uint32_t)((uint32_t)readEEPROM(eeaddress + i)<<((3-i)*8)); else data = data + (uint32_t)((uint32_t)EEPROM.read(eeaddress + i)<<((3-i)*8)); } return data; } char* SCKBase::readData(uint16_t eeaddress, uint16_t pos, uint8_t location) { eeaddress = eeaddress + buffer_length * pos; uint16_t i; if (location == EXTERNAL) { uint8_t temp = readEEPROM(eeaddress); for ( i = eeaddress; ((temp!= 0x00)&&(temp<0x7E)&&(temp>0x1F)&&((i - eeaddress)0x1F)&&((i - eeaddress)500) return false; Wire.read(); return true; } boolean SCKBase::RTCadjust(char *time) { byte rtc[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; byte count = 0x00; byte data_count=0; while (time[count]!=0x00) { if(time[count] == '-') data_count++; else if(time[count] == ' ') data_count++; else if(time[count] == ':') data_count++; else if ((time[count] >= '0')&&(time[count] <= '9')) { rtc[data_count] =(rtc[data_count]<<4)|(0x0F&time[count]); } else break; count++; } if (data_count == 5) { #if F_CPU == 8000000 Wire.beginTransmission(RTC_ADDRESS); Wire.write((int)0); Wire.write(rtc[5]); Wire.write(rtc[4]); Wire.write(rtc[3]); Wire.write(0x00); Wire.write(rtc[2]); Wire.write(rtc[1]); Wire.write(rtc[0]); Wire.endTransmission(); delay(4); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); //Address Wire.write(0x00); //Value Wire.endTransmission(); #else Wire.beginTransmission(RTC_ADDRESS); Wire.write((int)0); Wire.write(rtc[5]); Wire.write(rtc[4]); Wire.write(rtc[3]); Wire.write(0x00); Wire.write(rtc[2]); Wire.write(rtc[1]); Wire.write(rtc[0]); Wire.write((int)0); Wire.endTransmission(); return true; #endif return true; } return false; } boolean SCKBase::RTCtime(char *time) { Wire.beginTransmission(RTC_ADDRESS); Wire.write((int)0); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 7); uint8_t seconds = (Wire.read() & 0x7F); uint8_t minutes = Wire.read(); uint8_t hours = Wire.read(); Wire.read(); uint8_t day = Wire.read(); uint8_t month = Wire.read(); uint8_t year = Wire.read(); time[0] = '2'; time[1] = '0'; time[2] = (year>>4) + '0'; time[3] = (year&0x0F) + '0'; time[4] = '-'; time[5] = (month>>4) + '0'; time[6] = (month&0x0F) + '0'; time[7] = '-'; time[8] = (day>>4) + '0'; time[9] = (day&0x0F) + '0'; time[10] = ' '; time[11] = (hours>>4) + '0'; time[12] = (hours&0x0F) + '0'; time[13] = ':'; time[14] = (minutes>>4) + '0'; time[15] = (minutes&0x0F) + '0'; time[16] = ':'; time[17] = (seconds>>4) + '0'; time[18] = (seconds&0x0F) + '0'; time[19] = 0x00; return true; } uint16_t SCKBase::getPanel(float Vref){ #if F_CPU == 8000000 uint16_t value = 11*average(PANEL)*Vref/1023.; if (value > 500) value = value + 120; //Voltage protection diode else value = 0; #else uint16_t value = 3*average(PANEL)*Vref/1023.; if (value > 500) value = value + 750; //Voltage protection diode else value = 0; #endif #if debugBASE Serial.print("Panel = "); Serial.print(value); Serial.println(" mV"); #endif return value; } uint16_t SCKBase::getBattery(float Vref) { uint16_t temp = average(BAT); #if F_CPU == 8000000 float voltage = Vref*temp/1023.; voltage = voltage + (voltage/180)*100; #else float voltage = Vref*temp/1023.; #endif temp = map(voltage, VAL_MIN_BATTERY, VAL_MAX_BATTERY, 0, 1000); if (temp>1000) temp=1000; if (temp<0) temp=0; #if debugBASE Serial.print("Vbat: "); Serial.print(voltage); Serial.print(" mV, "); Serial.print("Battery level: "); Serial.print(temp/10.); Serial.println(" %"); #endif return temp; } boolean SCKBase::findInResponse(const char *toMatch, unsigned int timeOut = 1000) { int byteRead; unsigned long timeOutTarget; // in milliseconds for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping while (!Serial1.available()) { // Wait, with optional time out. if (timeOut > 0) { if (millis() > timeOutTarget) { return false; } } delay(1); // This seems to improve reliability slightly } byteRead = Serial1.read(); //Serial.print((char)byteRead); delay(1); // Removing logging may affect timing slightly if (byteRead != toMatch[offset]) { offset = 0; // Ignore character read if it's not a match for the start of the string if (byteRead != toMatch[offset]) { offset = -1; } continue; } } return true; } void SCKBase::skipRemainderOfResponse(unsigned int timeOut) { unsigned long time = millis(); while (((millis()-time) // Specify the channel to create network sendCommand(F("set wlan ssid "), true); // Set up network broadcast SSID sendCommand(ssid); buffer[6] = 0x00; sendCommand(F("set opt device_id "), true); // Set up network broadcast SSID sendCommand(ssid); sendCommand(F("set ip dhcp 4")); // Enable DHCP server sendCommand(F("set ip address 1.2.3.4")); // Specify the IP address sendCommand(F("set ip net 255.255.255.0")); // Specify the subnet mask sendCommand(F("set ip gateway 1.2.3.4")); // Specify the gateway sendCommand(F("save"), false, "Storing in config"); // Store settings sendCommand(F("reboot"), false, "*READY*"); // Reboot the module in AP mode } } boolean SCKBase::ready() { if(!enterCommandMode()) { repair(); return(false); } else { Serial1.println(F("join")); if (findInResponse("Associated!", 8000)) { skipRemainderOfResponse(3000); exitCommandMode(); return(true); } } } boolean connected = false; boolean SCKBase::open(const char *addr, int port) { if (connected) { close(); } if (enterCommandMode()) { sendCommand(F("open "), true); sendCommand(addr, true); Serial1.print(F(" ")); Serial1.print(port); if (sendCommand("", false, "*OPEN*")) { connected = true; return true; } else return false; } enterCommandMode(); return false; } boolean SCKBase::close() { if (!connected) { return true; } if (sendCommand(F("close"), false, "*CLOS*")) { connected = false; return true; } connected = false; return false; } #define MAC_ADDRESS_BUFFER_SIZE 18 // "FF:FF:FF:FF:FF:FF\0" char* SCKBase::MAC() { if (enterCommandMode()) { if (sendCommand(F("get mac"), false, "Mac Addr=")) { char newChar; byte offset = 0; while (offset < MAC_ADDRESS_BUFFER_SIZE) { if (Serial1.available()) { newChar = Serial1.read(); //Serial.println(newChar); if ((newChar == '\n')||(newChar < '0')) { buffer[offset] = '\x00'; break; } else if (newChar != -1) { buffer[offset] = newChar; offset++; } } } buffer[MAC_ADDRESS_BUFFER_SIZE-1] = '\x00'; exitCommandMode(); } } return buffer; } char* SCKBase::id() { char* temp = MAC(); byte len = strlen(temp); byte j = 4; buffer[0] = 'S'; buffer[1] = 'C'; buffer[2] = 'K'; buffer[3] = '_'; for(byte i=12; i 0) { if (ver < WIFLY_LATEST_VERSION) { if(update()) return 1; //Wifly Updated. else return 2; //Update Fail. reset(); } else return 0; //WiFly up to date. } else return -1; //Error reading the wifi version. } int SCKBase::getWiFlyVersion() { if (enterCommandMode()) { if (sendCommand(F("ver"), false, "wifly-GSX Ver")) { char newChar; byte offset = 0; boolean prevWasNumber = false; while (offset < 3) { if (Serial1.available()) { newChar = Serial1.read(); if ((newChar != -1 && isdigit(newChar)) || newChar == '.') { if (newChar != '.') { buffer[offset] = newChar; offset++; } prevWasNumber = true; } else { if (prevWasNumber){ break; } prevWasNumber = false; } } } exitCommandMode(); buffer[offset] = 0x00; return atoi(buffer); } return 0; } return 0; } boolean SCKBase::update() { if (enterCommandMode()) { sendCommand(F(DEFAULT_WIFLY_FIRMWARE)); delay(1000); if (findInResponse("FTP OK.", 60000)) { return true; } } else return false; } uint32_t baud[7]={ 2400, 4800, 9600, 19200, 38400, 57600, 115200}; void SCKBase::repair() { if(!enterCommandMode()) { boolean repair = true; for (int i=6; ((i>=0)&&repair); i--) { Serial1.begin(baud[i]); if(enterCommandMode()) { reset(); repair = false; } Serial1.begin(9600); } } } /*TIMER*/ #define RESOLUTION 65536 // Timer1 is 16 bit unsigned int pwmPeriod; unsigned char clockSelectBits; char oldSREG; // To hold Status void SCKBase::timer1SetPeriod(long microseconds) // AR modified for atomic access { long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum oldSREG = SREG; cli(); // Disable interrupts for 16 bit register access ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode SREG = oldSREG; TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock } void SCKBase::timer1Initialize() { TCCR1A = 0; // clear control register A TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer timer1SetPeriod(1500); TIMSK1 = _BV(TOIE1); } void SCKBase::timer1Stop() { TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits TIMSK1 &= ~(_BV(TOIE1)); }