Помогите решить проблему

volshebnik123
Offline
Зарегистрирован: 22.01.2018

Нашел проект http://forum.arduino.cc/index.php?topic=62955.0

Но при компиляции выходит ошибка:  

C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:7:0: warning: "PROGMEM" redefined
 
 #define PROGMEM
 
 ^
 
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:28:0,
 
                 from C:\Program Files (x86)\Arduino\libraries\phi_prompt/phi_prompt.h:69,
 
                 from C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:1:
 
c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\pgmspace.h:113:0: note: this is the location of the previous definition
 
 #define PROGMEM __ATTR_PROGMEM__
 
 ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void setup()':
 
SMBusBattery_Phi:253: error: call of overloaded 'write(int)' is ambiguous
 
   lcd.write(0); lcd.write(1); lcd.write(2); lcd.write(3);
 
              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:253:14: note: candidates are:
 
In file included from C:\Program Files (x86)\Arduino\libraries\phi_prompt/phi_prompt.h:70:0,
 
                 from C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:1:
 
C:\Program Files (x86)\Arduino\libraries\LiquidCrystal\src/LiquidCrystal.h:83:18: note: virtual size_t LiquidCrystal::write(uint8_t)
 
   virtual size_t write(uint8_t);
 
                  ^
 
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,
 
                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,
 
                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:232,
 
                 from C:\Program Files (x86)\Arduino\libraries\phi_prompt/phi_prompt.h:69,
 
                 from C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:1:
 
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:52:12: note: size_t Print::write(const char*)
 
     size_t write(const char *str) {
 
            ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void SelectCommand()':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:405:53: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
 
     if (commandMenu.low.i >= 0 && commandMenu.low.i <= (sizeof(cmdset_items) / sizeof(&cmdset_items))-1) {
 
                                                     ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void DisplaySingleCommand()':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:434:47: warning: null argument where non-null required (argument 2) [-Wnonnull]
 
         strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Ah"));
 
                                               ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:439:47: warning: null argument where non-null required (argument 2) [-Wnonnull]
 
         strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Amps"));
 
                                               ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:444:47: warning: null argument where non-null required (argument 2) [-Wnonnull]
 
         strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Volts"));
 
                                               ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:448:47: warning: null argument where non-null required (argument 2) [-Wnonnull]
 
         strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Minutes"));
 
                                               ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:452:47: warning: null argument where non-null required (argument 2) [-Wnonnull]
 
         strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR("%"));
 
                                               ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:457:47: warning: null argument where non-null required (argument 2) [-Wnonnull]
 
         strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" F"));
 
                                               ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void ScanI2C()':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:543:33: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
 
     ok_dialog("No devices found");
 
                                 ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void DisplayChargeData()':
 
SMBusBattery_Phi:631: error: call of overloaded 'write(int)' is ambiguous
 
   lcd.write(0); lcd.write(1);
 
              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:631:14: note: candidates are:
 
In file included from C:\Program Files (x86)\Arduino\libraries\phi_prompt/phi_prompt.h:70:0,
 
                 from C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:1:
 
C:\Program Files (x86)\Arduino\libraries\LiquidCrystal\src/LiquidCrystal.h:83:18: note: virtual size_t LiquidCrystal::write(uint8_t)
 
   virtual size_t write(uint8_t);
 
                  ^
 
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,
 
                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,
 
                 from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:232,
 
                 from C:\Program Files (x86)\Arduino\libraries\phi_prompt/phi_prompt.h:69,
 
                 from C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:1:
 
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:52:12: note: size_t Print::write(const char*)
 
     size_t write(const char *str) {
 
            ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void EnterI2C()':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:30: warning: narrowing conversion of '(((((int)deviceAddress) >> 6) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:62: warning: narrowing conversion of '(((((int)deviceAddress) >> 5) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                                                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:94: warning: narrowing conversion of '(((((int)deviceAddress) >> 4) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                                                                                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:126: warning: narrowing conversion of '(((((int)deviceAddress) >> 3) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                                                                                                                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:158: warning: narrowing conversion of '(((((int)deviceAddress) >> 2) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                                                                                                                                                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:190: warning: narrowing conversion of '(((((int)deviceAddress) >> 1) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                                                                                                                                                                                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:712:222: warning: narrowing conversion of '((((int)deviceAddress) & 1) + 48)' from 'int' to 'char' inside { } [-Wnarrowing]
 
   char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
 
                                                                                                                                                                                                                              ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void lcdPadBinary(uint8_t, uint8_t)':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:919:37: warning: return-statement with a value, in function returning 'void' [-fpermissive]
 
   if (bits > 8) return lcd.write('E');
 
                                     ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void lcd_reinit_phi()':
 
SMBusBattery_Phi:1018: error: cannot convert 'phi_buttons**' to 'multiple_button_input**' for argument '2' to 'void init_phi_prompt(LiquidCrystal*, multiple_button_input**, char**, int, int, char)'
 
   init_phi_prompt(&lcd,btns,lcd_columns, lcd_rows, '\x7e'); // Supply the liquid crystal object and the phi_buttons objecst. Also supply the column and row of the lcd, and indicator as '>'. You can also use '\x7e', which is a right arrow.
 
                                                          ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'void lcdClearSpace(byte, byte, byte)':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:1051:9: warning: statement has no effect [-Wunused-value]
 
   for (x;x<spaces;x++) lcd.write(' ');
 
         ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'uint8_t cmd_getCode(uint8_t)':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:167:1: warning: control reaches end of non-void function [-Wreturn-type]
 
 }
 
 ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'uint8_t cmd_getType(uint8_t)':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:175:1: warning: control reaches end of non-void function [-Wreturn-type]
 
 }
 
 ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'char** cmd_getPtr()':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:190:1: warning: control reaches end of non-void function [-Wreturn-type]
 
 }
 
 ^
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino: In function 'uint8_t cmd_getLength()':
 
C:\Users\PM\Documents\sketch_jan22b\SMBusBattery_Phi\SMBusBattery_Phi.ino:197:1: warning: control reaches end of non-void function [-Wreturn-type]
 
 }
 
 ^
 
exit status 1
call of overloaded 'write(int)' is ambiguous
 

 

volshebnik123
Offline
Зарегистрирован: 22.01.2018
Вот код который в скетче

#include <phi_prompt.h>
#include <phi_interfaces.h>
#include <phi_buttons.h>
#include <LiquidCrystal.h>
#include <i2cmaster.h>
#include <Arduino.h>  
#define PROGMEM
// SMBus Hacker v1.0 by FalconFour
//  with huge credit to liudr (http://liudr.wordpress.com/) for the awesome work on phi_prompt
//
// insert standard block of legalese and disclaimers here; by relation of the phi_prompt license,
// this code is only licensed for personal and educational use. don't blow yourself up.
// don't sell it. don't blame me if you blow yourself up. and don't sue me if you need more
// money, because i don't have any! =P
//
// The battery SMBus connection always connects to analog pins 5 and 6. To say that SCL is analog
//  5 and SDA is analog 4 probably wouldn't do much good since they don't usually mark that stuff
//  on batteries. First, start with a multimeter and a length of wire, checking the outer pins
//  first. Those are usually + and -. You need "-", unplug + when you find it. Poke around with
//  the "+" wire you just removed, and ground still plugged in. You should NOT see over 5 volts on
//  any pins. Avoid a pin if you see more than 5 volts. Use the SMBus Test function to test your
//  wiring. It won't respond to anything but its own address, so you might want to use a SMBus
//  Scan when you're not having luck but have secure wires.
//
//                          --- THIS IS WHERE I GET YOUR ATTENTION! ---
//    These are the parts you need to modify to your own setup. Add buttons as needed (minimum of
//    4 to navigate without resetting every mis-step), change the LCD pins, mode, etc.
//

byte deviceAddress = B0001011; // most battery controllers seem to use this
byte cmdSet = 0; // default command set (bq2040), seems to have good luck

//         lcd(rs,enable,dp4,dp5,dp6,dp7);
LiquidCrystal lcd(7,6,5,4,3,2);

#define lcd_rows 2
#define lcd_columns 16

#define btn_u 12
// #define btn_d xxxx
#define btn_l 11
#define btn_r 9
#define btn_b 10
// #define btn_a xxxx

//       btn_x(pin, state); - the numbers are mapped to their positions in phi_prompt, as in btns[] below
phi_buttons btn_1(btn_u, LOW);    // button for "UP"
phi_buttons btn_2(btn_null, LOW); // button for "DOWN"
phi_buttons btn_3(btn_l, LOW);    // button for "LEFT"
phi_buttons btn_4(btn_r, LOW);    // button for "RIGHT"
phi_buttons btn_5(btn_b, LOW);    // button for "B" (Enter/Activate)
phi_buttons btn_6(btn_null, LOW); // button for "A" (Back/Escape)

phi_buttons *btns[]={&btn_1,&btn_2,&btn_3,&btn_4,&btn_5,&btn_6};

// -- Okay, you can hit Upload now.
//
#define bufferLen 32
char i2cBuffer[bufferLen];
uint8_t serialCommand;
unsigned int serialData;
int global_style=125; // This is the style of the phi_prompt menus

#define BATT_MAH 0
#define BATT_MA 1
#define BATT_MV 2
#define BATT_MINUTES 3
#define BATT_PERCENT 4
#define BATT_TENTH_K 5
#define BATT_BITFIELD 6
#define BATT_DEC 7
#define BATT_HEX 8
#define BATT_STRING 16

#define Cmd_ManufacturerAccess     0x00
#define Cmd_RemainingCapacityAlarm 0x01
#define Cmd_RemainingTimeAlarm     0x02
#define Cmd_BatteryMode            0x03
#define Cmd_AtRate                 0x04
#define Cmd_AtRateTimeToFull       0x05
#define Cmd_AtRateTimeToEmpty      0x06
#define Cmd_AtRateOK               0x07
#define Cmd_Temperature            0x08
#define Cmd_Voltage                0x09
#define Cmd_Current                0x0A
#define Cmd_AverageCurrent         0x0B
#define Cmd_MaxError               0x0C
#define Cmd_RelativeStateOfCharge  0x0D
#define Cmd_AbsoluteStateOfCharge  0x0E
#define Cmd_RemainingCapacity      0x0F
#define Cmd_FullChargeCapacity     0x10
#define Cmd_RunTimeToEmpty         0x11
#define Cmd_AverageTimeToEmpty     0x12
#define Cmd_AverageTimeToFull      0x13
#define Cmd_ChargingCurrent        0x14
#define Cmd_ChargingVoltage        0x15
#define Cmd_BatteryStatus          0x16
#define Cmd_CycleCount             0x17
#define Cmd_DesignCapacity         0x18
#define Cmd_DesignVoltage          0x19
#define Cmd_SpecificationInfo      0x1A
#define Cmd_ManufactureDate        0x1B
#define Cmd_SerialNumber           0x1C
#define Cmd_ManufacturerName       0x1D
#define Cmd_DeviceName             0x1E
#define Cmd_DeviceChemistry        0x1F
#define Cmd_ManufacturerData       0x20
#define Cmd_Flags                  0x21
#define Cmd_EDV1                   0x22
#define Cmd_EDVF                   0x23

// table of ALL global command labels used in the command sets; if you want to add a new command, tack it onto the bottom.
char cmdLabel_ManufacturerAccess[] PROGMEM = "ManufacturerAccess";
char cmdLabel_RemainingCapacityAlarm[] PROGMEM = "RemainingCapacityAlarm";
char cmdLabel_RemainingTimeAlarm[] PROGMEM = "RemainingTimeAlarm";
char cmdLabel_BatteryMode[] PROGMEM = "BatteryMode";
char cmdLabel_AtRate[] PROGMEM = "AtRate";
char cmdLabel_AtRateTimeToFull[] PROGMEM = "AtRateTimeToFull";
char cmdLabel_AtRateTimeToEmpty[] PROGMEM = "AtRateTimeToEmpty";
char cmdLabel_AtRateOK[] PROGMEM = "AtRateOK";
char cmdLabel_Temperature[] PROGMEM = "Temperature";
char cmdLabel_Voltage[] PROGMEM = "Voltage";
char cmdLabel_Current[] PROGMEM = "Current";
char cmdLabel_AverageCurrent[] PROGMEM = "AverageCurrent";
char cmdLabel_MaxError[] PROGMEM = "MaxError";
char cmdLabel_RelativeStateOfCharge[] PROGMEM = "RelativeStateOfCharge";
char cmdLabel_AbsoluteStateOfCharge[] PROGMEM = "AbsoluteStateOfCharge";
char cmdLabel_RemainingCapacity[] PROGMEM = "RemainingCapacity";
char cmdLabel_FullChargeCapacity[] PROGMEM = "FullChargeCapacity";
char cmdLabel_RunTimeToEmpty[] PROGMEM = "RunTimeToEmpty";
char cmdLabel_AverageTimeToEmpty[] PROGMEM = "AverageTimeToEmpty";
char cmdLabel_AverageTimeToFull[] PROGMEM = "AverageTimeToFull";
char cmdLabel_ChargingCurrent[] PROGMEM = "ChargingCurrent";
char cmdLabel_ChargingVoltage[] PROGMEM = "ChargingVoltage";
char cmdLabel_BatteryStatus[] PROGMEM = "BatteryStatus";
char cmdLabel_CycleCount[] PROGMEM = "CycleCount";
char cmdLabel_DesignCapacity[] PROGMEM = "DesignCapacity";
char cmdLabel_DesignVoltage[] PROGMEM = "DesignVoltage";
char cmdLabel_SpecificationInfo[] PROGMEM = "SpecificationInfo";
char cmdLabel_ManufactureDate[] PROGMEM = "ManufactureDate";
char cmdLabel_SerialNumber[] PROGMEM = "SerialNumber";
char cmdLabel_ManufacturerName[] PROGMEM = "ManufacturerName";
char cmdLabel_DeviceName[] PROGMEM = "DeviceName";
char cmdLabel_DeviceChemistry[] PROGMEM = "DeviceChemistry";
char cmdLabel_ManufacturerData[] PROGMEM = "ManufacturerData";
char cmdLabel_Flags[] PROGMEM = "Flags";
char cmdLabel_EDV1[] PROGMEM = "EDV1";
char cmdLabel_EDVF[] PROGMEM = "EDVF";

// this is set up in the same fashion as phi_prompt menus, because it's also used as one in the selector. String the names of your commands together IN ORDER with the commands definition below this.
const char *bq2040Labels[] PROGMEM =        { cmdLabel_ManufacturerAccess, cmdLabel_RemainingCapacityAlarm, cmdLabel_RemainingTimeAlarm, cmdLabel_BatteryMode, cmdLabel_AtRate, cmdLabel_AtRateTimeToFull, cmdLabel_AtRateTimeToEmpty, cmdLabel_AtRateOK, cmdLabel_Temperature, cmdLabel_Voltage, cmdLabel_Current, cmdLabel_AverageCurrent, cmdLabel_MaxError, cmdLabel_RelativeStateOfCharge, cmdLabel_AbsoluteStateOfCharge, cmdLabel_RemainingCapacity, cmdLabel_FullChargeCapacity, cmdLabel_RunTimeToEmpty, cmdLabel_AverageTimeToEmpty, cmdLabel_AverageTimeToFull, cmdLabel_ChargingCurrent, cmdLabel_ChargingVoltage, cmdLabel_BatteryStatus, cmdLabel_CycleCount, cmdLabel_DesignCapacity, cmdLabel_DesignVoltage, cmdLabel_SpecificationInfo, cmdLabel_ManufactureDate, cmdLabel_SerialNumber, cmdLabel_ManufacturerName, cmdLabel_DeviceName, cmdLabel_DeviceChemistry, cmdLabel_ManufacturerData, cmdLabel_Flags, cmdLabel_EDV1, cmdLabel_EDVF };
// here, a two-dimension array. first byte is the command code itself (hex). second byte is the type of result it's expected to return (all except the strings come through as words.
const uint8_t bq2040Commands[][2] PROGMEM = {      { 0x00, BATT_HEX },          { 0x01, BATT_MAH },            { 0x02, BATT_MINUTES }, { 0x03, BATT_BITFIELD },{ 0x04, BATT_MA }, { 0x05, BATT_MINUTES },    { 0x06, BATT_MINUTES },   {0x07, BATT_HEX},  {0x08, BATT_TENTH_K}, {0x09, BATT_MV}, { 0x0A, BATT_MA },   { 0x0B, BATT_MA },   {0x0C, BATT_PERCENT},    { 0x0D, BATT_PERCENT },         { 0x0E, BATT_PERCENT },         { 0x0F, BATT_MAH },         { 0x10, BATT_MAH },      { 0x11, BATT_MINUTES },     { 0x12, BATT_MINUTES },     { 0x13, BATT_MINUTES },      { 0x14, BATT_MA },        { 0x15, BATT_MV },    { 0x16, BATT_BITFIELD }, { 0x17, BATT_DEC },    { 0x18, BATT_MAH },      { 0x19, BATT_MV },     { 0x1A, BATT_BITFIELD },   { 0x1B, BATT_BITFIELD },   { 0x1C, BATT_DEC },    { 0x20, BATT_STRING },    {0x21, BATT_STRING},  { 0x22, BATT_STRING },     { 0x23, BATT_STRING },{0x2F, BATT_BITFIELD},{0x3E, BATT_MV},{0x3F, BATT_MV} };

// this is what selects the command set itself. there's only one listing here, so just add a new entry (char cmdset_item01[] PROGMEM), then add that entry to the cmdset_items() list below.
char cmdset_item00[] PROGMEM = "bq2040";
const char *cmdset_items[] PROGMEM = {cmdset_item00};

// update each of these commands with your custom command set, just add a new "case" correlating to the cmdset_items[] position above.
uint8_t cmd_getCode(uint8_t command) {
  switch (cmdSet) {
    case 0:
      // bq2040 commands
      return pgm_read_byte(&bq2040Commands[command][0]); // command is first parameter
      break;
  }
}
uint8_t cmd_getType(uint8_t command) {
  switch (cmdSet) {
    case 0:
      // bq2040 commands
      return pgm_read_byte(&bq2040Commands[command][1]); // type is second parameter
      break;
  }
}
void cmd_getLabel(uint8_t command, char* destBuffer) {
  switch (cmdSet) {
    case 0:
      // bq2040 commands
      strlcpy_P(destBuffer,(char*)pgm_read_word(&bq2040Labels[command]),bufferLen-1);
      break;
  }
}
char** cmd_getPtr() {
  switch (cmdSet) {
    case 0:
      return (char**)&bq2040Labels;
      break;
  }
}
uint8_t cmd_getLength() {
  switch (cmdSet) {
    case 0:
      return (sizeof(bq2040Labels) / sizeof(&bq2040Labels));
      break;
  }
}

phi_prompt_struct topMenu;
phi_prompt_struct setupMenu;
phi_prompt_struct readMenu;
phi_prompt_struct controlMenu;
phi_prompt_struct commandMenu;
phi_prompt_struct inputBin;
phi_prompt_struct inputHex;
phi_prompt_struct singleCmdList;

char top_menu_item00[] PROGMEM = "Setup";
char top_menu_item01[] PROGMEM = "Read Info";
char top_menu_item02[] PROGMEM = "Control";
const char *top_menu_items[] PROGMEM = {top_menu_item00, top_menu_item01, top_menu_item02};

char setup_menu_item00[] PROGMEM = "Test SMBus";
char setup_menu_item01[] PROGMEM = "Scan SMBus";
char setup_menu_item02[] PROGMEM = "Enter Address";
char setup_menu_item03[] PROGMEM = "Command Set";
char setup_menu_item04[] PROGMEM = "Main Menu";
const char *setup_menu_items[] PROGMEM = {setup_menu_item00, setup_menu_item01, setup_menu_item02, setup_menu_item03, setup_menu_item04};

char read_menu_item00[] PROGMEM = "Battery ID";
char read_menu_item01[] PROGMEM = "Charge data";
char read_menu_item02[] PROGMEM = "Statistics";
char read_menu_item03[] PROGMEM = "Main Menu";
PROGMEM const char *read_menu_items[] = {read_menu_item00, read_menu_item01, read_menu_item02, read_menu_item03};

char control_menu_item00[] PROGMEM = "Single Command";
char control_menu_item01[] PROGMEM = "Write word";
char control_menu_item02[] PROGMEM = "Read word";
char control_menu_item03[] PROGMEM = "Read block";
char control_menu_item04[] PROGMEM = "Main menu";
PROGMEM const char *control_menu_items[] = {control_menu_item00, control_menu_item01, control_menu_item02, control_menu_item03, control_menu_item04};

byte lcdCustomCharBuffer[8][8];
const byte lcdStartupLogo[8][8] PROGMEM = {
{ B01111, B11111, B11111, B11100, B11100, B11100, B11100, B11100 },
{ B11110, B11111, B11111, B00111, B00111, B00111, B00111, B00111 },
{ B00000, B00000, B01110, B11011, B10001, B10100, B11001, B01110 },
{ B00000, B00000, B01100, B10011, B01101, B10101, B11011, B01100 },
{ B11111, B11111, B11111, B11100, B11100, B11100, B11100, B11100 },
{ B11111, B11111, B11111, B00111, B00111, B00111, B00111, B00111 },
{ B01000, B01100, B01000, B00000, B01100, B01100, B00000, B00000 },
{ B00000, B00000, B00000, B00000, B00000, B00000, B00000, B00000 } };

void setup() {
  byte x,y;
  lcd.begin(lcd_columns, lcd_rows);
  for (x=0; x<=7; x++) for (y=0; y<=7; y++) lcdCustomCharBuffer[x][y] = pgm_read_byte(&lcdStartupLogo[x][y]);

  i2c_init();
  PORTC = (1 << PORTC4) | (1 << PORTC5); //enable pullups
  lcd.clear();
  lcd.print("BattMon 1.0 ");
  lcd.write(0); lcd.write(1); lcd.write(2); lcd.write(3);
  lcd.setCursor(0,1);
  lcd.print("for Arduino ");
  lcd.write(4); lcd.write(5); lcd.write(6); lcd.write(7);
  for (x=0;x<=7;x++) lcd.createChar(x,lcdCustomCharBuffer[x]);
  delay(1000);
  for (x=0;x<=20;x++) {
    lcdCharShiftRight(0,3);
    lcdCharShiftRight(4,7);
    delay(20);
  }
  delay(500);
  lcd_reinit_phi();
  // Initialize the menus only once, so they stay persistent between submenus.
  //  -- and yeah, dirty hacks are fun! Maybe I could've just "commandMenu = controlMenu", but I don't think that'll work so well.
  commandMenu.low.i = controlMenu.low.i = readMenu.low.i = setupMenu.low.i = singleCmdList.low.i = topMenu.low.i = 0; // Default item highlighted on the list
  commandMenu.width = controlMenu.width = readMenu.width = setupMenu.width = singleCmdList.width = topMenu.width = lcd_columns-((global_style&phi_prompt_arrow_dot)!=0)-((global_style&phi_prompt_scroll_bar)!=0); // Auto fit the size of the list to the screen. Length in characters of the longest list item.
  commandMenu.step.c_arr[0] = controlMenu.step.c_arr[0] = readMenu.step.c_arr[0] = setupMenu.step.c_arr[0] = singleCmdList.step.c_arr[0] = topMenu.step.c_arr[0] = lcd_rows; // rows to auto fit entire screen
  commandMenu.step.c_arr[1] = controlMenu.step.c_arr[1] = readMenu.step.c_arr[1] = setupMenu.step.c_arr[1] = singleCmdList.step.c_arr[1] = topMenu.step.c_arr[1] = 1; // one col list
  commandMenu.step.c_arr[2] = controlMenu.step.c_arr[2] = readMenu.step.c_arr[2] = setupMenu.step.c_arr[2] = singleCmdList.step.c_arr[2] = topMenu.step.c_arr[2] = 0; // row for current/total indicator, or 123^56 list (row 0) 
  commandMenu.step.c_arr[3] = controlMenu.step.c_arr[3] = readMenu.step.c_arr[3] = setupMenu.step.c_arr[3] = singleCmdList.step.c_arr[3] = topMenu.step.c_arr[3] = lcd_columns - 4 - ((global_style&phi_prompt_index_list)!=0) - ((global_style&phi_prompt_scroll_bar)!=0); // col for current/total indicator or list (scrollbar minus 4 minus one for index list)
  commandMenu.col = controlMenu.col = readMenu.col = setupMenu.col = singleCmdList.col = topMenu.col = 0; // Display menu at column 0
  commandMenu.row = controlMenu.row = readMenu.row = setupMenu.row = singleCmdList.row = topMenu.row = 0; // Display menu at row 1
  commandMenu.option = controlMenu.option = readMenu.option = setupMenu.option = singleCmdList.option = topMenu.option = global_style; // Option 0, display classic list, option 1, display 2X2 list, option 2, display list with index, option 3, display list with index2.
  
  topMenu.ptr.list=(char**)&top_menu_items; // Assign the list to the pointer
  topMenu.high.i=(sizeof(top_menu_items) / sizeof(&top_menu_items))-1; // Last item of the list is size of the list - 1.
  controlMenu.ptr.list=(char**)&control_menu_items;
  controlMenu.high.i=(sizeof(control_menu_items) / sizeof(&control_menu_items))-1;
  readMenu.ptr.list=(char**)&read_menu_items;
  readMenu.high.i=(sizeof(read_menu_items) / sizeof(&read_menu_items))-1;
  setupMenu.ptr.list=(char**)&setup_menu_items;
  setupMenu.high.i=(sizeof(setup_menu_items) / sizeof(&setup_menu_items))-1;
  commandMenu.ptr.list=(char**)&cmdset_items;
  commandMenu.high.i=(sizeof(cmdset_items) / sizeof(&cmdset_items))-1;
}

void loop() {
  // dummy loop() statement since we're sorta abstracting C into an object-oriented layout here... just enters into a menu loop and stays there, this never loops.
  top_menu();
  // ... I could probably do something really nasty here like erase the flash, and it'd never know.
}

void top_menu() {
  while(1) // This loops every time a menu item is selected.
  {
    lcd.clear();  // Refresh menu if a button has been pushed
    select_list(&topMenu); // Use the select_list to ask the user to select an item of the list, that is a menu item from your menu.
    while (wait_on_escape(25)) ; // let go please
    switch (topMenu.low.i) {
      case 0:
      DisplaySetupMenu();
      break;
      case 1:
      DisplayReadMenu();
      break;
      case 2:
      DisplayControlMenu(); // Display submenu, will return here upon exiting menu
      break;
      default:
      break;
    }
    delay(500);
  }
}

void DisplaySetupMenu() {
  while(1) {
    lcd.clear();
    if (select_list(&setupMenu) == -3) return; // left -> go back to main menu
    while (wait_on_escape(25)) ; // let go please
    switch (setupMenu.low.i) {
      case 0:
      DetectSMBus();
      break;
      case 1:
      ScanI2C();
      break;
      case 2:
      EnterI2C();
      break;
      case 3:
      SelectCommand();
      break;
      case 4:
      return;
      break;
      default:
      break;
    }
    delay(500);
  }
}

void DisplayReadMenu() {
  while(1) {
    lcd.clear();
    if (select_list(&readMenu) == -3) return; // left arrow -> back to main
    while (wait_on_escape(25)) ; // let go please
    switch (readMenu.low.i) {
      case 0:
      DisplayIDData();
      break;
      case 1:
      DisplayChargeData();
      break;
      case 2:
      DisplayStatistics();
      break;
      case 3:
      return;
      break;
      default:
      break;
    }
    delay(500);
  }
}

void DisplayControlMenu() {
  while(1) {
    lcd.clear();
    if (select_list(&controlMenu) == -3) return;
    while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
    switch (controlMenu.low.i) {
      case 0:
      DisplaySingleCommand();
      break;
      case 1:
      DisplayControlWriteWord();
      break;
      case 2:
      DisplayControlReadWord();
      break;
      case 3:
      DisplayControlReadBlock();
      break;
      case 4:
      return; // back to main menu
      break;
      default:
      break;
    }
    delay(500);
  }
}

void SelectCommand() {
  while(1) {
    lcd.clear();
    if (select_list(&commandMenu) == -3) return;
    while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
    if (commandMenu.low.i >= 0 && commandMenu.low.i <= (sizeof(cmdset_items) / sizeof(&cmdset_items))-1) {
      cmdSet = commandMenu.low.i; // just set the selection to the new command set, looks valid
      return;
    }
  }
}

void DisplaySingleCommand() {
  int wordBuffer;
  double valueBuffer;
  singleCmdList.ptr.list=cmd_getPtr();   // grab the currently selected command list in a pointer
  singleCmdList.high.i=cmd_getLength()-1;
  while(1) {
    lcd.clear();
    if (select_list(&singleCmdList) == -3) return; // left: exit
    while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
    lcd.clear();
    msg_lcd(PSTR(">> Reading... <<"));
    lcd.setCursor(0,1);
    msg_lcd(PSTR("Hung? Check con."));
    if (cmd_getType(singleCmdList.low.i) < BATT_STRING) {
      wordBuffer = i2c_smbus_read_word(cmd_getCode(singleCmdList.low.i));
    } else if (cmd_getType(singleCmdList.low.i) == BATT_STRING) {
      i2c_smbus_read_block(cmd_getCode(singleCmdList.low.i),i2cBuffer,bufferLen);
    } else return;
    switch (cmd_getType(singleCmdList.low.i)) {
      case BATT_MAH:
        valueBuffer = wordBuffer/1000;
        fmtDouble(valueBuffer,6,i2cBuffer,bufferLen);
        strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Ah"));
        break;
      case BATT_MA:
        valueBuffer = wordBuffer/1000;
        fmtDouble(valueBuffer,6,i2cBuffer,bufferLen);
        strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Amps"));
        break;
      case BATT_MV:
        valueBuffer = wordBuffer/1000;
        fmtDouble(valueBuffer,6,i2cBuffer,bufferLen);
        strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Volts"));
        break;
      case BATT_MINUTES:
        itoa(wordBuffer,i2cBuffer,10);
        strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" Minutes"));
        break;
      case BATT_PERCENT:
        itoa(wordBuffer,i2cBuffer,10);
        strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR("%"));
        break;
      case BATT_TENTH_K:
        valueBuffer = ((float)wordBuffer/10 - 273.15) * 1.8 + 32;
        fmtDouble(valueBuffer,6,i2cBuffer,bufferLen);
        strcpy_P(i2cBuffer+strcspn(i2cBuffer,0),PSTR(" F"));
        break;
      case BATT_BITFIELD:
        itoa(wordBuffer,i2cBuffer,2);
        break;
      case BATT_DEC:
        itoa(wordBuffer,i2cBuffer,10);
        break;
      case BATT_HEX:
        strcpy_P(i2cBuffer,PSTR("0x"));
        itoa(wordBuffer,i2cBuffer+2,16);
        break;
    }
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print(i2cBuffer);
    lcd.setCursor(0,0);
    cmd_getLabel(singleCmdList.low.i,i2cBuffer);
    lcd.print(i2cBuffer);
    lcd.setCursor(12,1);
    msg_lcd(PSTR(">OK<"));
    while (wait_on_escape(500) == 0) ; // wait for button press
    while (wait_on_escape(25)) ; // wait for release
    return;
  }
}

void DetectSMBus() {
  byte x = 0;
  lcd.clear();
  lcd.setCursor(0,0);
  msg_lcd(PSTR("Address: "));
  if (deviceAddress == 0) {
    lcd.setCursor(0,1);
    msg_lcd(PSTR("Invalid address!"));
    while (wait_on_escape(500) == 0) ; // wait for button press
    while (wait_on_escape(25)) ; // wait for release
  }
  lcdPadBinary(deviceAddress,7);
  lcd.setCursor(0,1);
  lcd.noCursor();
  lcd.noBlink();
  x = 0;
  msg_lcd(PSTR("....Checking...."));
  while (!i2c_detect_device(deviceAddress)) {
    lcd.setCursor((x&B100)?x+8:x,1);
    lcd.write('.');
    x++;
    x &= B111; // keep it under 8
    lcd.setCursor((x&B100)?x+8:x,1);
    lcd.write('>');
    if (wait_on_escape(250)) return;
  }
  lcd.setCursor(0,1);
  msg_lcd(PSTR("  !! Found !!   "));
  lcd.setCursor(15,1);
  while (wait_on_escape(500) == 0) ; // wait for button press
  while (wait_on_escape(25)) ; // wait for release
}

void ScanI2C() {
  byte addr = 1;
  byte foundI2C = 0;
  byte cursorPos = 1;
  byte scanDirection = 2; // 0: don't change, 1: reverse scan, 2: forward scan (display function)
  byte i2cBitmap[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // ah, data compression. ran into a bug during debugging where this wasn't actually zeroed out on startup, causing huge amounts of corruption.
  int button_status;
  lcd.clear();
  lcd.setCursor(0,0);
  msg_lcd(PSTR("Address    Found"));
  while (addr) {
    lcd.setCursor(0,1);
    lcdPadBinary(addr,7);
    if (i2c_detect_device(addr)) {
      foundI2C++;
      i2cBitmap[addr/8] |= 1 << (addr%8);
    }
    lcd.setCursor(11,1);
    lcd.print(foundI2C,DEC);
    addr++;
    // reserved addresses
    if (addr == 112) addr = 0;
    if (wait_on_escape(25)) return;
  }
  if (foundI2C == 0) {
    lcd.clear();
    ok_dialog("No devices found");
    return;
  }
  addr = 0;
  while (true) {
    if (i2cBitmap[addr/8] & (1 << addr%8)) {
      lcd.clear();
      msg_lcd(PSTR("Select ("));
      lcd.print(cursorPos,DEC);
      lcd.write('/');
      lcd.print(foundI2C,DEC);
      lcd.write(')');
      lcd.setCursor(0,1);
      lcdPadBinary(addr,7);
      lcd.print(" (0x");
      lcd.print(addr,HEX);
      lcd.write(')');
      scroll_bar_v(cursorPos*99/foundI2C,lcd_columns-1,0,lcd_rows);
      while ((button_status = wait_on_escape(500)) == 0) ;
      switch (button_status) {
        case 1:
          scanDirection = 1;
          if (!--cursorPos) {
            cursorPos = foundI2C;
            addr = 112;
          }
          break;
        case 2:
          scanDirection = 2;
          if (++cursorPos > foundI2C) {
            cursorPos = 0;
            addr = 0;
          }
          break;
        case 5:
          deviceAddress = addr;
          strcpy(i2cBuffer,"Using: ");
          itoa(deviceAddress,i2cBuffer+7,2);
          ok_dialog(i2cBuffer);
          while (wait_on_escape(25)) ; // wait for release
          return;
          break;
        default:
          scanDirection = 0;
          break;
      }
    }
    if (scanDirection == 1) addr--;
    else if (scanDirection == 2) addr++;
  }
}

void DisplayIDData() {
  lcd.clear();
  msg_lcd(PSTR("Mfg   Dev   Chem"));
  lcd.setCursor(0,1);
  msg_lcd(PSTR("... Reading ... "));
  do {
    i2c_smbus_read_block(cmd_getCode(Cmd_ManufacturerName),i2cBuffer,bufferLen);
    lcd.setCursor(0,1);
    msg_lcd(PSTR("                "));
    lcd.setCursor(0,1);
    lcd.print(i2cBuffer);
    lcd.setCursor(6,1);
    i2c_smbus_read_block(cmd_getCode(Cmd_DeviceName),i2cBuffer,bufferLen);
    lcd.print(i2cBuffer);
    lcd.setCursor(12,1);
    i2c_smbus_read_block(cmd_getCode(Cmd_DeviceChemistry),i2cBuffer,bufferLen);
    lcd.print(i2cBuffer);
  } while (wait_on_escape(500) == 0);
}

void DisplayChargeData() {
  int currVoltage, currAmps, estPercent, currTemp;
  int lastVoltage, lastAmps, lastPercent, lastTemp;
  int lowVoltage, lowAmps, lowTemp, highVoltage, highAmps, highTemp;
  byte x,y;
  lcd.clear();
  // initialize the custom char buffer & clear characters
  for (x=0; x<=7; x++) {
    for (y=0; y<=7; y++) lcdCustomCharBuffer[x][y] = 0;
    lcd.createChar(x,lcdCustomCharBuffer[x]);
  }
  lcd.setCursor(0,0);
  msg_lcd(PSTR("V    A    % "));
  lcd.write(0xDF); // ok, seriously, why is this symbol all the way in the far corner of the LCD charmap? With the Chinese gibberish?
  lcd.write('F');
  lcd.setCursor(2,0);
  lcd.write(0); lcd.write(1);
  lcd.setCursor(7,0);
  lcd.write(2); lcd.write(3);
  lcd.setCursor(14,0);
  lcd.write(4); lcd.write(5);
  lcd.setCursor(0,1);
  msg_lcd(PSTR("... Reading ... "));
  while (wait_on_escape(25)) ;
  lowVoltage = i2c_smbus_read_word(cmd_getCode(Cmd_EDVF));
  highVoltage = i2c_smbus_read_word(cmd_getCode(Cmd_ChargingVoltage)) + 300;
  lowAmps = 32767;
  highAmps = 0;
  lowTemp = 32767;
  highTemp = 0;
  do {
    currVoltage = i2c_smbus_read_word(cmd_getCode(Cmd_Voltage));
    currAmps = i2c_smbus_read_word(cmd_getCode(Cmd_Current));
    estPercent = i2c_smbus_read_word(cmd_getCode(Cmd_RelativeStateOfCharge));
    currTemp = i2c_smbus_read_word(cmd_getCode(Cmd_Temperature));
    if (currVoltage != lastVoltage) {
      lastVoltage = currVoltage;
      lcdClearSpace(0,1,5);
      lcd.print((float)currVoltage / 1000, 1);
      lcdCharShiftLeft(0,1);
      y = map(currVoltage,lowVoltage,highVoltage,8,0);
      for (x=0;x<=7;x++) if (x >= y) bitSet(lcdCustomCharBuffer[1][x],0);
      lcd.createChar(1,lcdCustomCharBuffer[1]);
    }
    if (currAmps != lastAmps) {
      lastAmps = currAmps;
      lcdClearSpace(5,1,4);
      lcd.print((float)currAmps / 1000, 1);
      highAmps = max(highAmps,currAmps+100); // +/- 0.1 amps
      lowAmps = min(lowAmps,currAmps-100);
      lcdCharShiftLeft(2,3);
      y = map(currAmps,lowAmps,highAmps,8,0);
      for (x=0;x<=7;x++) if (x >= y) bitSet(lcdCustomCharBuffer[3][x],0);
      lcd.createChar(3,lcdCustomCharBuffer[3]);
    }
    if (estPercent != lastPercent) {
      lastPercent = estPercent;
      lcdClearSpace(9,1,3);
      lcd.print(estPercent,DEC);
    }
    if (currTemp != lastTemp) {
      lastTemp = currTemp;
      lcdClearSpace(12,1,4);
      lcd.print(((float)currTemp/10 - 273.15) * 1.8 + 32, 1);
      highTemp = max(highTemp,currTemp+10); // +/- 0.1 deg K
      lowTemp = min(lowTemp,currTemp-10);
      lcdCharShiftLeft(4,5);
      y = map(currTemp,lowTemp,highTemp,8,0);
      for (x=0;x<=7;x++) if (x >= y) bitSet(lcdCustomCharBuffer[5][x],0);
      lcd.createChar(5,lcdCustomCharBuffer[5]);
    }
  } while (wait_on_escape(500) == 0);
  lcd_reinit_phi();
}

void DisplayStatistics() {
  lcd.clear();
  lcd.setCursor(0,0);
  msg_lcd(PSTR("Date       #Cyc"));
  lcd.setCursor(0,1);
  msg_lcd(PSTR("... Reading ... "));
  serialData = i2c_smbus_read_word(cmd_getCode(Cmd_ManufactureDate));
  lcdClearSpace(0,1,16);
  lcd.print((uint8_t)(serialData >> 5) & B00001111,DEC);
  lcd.print('/');
  lcd.print((uint8_t)serialData & B00011111,DEC);
  lcd.print('/');
  lcd.print((serialData >> 9) + 1980,DEC);
  lcd.setCursor(11,1);
  lcd.print(i2c_smbus_read_word(cmd_getCode(Cmd_CycleCount)),DEC);
  while (wait_on_escape(500) == 0) ;
}

void EnterI2C() {
  lcd.clear(); // Clear the lcd
  msg_lcd(PSTR("Enter 7 bits:   ")); // Prompt user for input

  char textAddress[8] = {'0' + bitRead(deviceAddress,6), '0' + bitRead(deviceAddress,5), '0' + bitRead(deviceAddress,4), '0' + bitRead(deviceAddress,3), '0' + bitRead(deviceAddress,2), '0' + bitRead(deviceAddress,1), '0' + bitRead(deviceAddress,0)}; // This is the buffer that will store the content of the text panel.
  inputBin.ptr.msg=textAddress; // Assign the text buffer address
  inputBin.low.c='0'; // Text panel valid input starts with character '0'.
  inputBin.high.c='1'; // Text panel valid input ends with character '1'.
  inputBin.width=7; // Length of the input panel is 2 characters.
  inputBin.col=2; // Display input panel at column 2
  inputBin.row=1; // Display input panel at row 1
  inputBin.option=0;

  switch (input_panel(&inputBin)) {
    case -1: // escape (back to menu)
    case -3: // left (at MSB, back to menu)
      return;
      break;
    case 1:
      deviceAddress = strtoul(textAddress, NULL, 2);
      lcdClearSpace(2,1,7);
      lcdPadBinary(deviceAddress,7);
      msg_lcd(PSTR(" >OK<"));
      break;
    default:
      break;
  }
  while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
  while (wait_on_escape(500) == 0) ; // wait for button press
}

void DisplayControlWriteWord() {
  char textAddress[3]="00";  // This is the buffer that will store the content of the text panel. 
  char textValue[5]="0000"; 
  int menuSelection;

  lcd.clear(); // Clear the lcd
  msg_lcd(PSTR("Adr -WRITE- Val ")); // Prompt user for input
  lcd.setCursor(0,1);
  msg_lcd(PSTR("0x..      0x0000"));
  // common parameters
  inputHex.low.c='A'; // Text panel valid input starts with character 'A'.
  inputHex.high.c='F'; // Text panel valid input ends with character 'Z'.
  inputHex.row=1; // Display input panel at row 1
  inputHex.option=1; // Option 1 incluess 0-9 as valid characters.

  while (true) { // this way we can go back and forth, come back to it when we loop back from value field
    inputHex.ptr.msg=textAddress; // Assign the text buffer address
    inputHex.width=2; // Length of the input panel is 2 characters.
    inputHex.col=2; // Display input panel at column 2 (at "0x__")
    switch (input_panel(&inputHex)) {
      case -4: // right (at LSB, go right to the value)
      case 1:  // enter (confirm address, go to the value)
        serialCommand = strtoul(textAddress, NULL, 16);
        lcdClearSpace(2,1,2);
        lcd.print(serialCommand,HEX);
        inputHex.ptr.msg=textValue; // Assign the text buffer address
        inputHex.width=4; // Length of the input panel is 4 characters.
        inputHex.col=12; // Display input panel at column 12 (right side of screen, at "0x____")
        while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
        menuSelection = input_panel(&inputHex);
        while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
        serialData = strtoul(textValue, NULL, 16);
        lcdClearSpace(12,1,4);
        lcd.print(serialData,HEX);
        switch (menuSelection) {
          case 1: // enter (confirm all, perform write)
            i2c_smbus_write_word(serialCommand,serialData); // write value with command (value converted from string in default above; command converted before we got here)
            lcd.setCursor(5,1);
            msg_lcd(PSTR("-OK-"));
            while (wait_on_escape(500) == 0) ; // wait for button press
          case -1: // escape (return to menu)
            return;
            break; // dummy break, won't reach this
          case -3: // left (at MSB, go back to address)
            break; // this is the only case where this is actually reached... haha
        }
        break;
      case -3: // left (at MSB, go back to menu since we don't want to be here)
      case -1: // escape (back to menu)
        return;
        break;
      default: // invalid?
        break;
    }
  }
}

void DisplayControlReadWord() {
  lcd.clear(); // Clear the lcd
  msg_lcd(PSTR("Addr  -READ- Val")); // Prompt user for input
  lcd.setCursor(0,1);
  msg_lcd(PSTR("0x..      0x...."));

  char textAddress[3]="00"; // This is the buffer that will store the content of the text panel. 
  inputHex.ptr.msg=textAddress; // Assign the text buffer address
  inputHex.low.c='A'; // Text panel valid input starts with character 'A'.
  inputHex.high.c='F'; // Text panel valid input ends with character 'F'.
  inputHex.width=2; // Length of the input panel is 2 characters.
  inputHex.col=2; // Display input panel at column 2
  inputHex.row=1; // Display input panel at row 1
  inputHex.option=1; // Option 1 incluess 0-9 as valid characters.

  switch (input_panel(&inputHex)) {
    case -1: // escape (back to menu)
    case -3: // left (at MSB, back to menu)
      return;
      break;
    case 1:
      serialCommand = strtoul(textAddress, NULL, 16);
      serialData = i2c_smbus_read_word(serialCommand);
      lcdClearSpace(12,1,4);
      lcd.print(serialData,HEX);
      break;
    default:
      break;
  }
  while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
  while (wait_on_escape(500) == 0) ; // wait for button press
}

void DisplayControlReadBlock() {
  byte bytesReceived;
  lcd.clear(); // Clear the lcd
  msg_lcd(PSTR("Block Read: Addr")); // Prompt user for input

  char textAddress[3]="00"; // This is the buffer that will store the content of the text panel.
  inputHex.ptr.msg=textAddress; // Assign the text buffer address
  inputHex.low.c='A'; // Text panel valid input starts with character 'A'.
  inputHex.high.c='F'; // Text panel valid input ends with character 'Z'.
  inputHex.width=3; // Length of the input panel is 3 characters.
  inputHex.col=7; // Display input panel at column 7
  inputHex.row=1; // Display input panel at row 1
  inputHex.option=1; // Option 1 incluess 0-9 as valid characters. Option 0, default, option 1 include 0-9 as valid inputs.

  if (input_panel(&inputHex) == 1) { // only one case here, we want ENTER. Everything else escapes back to menu.
    serialCommand = strtoul(textAddress, NULL, 16);
    lcd.clear();
    bytesReceived = i2c_smbus_read_block(serialCommand,i2cBuffer,bufferLen);
    msg_lcd(PSTR("Cmd "));
    lcd.print(serialCommand,HEX);
    msg_lcd(PSTR(": "));
    lcd.print(bytesReceived,DEC);
    msg_lcd(PSTR(" Bytes"));
    lcd.setCursor(0,1);
    if (bytesReceived > 0 && bytesReceived <= 16) // more than 0 bytes, less than 16.
      lcd.print(i2cBuffer);
    else
      msg_lcd(PSTR("ERR:Invalid Data"));
    while (wait_on_escape(25)) ; // wait for buttons to be up, may have residual press from menu
    while (wait_on_escape(500) == 0) ; // wait for any button to continue
  }
  while (wait_on_escape(25)) ; // wait for no button press
}

uint8_t i2c_detect_device ( uint8_t addr ) {
  addr <<= 1; // shift to make room for read/write bit
  if (i2c_start(addr + I2C_WRITE)) {
    // device inaccessible
    i2c_stop();
    delay(100);
    return false;
  } else {
    // device accessible
    i2c_write(0x00);
    i2c_rep_start(addr + I2C_READ);
    i2c_readAck();
    i2c_readNak();
    i2c_stop();
    delay(100);
    return true;
  }
}

void i2c_smbus_write_word ( uint8_t command, unsigned int data ) {
  i2c_start((deviceAddress<<1) + I2C_WRITE);
  i2c_write(command);
  i2c_write((uint8_t)data);
  i2c_write((uint8_t)(data>>8));
  i2c_stop();
  return;
}

unsigned int i2c_smbus_read_word ( uint8_t command ) {
  unsigned int buffer = 0;
  i2c_start((deviceAddress<<1) + I2C_WRITE);
  i2c_write(command);
  i2c_rep_start((deviceAddress<<1) + I2C_READ);
  buffer = i2c_readAck();
  buffer += i2c_readNak() << 8;
  i2c_stop();
  return buffer;
}

uint8_t i2c_smbus_read_block ( uint8_t command, char* blockBuffer, uint8_t blockBufferLen ) {
  uint8_t x, num_bytes;
  i2c_start((deviceAddress<<1) + I2C_WRITE);
  i2c_write(command);
  i2c_rep_start((deviceAddress<<1) + I2C_READ);
  num_bytes = i2c_readAck(); // num of bytes; 1 byte will be index 0
  num_bytes = constrain(num_bytes,0,blockBufferLen-2); // room for null at the end
  for (x=0; x<num_bytes-1; x++) { // -1 because x=num_bytes-1 if x<y; last byte needs to be "nack"'d, x<y-1
    blockBuffer[x] = i2c_readAck();
  }
  blockBuffer[x++] = i2c_readNak(); // this will nack the last byte and store it in x's num_bytes-1 address.
  blockBuffer[x] = 0; // and null it at last_byte+1 for LCD printing
  i2c_stop();
  return num_bytes;
}

void lcdPadBinary (uint8_t value, uint8_t bits) {
  if (bits > 8) return lcd.write('E');
  byte x = 7;
  do {
    if (x > bits-1) continue;
    lcd.write('0' + bitRead(value,x));
  } while (x--);
}

void fmtDouble(double val, byte precision, char *buf, unsigned bufLen = 0xffff);
unsigned fmtUnsigned(unsigned long val, char *buf, unsigned bufLen = 0xffff, byte width = 0);

//
// Produce a formatted string in a buffer corresponding to the value provided.
// If the 'width' parameter is non-zero, the value will be padded with leading
// zeroes to achieve the specified width.  The number of characters added to
// the buffer (not including the null termination) is returned.
//
unsigned fmtUnsigned(unsigned long val, char *buf, unsigned bufLen, byte width) {
  if (!buf || !bufLen) return(0);

  // produce the digit string (backwards in the digit buffer)
  char dbuf[10];
  unsigned idx = 0;
  while (idx < sizeof(dbuf)) {
    dbuf[idx++] = (val % 10) + '0';
    if ((val /= 10) == 0) break;
  }

  // copy the optional leading zeroes and digits to the target buffer
  unsigned len = 0;
  byte padding = (width > idx) ? width - idx : 0;
  char c = '0';
  while ((--bufLen > 0) && (idx || padding)) {
    if (padding) padding--;
    else c = dbuf[--idx];
    *buf++ = c;
    len++;
  }

  // add the null termination
  *buf = '\0';
  return(len);
}

//
// Format a floating point value with number of decimal places.
// The 'precision' parameter is a number from 0 to 6 indicating the desired decimal places.
// The 'buf' parameter points to a buffer to receive the formatted string.  This must be
// sufficiently large to contain the resulting string.  The buffer's length may be
// optionally specified.  If it is given, the maximum length of the generated string
// will be one less than the specified value.
//
// example: fmtDouble(3.1415, 2, buf); // produces 3.14 (two decimal places)
//
void fmtDouble(double val, byte precision, char *buf, unsigned bufLen) {
  if (!buf || !bufLen) return;
  // limit the precision to the maximum allowed value
  const byte maxPrecision = 6;
  if (precision > maxPrecision)
    precision = maxPrecision;

  if (--bufLen > 0)
  {
    // check for a negative value
    if (val < 0.0) {
      val = -val;
      *buf = '-';
      bufLen--;
    }

    // compute the rounding factor and fractional multiplier
    double roundingFactor = 0.5;
    unsigned long mult = 1;
    for (byte i = 0; i < precision; i++) {
      roundingFactor /= 10.0;
      mult *= 10;
    }
    if (bufLen > 0) {
      // apply the rounding factor
      val += roundingFactor;

      // add the integral portion to the buffer
      unsigned len = fmtUnsigned((unsigned long)val, buf, bufLen);
      buf += len;
      bufLen -= len;
    }

    // handle the fractional portion
    if ((precision > 0) && (bufLen > 0)) {
      *buf++ = '.';
      if (--bufLen > 0) buf += fmtUnsigned((unsigned long)((val - (unsigned long)val) * mult), buf, bufLen, precision);
    }
  }

  // null-terminate the string
  *buf = '\0';
}

void lcd_reinit_phi() {
  init_phi_prompt(&lcd,btns,lcd_columns, lcd_rows, '\x7e'); // Supply the liquid crystal object and the phi_buttons objecst. Also supply the column and row of the lcd, and indicator as '>'. You can also use '\x7e', which is a right arrow.
}

void lcdCharShiftLeft(byte startIdx, byte endIdx) {
  byte x, y;
  for (x=startIdx; x<=endIdx; x++) {
    for (y=0; y<=7; y++) {
      if (x > startIdx) {
        if (bitRead(lcdCustomCharBuffer[x][y],4)) bitSet(lcdCustomCharBuffer[x-1][y],0);
        lcd.createChar(x-1,lcdCustomCharBuffer[x-1]); // now we can write it!
      }
      lcdCustomCharBuffer[x][y] <<= 1;
      lcdCustomCharBuffer[x][y] &= B11111;
    }
  }
  lcd.createChar(x,lcdCustomCharBuffer[x]); // had to save this one for last
}
void lcdCharShiftRight(byte startIdx, byte endIdx) {
  byte x, y;
  for (x=startIdx; x<=endIdx; x++) {
    for (y=0; y<=7; y++) {
      if (x < endIdx) {
        if (bitRead(lcdCustomCharBuffer[x][y],0)) bitSet(lcdCustomCharBuffer[x+1][y],5);
        else bitClear(lcdCustomCharBuffer[x+1][y],5);
      }
      lcdCustomCharBuffer[x][y] >>= 1;
    }
  lcd.createChar(x,lcdCustomCharBuffer[x]);
  }
}
void lcdClearSpace(byte col, byte row, byte spaces) {
  byte x = 0;
  lcd.setCursor(col,row);
  for (x;x<spaces;x++) lcd.write(' ');
  lcd.setCursor(col,row);
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

мошт, со светодиодика начать?  И мелкими-мелкими перебежками -> к свету?

volshebnik123
Offline
Зарегистрирован: 22.01.2018

Может поможете скомпилировать правильно?)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

volshebnik123 пишет:

Может поможете скомпилировать правильно?)

Неа. 

volshebnik123
Offline
Зарегистрирован: 22.01.2018

Ругается на 1019 строке 

exit status 1
cannot convert 'phi_buttons**' to 'multiple_button_input**' for argument '2' to 'void init_phi_prompt(LiquidCrystal*, multiple_button_input**, char**, int, int, char)'
Что надо изменить?
bwn
Offline
Зарегистрирован: 25.08.2014

Вот неужели всерьез думаешь, что кому то будет интересно копаться в этой портянке.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Мошт, аффтару налить? Он поможет

volshebnik123
Offline
Зарегистрирован: 22.01.2018

Но вроде код рабочий - просто не компилируется !  Кому налить?)

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Автору кода. 

b707
Offline
Зарегистрирован: 26.05.2017

volshebnik123. судя по некоторым #define вначале - это код для старых версий Ардуино ИДЕ. При выпуске новых версий в них часто появлются несовместимые изменения. поэтому компилировать старые проекты на свежих ИДЕ - это головная боль и гемор. Один из вариантов - это поставить на комп старую версию ИДЕ (примерно 1.0.х) и попытаться собрать в ней. Но не факт, что получится, потому что версий было много и лучше бы занать, под какой этот проект собирался.

А править код, чтобы убрать все ошибки в листинге более 1000 строк - это вряд ли хоть кто-то станет, кроме автора.