├── .gitignore ├── .gitmodules ├── AUTHORS ├── CLI.md ├── CMakeLists.txt ├── README.md ├── bootloader ├── AN1310cl.exe ├── AN1310ui.exe ├── PIC18 Bootloader │ ├── PIC18 Bootloader.asm │ ├── PIC18 Bootloader.mcp │ ├── PIC18 Bootloader.mcw │ ├── bootconfig.inc │ ├── devices.inc │ └── preprocess.inc ├── QtCore4.dll ├── QtGui4.dll ├── QtSql4.dll ├── devices.db ├── libgcc_s_dw2-1.dll ├── mingwm10.dll └── sqldrivers │ └── qsqlite4.dll ├── cad ├── Sensorbox2.scad ├── Sensorbox2.stl ├── polyholes.scad ├── teardrops.scad └── utils.scad ├── eagle ├── 3PCurrentTX.brd ├── 3PCurrentTX.pdf ├── 3PCurrentTX.sch ├── LCD_board.brd ├── LCD_board.pdf ├── LCD_board.sch ├── SmartEVSE.brd ├── SmartEVSE.pdf └── SmartEVSE.sch ├── pictures ├── 1Phase_Charging26A.jpg ├── 1Phase_ChargingL123.jpg ├── EVSE_enclosure.jpg ├── EVSE_enclosure_opened.jpg ├── LCD_menu.jpg ├── SmartEVSE_DIN.jpg ├── SmartEVSE_PCBa.jpg ├── SmartEVSE_PCBb.jpg ├── SmartEVSEv2_mode_smart.jpg ├── SmartEVSEv2_small.jpg ├── SmartEVSEv2white.jpg ├── sensorbox.jpg ├── sensorbox_opened.jpg ├── smartevse_cli.png ├── smartevse_cli_ttl_cable.jpg ├── wiring_diagram_1phase.jpg └── wiring_diagram_3phase.jpg ├── src ├── CMakeLists.txt ├── CurrentTX.c ├── EVSE.c ├── EVSE.h ├── EVSE_CTX.mcp ├── EVSE_CTX.mcw ├── EVSE_MAIN.mcp ├── EVSE_MAIN.mcs ├── EVSE_MAIN.mcw ├── LCD.c └── LCD.h └── version2 ├── .gitignore ├── CMakeLists.txt ├── README.md ├── SmartEVSE2.X ├── EVSE.c ├── EVSE.h ├── GLCD.c ├── GLCD.h ├── Makefile ├── OneWire.c ├── OneWire.h ├── bootloader.c ├── bootloader.h ├── dist │ └── default │ │ └── production │ │ └── SmartEVSE2.X.production.hex ├── modbus.c ├── modbus.h ├── nbproject │ ├── Makefile-default.mk │ ├── Makefile-genesis.properties │ ├── Makefile-impl.mk │ ├── Makefile-local-default.mk │ ├── Makefile-variables.mk │ ├── Package-default.bash │ ├── configurations.xml │ └── project.xml ├── utils.c └── utils.h ├── eagle ├── LCD_boardv2.brd ├── LCD_boardv2.pdf ├── LCD_boardv2.sch ├── SmartEVSEv2.2.brd ├── SmartEVSEv2.2.pdf └── SmartEVSEv2.2.sch └── manual ├── SmartEVSEv2.2_install_v2.16.pdf └── SmartEVSEv2_manual_1.07.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/cmake-microchip"] 2 | path = external/cmake-microchip 3 | url = git://github.com/Elemecca/cmake-microchip.git 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | FuzzyLogic 2 | -------------------------------------------------------------------------------- /CLI.md: -------------------------------------------------------------------------------- 1 | CLI 2 | ==== 3 | SmartEVSE has a CLI available via a FTDI/UART/TTL interface. 4 | 5 | To use the CLI you needa USB to TTL cable, a TTL-232R-3V3 would work. But a 5V cable also works. 6 | 7 | The pin layout on the board (for version 1: underneath the LCD) is: 8 | * Ground 9 | * Unused 10 | * Unused 11 | * RXD 12 | * TXD 13 | * Unused 14 | 15 | Version 2.x of the SmartEVSE has the 6 pin 'header' just behind the 12 pin pluggable conenctor. 16 | 17 | In your terminal use these settings: 18 | * 115200 8N1 19 | * No hardware of software flow control 20 | 21 | Hit enter a couple of times and you should get a menu. 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | 3 | # set up the Microchip cross toolchain 4 | set(CMAKE_TOOLCHAIN_FILE external/cmake-microchip/toolchain.cmake) 5 | 6 | # set the default MCU model 7 | set(MICROCHIP_MCU PIC18F26K22) 8 | 9 | if(NOT CMAKE_BUILD_TYPE) 10 | set(CMAKE_BUILD_TYPE Release) 11 | endif() 12 | 13 | project(xc8-cmake C) 14 | 15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpedantic") 16 | set(CMAKE_C_FLAGS_DEBUG "-g") 17 | set(CMAKE_C_FLAGS_RELEASE "-O3") 18 | 19 | #add_subdirectory(src/) 20 | add_subdirectory(version2/) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SmartEVSE v1 2 | ========= 3 | 4 | This repository is now for the older v1 of the module only. 5 | All developement for the current version v2 of the module is taking place here: 6 | [SmartEVSE-2](https://github.com/SmartEVSE/SmartEVSE-2) 7 | 8 | -------------------------------------------------------------------------------- /bootloader/AN1310cl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/AN1310cl.exe -------------------------------------------------------------------------------- /bootloader/AN1310ui.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/AN1310ui.exe -------------------------------------------------------------------------------- /bootloader/PIC18 Bootloader/PIC18 Bootloader.mcp: -------------------------------------------------------------------------------- 1 | [HEADER] 2 | magic_cookie={66E99B07-E706-4689-9E80-9B2582898A13} 3 | file_version=1.0 4 | device=PIC18F25K22 5 | [PATH_INFO] 6 | BuildDirPolicy=BuildDirIsSourceDir 7 | dir_src= 8 | dir_bin= 9 | dir_tmp= 10 | dir_sin= 11 | dir_inc= 12 | dir_lib= 13 | dir_lkr= 14 | [CAT_FILTERS] 15 | filter_src=*.asm 16 | filter_inc=*.h;*.inc 17 | filter_obj=*.o 18 | filter_lib=*.lib 19 | filter_lkr=*.lkr 20 | [CAT_SUBFOLDERS] 21 | subfolder_src= 22 | subfolder_inc= 23 | subfolder_obj= 24 | subfolder_lib= 25 | subfolder_lkr= 26 | [FILE_SUBFOLDERS] 27 | file_000=. 28 | file_001=. 29 | file_002=. 30 | file_003=. 31 | [GENERATED_FILES] 32 | file_000=no 33 | file_001=no 34 | file_002=no 35 | file_003=no 36 | [OTHER_FILES] 37 | file_000=no 38 | file_001=no 39 | file_002=no 40 | file_003=no 41 | [FILE_INFO] 42 | file_000=PIC18 Bootloader.asm 43 | file_001=devices.inc 44 | file_002=bootconfig.inc 45 | file_003=preprocess.inc 46 | [SUITE_INFO] 47 | suite_guid={6B3DAA78-59C1-46DD-B6AA-DBDAE4E06484} 48 | suite_state=extended-mode generate-absolute-code 49 | [TOOL_SETTINGS] 50 | TS{DD2213A8-6310-47B1-8376-9430CDFC013F}= 51 | TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}=/m"$(BINDIR_)$(TARGETBASE).map" /w /o"$(BINDIR_)$(TARGETBASE).cof" 52 | TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}= 53 | [INSTRUMENTED_TRACE] 54 | enable=0 55 | transport=0 56 | format=0 57 | [CUSTOM_BUILD] 58 | Pre-Build= 59 | Pre-BuildEnabled=1 60 | Post-Build= 61 | Post-BuildEnabled=1 62 | -------------------------------------------------------------------------------- /bootloader/PIC18 Bootloader/PIC18 Bootloader.mcw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/PIC18 Bootloader/PIC18 Bootloader.mcw -------------------------------------------------------------------------------- /bootloader/PIC18 Bootloader/bootconfig.inc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) 2002-2011, Microchip Technology Inc. 2 | ; 3 | ; Microchip licenses this software to you solely for use with Microchip 4 | ; products. The software is owned by Microchip and its licensors, and 5 | ; is protected under applicable copyright laws. All rights reserved. 6 | ; 7 | ; SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY 8 | ; WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT 9 | ; NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 | ; FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL 11 | ; MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR 12 | ; CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR 13 | ; EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY 14 | ; OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED 15 | ; TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, 16 | ; OR OTHER SIMILAR COSTS. 17 | ; 18 | ; To the fullest extent allowed by law, Microchip and its licensors 19 | ; liability shall not exceed the amount of fees, if any, that you 20 | ; have paid directly to Microchip to use this software. 21 | ; 22 | ; MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE 23 | ; OF THESE TERMS. 24 | 25 | ;#define TBLWT_BUG ; Enable this to work around timing bug found in some PIC18Fxx20's 26 | ;#define INVERT_UART ; If you don't have an RS232 transceiver, you might want this option 27 | ;#define USE_MAX_INTOSC ; Sets OSCCON for maximum INTOSC frequency (8MHz) 28 | ;#define USE_PLL ; Sets OSCTUNE.PLLEN bit at start up for frequency multiplication. 29 | ;#define PICDEM_LCD2 ; RB0 = 1 required to enable MAX3221 TX output on PICDEM LCD 2 demo board 30 | #define USE_SOFTBOOTWP ; enable software boot block write protection 31 | ;#define USE_SOFTCONFIGWP ; enable software config words write protection 32 | 33 | ; Autobaud will be used by default. To save code space or to force a specific baud rate to be used, 34 | ; you can optionally define a BAUDRG value instead. Most PIC18's support BRG16 mode and use the 35 | ; following equation: 36 | ; BAUDRG = Fosc / (4 * Baud Rate) - 1 37 | ; 38 | ; Old PIC18's without BRG16 mode need this equation instead: 39 | ; BAUDRG = Fosc / (16 * Baud Rate) - 1 40 | ; 41 | ; Examples: 42 | ;#define BAUDRG .51 ; 19.2Kbps from 4MHz (BRG16 = 1, BRGH = 1) 43 | ;#define BAUDRG .103 ; 115.2Kbps from 48MHz (BRG16 = 1, BRGH = 1) 44 | ;#define BAUDRG .85 ; 115.2Kbps from 40MHz (BRG16 = 1, BRGH = 1) 45 | ;#define BAUDRG .68 ; 115.2Kbps from 32MHz (BRG16 = 1, BRGH = 1) 46 | ;#define BAUDRG .16 ; 115.2Kbps from 8MHz (BRG16 = 1, BRGH = 1) 47 | ;#define BAUDRG .11 ; 1Mbps from 48MHz (BRG16 = 1, BRGH = 1) 48 | ;#define BAUDRG .9 ; 1Mbps from 40MHz (BRG16 = 1, BRGH = 1) 49 | ;#define BAUDRG .4 ; 2Mbps from 40MHz (BRG16 = 1, BRGH = 1) 50 | ;#define BAUDRG .3 ; 3Mbps from 48MHz (BRG16 = 1, BRGH = 1) 51 | ;#define BAUDRG .12 ; 19.2Kbps from 4MHz, 115.2Kbps from 24MHz (BRG16 = 0, BRGH = 1) 52 | ;#define BAUDRG .10 ; 115.2Kbps from 19.6608MHz (BRG16 = 0, BRGH = 1) 53 | ;#define BAUDRG .34 54 | 55 | ; Bootloader must start at the beginning of a FLASH Erase Block. If unspecified, 56 | ; bootloader will automatically be located at the end of program memory address space. 57 | ;#define BOOTLOADER_ADDRESS 0 ; bootloader at beginning, application start/ISR vectors require remapping 58 | ;#define BOOTLOADER_ADDRESS END_FLASH - (ERASE_FLASH_BLOCKSIZE * 20) ; useful for running under debugger (debug executive wants to reside at the end of memory space too) 59 | ;#define BOOTLOADER_ADDRESS (END_FLASH - ERASE_FLASH_BLOCKSIZE) ; use on J parts to locate inside flash config erase block 60 | 61 | #ifdef BOOTLOADER_ADDRESS 62 | #if BOOTLOADER_ADDRESS == 0 63 | ; For Bootloader located at program memory address 0, the application firmware must 64 | ; provide remapped reset and interrupt vectors outside of the Boot Block. The following 65 | ; #defines tell the bootloader firmware where application entry points are to be expected: 66 | #define AppVector 0x400 ; application start up code should be located here. 67 | #define AppHighIntVector 0x408 ; application high priority interrupt should be located here 68 | #define AppLowIntVector 0x418 ; application low priority interrupt should be located here 69 | #endif 70 | #endif 71 | 72 | ; Define UART pins and registers. 73 | ; Modify the following lines if you want to use a different UART module. 74 | ; 75 | ; Note: If your UART's RX pin happens to be multiplexed with analog ANx input 76 | ; functionality, you may need to edit the "preprocess.inc" DigitalInput 77 | ; macro. Code there needs to enable the digital input buffer (refer to 78 | ; ADC chapter of your device's datasheet). 79 | #define UARTNUM 2 80 | #if UARTNUM == 1 81 | #define UxSPBRG SPBRG 82 | #define UxSPBRGH SPBRGH 83 | #define UxRCSTA RCSTA 84 | #define UxTXSTA TXSTA 85 | #define UxRCREG RCREG 86 | #define UxTXREG TXREG 87 | #define UxPIR PIR1 88 | #define UxRCIF RCIF 89 | #define UxTXIF TXIF 90 | #define UxBAUDCON BAUDCON 91 | 92 | ; #define RXPORT PORTC ; RX on RC7 is used by default for most PIC18's. 93 | ; #define RXPIN .7 94 | 95 | ; #define RXPORT PORTB ; PIC18F14K50: RX on RB5/AN11 96 | ; #define RXPIN .5 97 | 98 | ; #define RXANSEL ANSELH ; RX/AN11 multiplexed -- must enable digital input buffer 99 | ; #define RXAN .3 ; ANSELH<3> controls AN11 digital input buffer 100 | #endif 101 | 102 | #if UARTNUM == 2 103 | #define UxSPBRG SPBRG2 104 | #define UxSPBRGH SPBRGH2 105 | #define UxRCSTA RCSTA2 106 | #define UxTXSTA TXSTA2 107 | #define UxRCREG RCREG2 108 | #define UxTXREG TXREG2 109 | #define UxPIR PIR3 110 | #define UxRCIF RC2IF 111 | #define UxTXIF TX2IF 112 | #define UxBAUDCON BAUDCON2 113 | 114 | #define RXPORT PORTB ; RX2 pin 115 | #define RXPIN .7 116 | 117 | ; #define RXPORT PORTG ; RG2 is default RX2 pin for some high pin count PIC18's. 118 | ; #define RXPIN .2 119 | 120 | ; #define RXPORT PORTD ; RX2 pin PPS'ed to RD4/RP21 on PIC18F46J11 for example. 121 | ; #define RXPIN .4 122 | 123 | ; #define RXANSEL ANSELH ; On PICs where RX is multiplexed with ANx analog inputs, 124 | ; #define RXAN .3 ; the digital input buffer needs to be enabled via ANSELx SFRs 125 | 126 | ; devices that use PPS to remap UART2 pins will need these lines defined: 127 | ; #define PPS_UTX .5 ; PPS code for TX2/CK2 output function 128 | ; #define PPS_UTX_PIN RPOR23 ; UART TX assigned to RP23 pin 129 | ; #define PPS_URX_PIN .21 ; UART RX assigned to RP21 pin 130 | ; #define PPS_URX RPINR16 ; PPS register for RX2/CK2 input function 131 | #endif 132 | 133 | ; If you get linker errors complaining "can not fit the absolute section," you might want to 134 | ; increase BOOTLOADERSIZE below or set the BOOTLOADER_ADDRESS above to a smaller address number. 135 | 136 | ; Because we need to know the total size of the bootloader before the assembler has finished 137 | ; compiling the source code, we have to estimate the final bootloader size and provide it 138 | ; here as BOOTLOADERSIZE. This number is in bytes (twice the instruction word count). 139 | ; 140 | ; If you see the bootloader is reserving more FLASH memory than it really needs (you'll 141 | ; see a bunch of FFFF/NOP instructions at the end of the bootloader memory region), 142 | ; you can try reducing BOOTLOADERSIZE. 143 | #define BOOTLOADERSIZE .708 144 | 145 | #define MAJOR_VERSION .1 ; Bootloader Firmware Version 146 | #define MINOR_VERSION .5 147 | -------------------------------------------------------------------------------- /bootloader/PIC18 Bootloader/preprocess.inc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) 2002-2011, Microchip Technology Inc. 2 | ; 3 | ; Microchip licenses this software to you solely for use with Microchip 4 | ; products. The software is owned by Microchip and its licensors, and 5 | ; is protected under applicable copyright laws. All rights reserved. 6 | ; 7 | ; SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY 8 | ; WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT 9 | ; NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 | ; FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL 11 | ; MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR 12 | ; CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR 13 | ; EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY 14 | ; OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED 15 | ; TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, 16 | ; OR OTHER SIMILAR COSTS. 17 | ; 18 | ; To the fullest extent allowed by law, Microchip and its licensors 19 | ; liability shall not exceed the amount of fees, if any, that you 20 | ; have paid directly to Microchip to use this software. 21 | ; 22 | ; MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE 23 | ; OF THESE TERMS. 24 | 25 | DigitalInput macro 26 | #ifdef __18F1320 27 | #if BOOTLOADER_ADDRESS == 0 28 | nop ; start up GOTO instruction errata 29 | #endif 30 | bsf ADCON1, PCFG6 ; RB4/AN6/RX pin on PIC18F1x20 requires digital mode 31 | #endif 32 | #ifdef __18F1220 33 | #if BOOTLOADER_ADDRESS == 0 34 | nop ; start up GOTO instruction errata 35 | #endif 36 | bsf ADCON1, PCFG6 ; RB4/AN6/RX pin on PIC18F1x20 requires digital mode 37 | #endif 38 | 39 | #ifdef RXANSEL 40 | banksel RXANSEL 41 | bcf RXANSEL, RXAN 42 | #else 43 | #ifdef ANSC7 44 | banksel ANSELC ; ANSELC is in non-access bank 0x0F on PIC18F46K22 family 45 | bcf ANSELC, ANSC7 ; Digital input enable on RC7/RX pin for PIC18F46K22 family 46 | #endif 47 | #endif 48 | endm 49 | 50 | pmwtpi macro ; tblwt*+ macro for PIC18Fxx20 bug 51 | #ifdef TBLWT_BUG 52 | tblwt * 53 | tblrd *+ 54 | #else 55 | tblwt *+ 56 | #endif 57 | endm 58 | 59 | #ifndef BAUDRG 60 | #ifndef USE_AUTOBAUD 61 | #define USE_AUTOBAUD 62 | #endif 63 | #endif 64 | 65 | #ifndef RXPORT 66 | #ifdef PORTC 67 | #define RXPORT PORTC 68 | #else 69 | #define RXPORT PORTB ; PIC18F1220, PIC18F1320 70 | #endif 71 | #endif 72 | 73 | #ifndef RXPIN 74 | #ifdef PORTC 75 | #define RXPIN 7 ; most PIC18's have RX on RC7 76 | #else 77 | #define RXPIN 4 ; PIC18F1220, PIC18F1320 have RX on RB4 78 | #endif 79 | #endif 80 | 81 | #ifdef BRG16 82 | #ifndef SPBRGH 83 | #define SPBRGH SPBRGH1 ; PIC18F87J10 doesn't define SPBRGH by default. 84 | #endif 85 | 86 | #ifndef BAUDCON 87 | #ifdef BAUDCON1 88 | #define BAUDCON BAUDCON1 ; PIC18F85J90 / PIC18F84J90 89 | #else 90 | #ifdef BAUDCTL 91 | #define BAUDCON BAUDCTL ; PIC18F1220, PIC18F1320 92 | #endif 93 | #endif 94 | #endif 95 | #endif 96 | 97 | #ifndef RCREG 98 | #ifdef RCREG1 99 | #define RCREG RCREG1 ; PIC18F85J90/PIC18F84J90 100 | #endif 101 | #endif 102 | 103 | #ifndef TXIF 104 | #ifdef TX1IF 105 | #define TXIF TX1IF ; PIC18F97J60 doesn't define TXIF by default 106 | #endif 107 | #endif 108 | 109 | #ifndef RCIF 110 | #ifdef RC1IF 111 | #define RCIF RC1IF ; Not a problem on PIC18F97J60, but just in case future parts might need it 112 | #endif 113 | #endif 114 | 115 | #ifndef RXDTP 116 | #ifdef DTRXP 117 | #define RXDTP DTRXP ; PIC18F14K50 doesn't define RXDTP, instead they call it DTRXP 118 | #endif 119 | #endif 120 | 121 | #ifndef TXCKP 122 | #ifdef CKTXP 123 | #define TXCKP CKTXP ; PIC18F14K50 124 | #endif 125 | #endif 126 | 127 | 128 | #if BOOTLOADERSIZE < ERASE_FLASH_BLOCKSIZE 129 | ; This device has a large Erase FLASH Block Size, so we need to reserve a full Erase Block 130 | ; page for the bootloader. Reserving an entire erase block prevents the PC application 131 | ; from trying to accidently erase a portion of the bootloader. 132 | #define BOOTBLOCKSIZE ERASE_FLASH_BLOCKSIZE 133 | #ifndef BOOTLOADER_ADDRESS 134 | #ifdef CONFIG_AS_FLASH 135 | #define BOOTLOADER_ADDRESS (END_FLASH - BOOTBLOCKSIZE - ERASE_FLASH_BLOCKSIZE) 136 | #else 137 | #define BOOTLOADER_ADDRESS (END_FLASH - BOOTBLOCKSIZE) 138 | #endif 139 | #endif 140 | #else 141 | #if (BOOTLOADERSIZE % ERASE_FLASH_BLOCKSIZE) == 0 142 | #define BOOTBLOCKSIZE BOOTLOADERSIZE 143 | #else 144 | #define BOOTBLOCKSIZE (BOOTLOADERSIZE / ERASE_FLASH_BLOCKSIZE + 1) * ERASE_FLASH_BLOCKSIZE 145 | #endif 146 | #ifndef BOOTLOADER_ADDRESS 147 | #define BOOTLOADER_ADDRESS (END_FLASH - BOOTBLOCKSIZE) 148 | #endif 149 | #endif 150 | -------------------------------------------------------------------------------- /bootloader/QtCore4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/QtCore4.dll -------------------------------------------------------------------------------- /bootloader/QtGui4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/QtGui4.dll -------------------------------------------------------------------------------- /bootloader/QtSql4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/QtSql4.dll -------------------------------------------------------------------------------- /bootloader/devices.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/devices.db -------------------------------------------------------------------------------- /bootloader/libgcc_s_dw2-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/libgcc_s_dw2-1.dll -------------------------------------------------------------------------------- /bootloader/mingwm10.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/mingwm10.dll -------------------------------------------------------------------------------- /bootloader/sqldrivers/qsqlite4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/bootloader/sqldrivers/qsqlite4.dll -------------------------------------------------------------------------------- /cad/Sensorbox2.scad: -------------------------------------------------------------------------------- 1 | // 2 | // Sensorbox, connects up to 4 current transformers, and transmits data over rs485 to smart EVSE 3 | // Top and bottom part 4 | // 5 | // uses nopheads polyholes to make hex nut traps and holes 6 | // 7 | // (c) 2013 Michael Stegen / Stegen Electronics 8 | 9 | include 10 | include 11 | include 12 | 13 | $fn=50; 14 | 15 | box_thickness = 1.8; 16 | height = 8; 17 | top_height = 8; 18 | length=65.5; 19 | width=46.5; 20 | ctoffset=0; 21 | 22 | 23 | layer_height = 0.3; // layer height when printing, for supported holes 24 | eta = 0.01; 25 | 26 | M3_head_depth = 4; // hex m3 bolt 27 | M3_head_radius = 6.3 / 2; // hex m3 bolt 28 | 29 | 30 | M3_tap_radius = 2.5 / 2; 31 | M3_clearance_radius = 3.3 / 2; 32 | M3_nut_radius = 6.5 / 2; 33 | M3_nut_trap_depth = 6; 34 | 35 | 36 | 37 | 38 | module sensor_back() { 39 | difference() { 40 | rounded_rectangle([length,width,height],3, center = false); 41 | difference() { 42 | translate([0,0,box_thickness]) 43 | rounded_rectangle([length-(box_thickness*2),width-(box_thickness*2),height],2, center = false); 44 | 45 | translate([(length/2)-7,(width/2)-1,height-1]) // make clips on both sides 46 | rotate([0,90,0]) 47 | cylinder(r=1,h=6, center=true); 48 | translate([-((length/2))+7,(width/2)-1,height-1]) 49 | rotate([0,90,0]) 50 | cylinder(r=1,h=6, center=true); 51 | translate([-((length/2))+7,-((width/2))+1,height-1]) 52 | rotate([0,90,0]) 53 | cylinder(r=1,h=6, center=true); 54 | translate([(length/2)-7,-((width/2))+1,height-1]) 55 | rotate([0,90,0]) 56 | cylinder(r=1,h=6, center=true); 57 | } 58 | 59 | 60 | translate([17+ctoffset,width/2-1,height]) // make holes for CTs 61 | rotate([90,0,0]) 62 | cylinder(r=3.1,h=5, center=true); 63 | 64 | translate([5.7+ctoffset,width/2-1,height]) 65 | rotate([90,0,0]) 66 | cylinder(r=3.1,h=5, center=true); 67 | 68 | translate([-5.7+ctoffset,width/2-1,height]) 69 | rotate([90,0,0]) 70 | cylinder(r=3.1,h=5, center=true); 71 | 72 | translate([-17+ctoffset,width/2-1,height]) 73 | rotate([90,0,0]) 74 | cylinder(r=3.1,h=5, center=true); 75 | 76 | translate([(length/2)-1,0,top_height-0.2]) // make hole for 4 way header 77 | cube([4,15.2,7.5], center=true); 78 | 79 | 80 | } 81 | } 82 | 83 | 84 | module sensor_top() { 85 | union(){ 86 | 87 | difference() { 88 | union(){ 89 | rounded_rectangle([length,width,top_height],3, center = false); 90 | rounded_rectangle([length-(box_thickness*2)-0.15,width-(box_thickness*2)-0.15,height+2.2],2, center = false); 91 | } 92 | difference() { 93 | translate([0,0,box_thickness]) 94 | rounded_rectangle([length-(box_thickness*4),width-(box_thickness*4),top_height+3],2, center = false); 95 | 96 | } 97 | 98 | translate([0,(width/2)-(box_thickness*2),box_thickness+2+(height/2)]) 99 | cube([length-20,box_thickness*2,height+4],center=true); 100 | 101 | translate([0,-(width/2)+(box_thickness*2),box_thickness+2+(height/2)]) 102 | cube([length-20,box_thickness*2,height+4],center=true); 103 | 104 | translate([(length/2)-(box_thickness*2),0,box_thickness+2+(height/2)]) 105 | cube([box_thickness*2,width-20,height+4],center=true); 106 | 107 | translate([-(length/2)+(box_thickness*2),0,box_thickness+2+(height/2)]) 108 | cube([box_thickness*2,width-20,height+4],center=true); 109 | 110 | 111 | translate([(length/2)-6,(width/2)-1,height+1]) // make clips on both sides 112 | rotate([0,90,0]) 113 | cylinder(r=1,h=10, center=true); 114 | translate([-((length/2))+6,(width/2)-1,height+1]) 115 | rotate([0,90,0]) 116 | cylinder(r=1,h=10, center=true); 117 | translate([-((length/2))+6,-((width/2))+1,height+1]) 118 | rotate([0,90,0]) 119 | cylinder(r=1,h=10, center=true); 120 | translate([(length/2)-6,-((width/2))+1,height+1]) 121 | rotate([0,90,0]) 122 | cylinder(r=1,h=10, center=true); 123 | 124 | 125 | 126 | 127 | translate([17-ctoffset,width/2-1,top_height]) // make holes for CTs 128 | rotate([90,0,0]) 129 | cylinder(r=3.1,h=6, center=true); 130 | 131 | translate([5.7-ctoffset,width/2-1,top_height]) 132 | rotate([90,0,0]) 133 | cylinder(r=3.1,h=6, center=true); 134 | 135 | translate([-5.7-ctoffset,width/2-1,top_height]) 136 | rotate([90,0,0]) 137 | cylinder(r=3.1,h=6, center=true); 138 | 139 | translate([-17-ctoffset,width/2-1,top_height]) 140 | rotate([90,0,0]) 141 | cylinder(r=3.1,h=6, center=true); 142 | 143 | translate([-(length/2)+1,0,height+0.2]) // make hole for 4 way header 144 | cube([6,15.2,7.5], center=true); 145 | 146 | 147 | } // end of difference 148 | 149 | //translate([-2.75,-4.75,height/2]) // light pipe for LED 150 | //cylinder(r=1.5,h=height,center=true); 151 | 152 | } // end of union 153 | } 154 | 155 | 156 | translate([0,25,0]) 157 | sensor_back(); 158 | translate([0,-25,0]) 159 | sensor_top(); 160 | 161 | -------------------------------------------------------------------------------- /cad/polyholes.scad: -------------------------------------------------------------------------------- 1 | // 2 | // Mendel90 3 | // 4 | // GNU GPL v2 5 | // nop.head@gmail.com 6 | // hydraraptor.blogspot.com 7 | // 8 | // See http://hydraraptor.blogspot.com/2011/02/polyholes.html 9 | // 10 | function sides(r) = max(round(4 *r),3); 11 | function corrected_radius(r,n) = 0.1 + r / cos(180 / n); 12 | function corrected_diameter(d) = 0.2 + d / cos(180 / sides(d / 2)); 13 | 14 | module poly_circle(r, center = false) { 15 | n = sides(r); 16 | circle(r = corrected_radius(r,n), $fn = n, center = center); 17 | } 18 | 19 | module poly_cylinder(r, h, center = false) { 20 | n = sides(r); 21 | cylinder(h = h, r = corrected_radius(r,n), $fn = n, center = center); 22 | } 23 | 24 | module poly_d_cylinder(r, center = false) { 25 | n = sides(r); 26 | r = corrected_radius(r,n); 27 | cylinder(h = h, r = r, $fn = n, center = center); 28 | translate([0, -r, 0]) 29 | cube([r, 2 * r, h]); 30 | } 31 | -------------------------------------------------------------------------------- /cad/teardrops.scad: -------------------------------------------------------------------------------- 1 | // 2 | // Mendel90 3 | // 4 | // GNU GPL v2 5 | // nop.head@gmail.com 6 | // hydraraptor.blogspot.com 7 | // 8 | // For making horizontal holes that don't need support material 9 | // Small holes can get away without it but they print better with truncated teardrops 10 | // 11 | module teardrop_2D(r, truncate = true) { 12 | difference() { 13 | union() { 14 | circle(r = r, center = true); 15 | translate([0,r / sqrt(2),0]) 16 | rotate([0,0,45]) 17 | square([r, r], center = true); 18 | } 19 | if(truncate) 20 | translate([0, r * 2, 0]) 21 | square([2 * r, 2 * r], center = true); 22 | } 23 | } 24 | 25 | module teardrop(h, r, center, truncate = true) 26 | linear_extrude(height = h, convexity = 2, center = center) 27 | teardrop_2D(r, truncate); 28 | 29 | module teardrop_plus(h, r, center, truncate = true) 30 | teardrop(h, r + layer_height / 4, center, truncate); 31 | 32 | 33 | module tearslot(h, r, w, center) 34 | linear_extrude(height = h, convexity = 6, center = center) 35 | hull() { 36 | translate([-w/2,0,0]) teardrop_2D(r, true); 37 | translate([ w/2,0,0]) teardrop_2D(r, true); 38 | } 39 | 40 | module vertical_tearslot(h, r, l, center = true) 41 | linear_extrude(height = h, convexity = 6, center = center) 42 | hull() { 43 | translate([0, l / 2]) teardrop_2D(r, true); 44 | translate([0, -l / 2, 0]) 45 | circle(r = r, center = true); 46 | } 47 | -------------------------------------------------------------------------------- /cad/utils.scad: -------------------------------------------------------------------------------- 1 | module slot(h, r, l, center = true) 2 | linear_extrude(height = h, convexity = 6, center = center) 3 | hull() { 4 | translate([l/2,0,0]) 5 | circle(r = r, center = true); 6 | translate([-l/2,0,0]) 7 | circle(r = r, center = true); 8 | } 9 | 10 | module nut_trap(screw_r, nut_r, depth, horizontal = false, supported = false) { 11 | union() { 12 | if(horizontal) { 13 | if(screw_r) 14 | teardrop_plus(r = screw_r, h = 200, center = true); 15 | cylinder(r = nut_r + layer_height / 4, h = depth * 2, center = true, $fn = 6); 16 | } 17 | else { 18 | difference() { 19 | union() { 20 | if(screw_r) 21 | poly_cylinder(r = screw_r, h = 200, center = true); 22 | cylinder(r = nut_r, h = depth * 2, center = true, $fn = 6); 23 | } 24 | if(supported) 25 | translate([0, 0, depth - eta]) 26 | cylinder(r = nut_r, h = layer_height, center = false); 27 | } 28 | } 29 | } 30 | } 31 | 32 | module head_trap(screw_r, nut_r, depth, supported = false) { 33 | union() { 34 | difference() { 35 | union() { 36 | if(screw_r) 37 | poly_cylinder(r = screw_r, h = 200, center = true); 38 | cylinder(r = nut_r, h = depth * 2, center = true); 39 | } 40 | if(supported) 41 | translate([0, 0, depth - eta]) 42 | cylinder(r = nut_r, h = layer_height, center = false); 43 | } 44 | } 45 | } 46 | 47 | module rounded_square(w, h, r) 48 | { 49 | union() { 50 | square([w - 2 * r, h], center = true); 51 | square([w, h - 2 * r], center = true); 52 | for(x = [-w/2 + r, w/2 - r]) 53 | for(y = [-h/2 + r, h/2 - r]) 54 | translate([x, y]) 55 | circle(r = r); 56 | } 57 | } 58 | 59 | module rounded_rectangle(size, r, center = true) 60 | { 61 | w = size[0]; 62 | h = size[1]; 63 | linear_extrude(height = size[2], center = center) 64 | rounded_square(size[0], size[1], r); 65 | } 66 | -------------------------------------------------------------------------------- /eagle/3PCurrentTX.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/eagle/3PCurrentTX.pdf -------------------------------------------------------------------------------- /eagle/LCD_board.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/eagle/LCD_board.pdf -------------------------------------------------------------------------------- /eagle/SmartEVSE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/eagle/SmartEVSE.pdf -------------------------------------------------------------------------------- /pictures/1Phase_Charging26A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/1Phase_Charging26A.jpg -------------------------------------------------------------------------------- /pictures/1Phase_ChargingL123.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/1Phase_ChargingL123.jpg -------------------------------------------------------------------------------- /pictures/EVSE_enclosure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/EVSE_enclosure.jpg -------------------------------------------------------------------------------- /pictures/EVSE_enclosure_opened.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/EVSE_enclosure_opened.jpg -------------------------------------------------------------------------------- /pictures/LCD_menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/LCD_menu.jpg -------------------------------------------------------------------------------- /pictures/SmartEVSE_DIN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/SmartEVSE_DIN.jpg -------------------------------------------------------------------------------- /pictures/SmartEVSE_PCBa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/SmartEVSE_PCBa.jpg -------------------------------------------------------------------------------- /pictures/SmartEVSE_PCBb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/SmartEVSE_PCBb.jpg -------------------------------------------------------------------------------- /pictures/SmartEVSEv2_mode_smart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/SmartEVSEv2_mode_smart.jpg -------------------------------------------------------------------------------- /pictures/SmartEVSEv2_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/SmartEVSEv2_small.jpg -------------------------------------------------------------------------------- /pictures/SmartEVSEv2white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/SmartEVSEv2white.jpg -------------------------------------------------------------------------------- /pictures/sensorbox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/sensorbox.jpg -------------------------------------------------------------------------------- /pictures/sensorbox_opened.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/sensorbox_opened.jpg -------------------------------------------------------------------------------- /pictures/smartevse_cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/smartevse_cli.png -------------------------------------------------------------------------------- /pictures/smartevse_cli_ttl_cable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/smartevse_cli_ttl_cable.jpg -------------------------------------------------------------------------------- /pictures/wiring_diagram_1phase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/wiring_diagram_1phase.jpg -------------------------------------------------------------------------------- /pictures/wiring_diagram_3phase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/pictures/wiring_diagram_3phase.jpg -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | CurrentTX.c 3 | EVSE.c 4 | LCD.c 5 | ) 6 | 7 | add_executable(version1 ${SOURCES}) 8 | target_include_directories(version1 PRIVATE ./) 9 | 10 | target_link_libraries(version1) 11 | -------------------------------------------------------------------------------- /src/CurrentTX.c: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: 3+ Phase Current Transmitter, for use with Smart EVSE 3 | ; Date: 16 October 2013 4 | ; 5 | ; Changes: 6 | ; 1.0 Initial release 7 | ; 8 | ; (C) 2013 Michael Stegen / Stegen Electronics 9 | ; 10 | ; RMS current measurement calculation, from openenergymonitor.org 11 | ; 12 | ; 13 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 14 | ; of this software and associated documentation files (the "Software"), to deal 15 | ; in the Software without restriction, including without limitation the rights 16 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | ; copies of the Software, and to permit persons to whom the Software is 18 | ; furnished to do so, subject to the following conditions: 19 | ; 20 | ; The above copyright notice and this permission notice shall be included in 21 | ; all copies or substantial portions of the Software. 22 | ; 23 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | ; THE SOFTWARE. 30 | */ 31 | 32 | 33 | #include "p18f14k22.h" 34 | #include 35 | #include 36 | 37 | 38 | // Configuration settings 39 | #pragma config FCMEN = OFF, IESO = OFF, PCLKEN = ON 40 | #pragma config PLLEN = ON, FOSC = IRC 41 | #pragma config BORV = 30, BOREN = OFF, PWRTEN = ON 42 | #pragma config WDTPS = 2048, WDTEN = OFF // WDT timeout 43 | #pragma config MCLRE = OFF, HFOFST = OFF 44 | #pragma config XINST = ON, BBSIZ = OFF, LVP = OFF, STVREN = ON 45 | #pragma config CP0 = OFF, CP1 = OFF, CPD = OFF, CPB = OFF 46 | #pragma config WRT0 = OFF, WRT1 = OFF 47 | #pragma config WRTD = OFF, WRTB = OFF, WRTC = OFF 48 | #pragma config EBTR1 = OFF, EBTR0 = OFF 49 | #pragma config EBTRB = OFF 50 | 51 | // Global data 52 | #pragma udata 53 | 54 | #define VERSION 1 55 | #define SAMPLES 2048 // Samples per channel 56 | #define BAUD1K2 // Baudrate 1200 bps 57 | #define NR_CTS 3 // Number of CT's 58 | 59 | char buffer[50]; 60 | double Irms[NR_CTS]; 61 | unsigned int lastSampleI,sampleI; //sample_ holds the raw analog read value, lastSample_ holds the last sample 62 | double lastFilteredI, filteredI; //Filtered_ is the raw analog value minus the DC offset 63 | 64 | unsigned int sampleI_CT[NR_CTS]={512,512,512}; 65 | double filteredI_CT[NR_CTS]={0,0,0}; 66 | 67 | 68 | 69 | void UartTX(char byte) 70 | { 71 | // output one byte 72 | while(!PIR1bits.TXIF) // set when register is empty 73 | continue; 74 | TXREG = byte; 75 | } 76 | 77 | /* 78 | void UartTXHex(unsigned char c) 79 | { 80 | unsigned char h; 81 | 82 | h = (c>>4); 83 | if (h>9) h+=7; 84 | h+='0'; // conversion to ASCII 85 | UartTX(h); // TX 86 | 87 | h = c & 0x0f; 88 | if (h>9) h+=7; 89 | h+='0'; // conversion to ASCII 90 | UartTX(h); 91 | } 92 | */ 93 | 94 | 95 | 96 | // calculates 16-bit CRC of given data 97 | // used for Frame Check Sequence on data frame 98 | // Poly used is x^16+x^12+x^5+x 99 | unsigned int calc_crc16(char* start, char len) 100 | { 101 | unsigned int crc=0xffff,c; 102 | int i; 103 | while(len--) 104 | { 105 | c=*start; 106 | for(i=0;i<8;i++) 107 | { 108 | if((crc ^ c) & 1) crc=(crc>>1)^0x8408; 109 | else crc>>=1; 110 | c>>=1; 111 | } 112 | start++; 113 | } 114 | crc = (unsigned int)(crc ^ 0xFFFF); 115 | return(crc); 116 | } 117 | 118 | 119 | 120 | 121 | void UART_RX(void) 122 | { 123 | char x; 124 | x = RCREG; // read USART byte to clear PIR1bits.RCIF flag 125 | // No further processing is done at this time 126 | } 127 | 128 | 129 | /* Send buffer over RS485. Use PPP in HDLC-like Framing for transfers 130 | ; for protocol spec see: http://tools.ietf.org/html/rfc1662 131 | ; compatible with existing RS485 line used on SMA solar inverters. 132 | ; 133 | ; baudrate is 1200 bps 134 | ; 135 | ; ,,,..., 136 | ; protocol = 0x5001 (2 bytes) 137 | ; version = 0x01 (1 byte) 138 | ; nr of channels = 1 byte 139 | ; samples are 4 bytes (double) 140 | ; crc16 is 2 bytes 141 | ; 142 | ; total 4+(n*4)+2 bytes (+ HDLC overhead) 143 | ; 144 | */ 145 | void UART_SendBuf(char* buffer, unsigned char len) 146 | { 147 | char ch; 148 | PORTBbits.RB6 = 1; // set RS485 transceiver to transmit 149 | UartTX(0x7E); // transmit sync flag 150 | 151 | while(len--) 152 | { 153 | ch = *buffer++; // load next byte 154 | if ((ch == 0x11) || (ch == 0x12) || (ch == 0x13) || (ch == 0x7E) || (ch == 0x7D)) // check for escape character 155 | { 156 | ch = ch^0x20; 157 | UartTX(0x7D); // transmit escape character 158 | } 159 | UartTX(ch); // transmit byte 160 | } 161 | 162 | UartTX(0x7E); // transmit sync flag 163 | 164 | while (!TXSTAbits.TRMT) continue; // transmit register empty? 165 | PORTBbits.RB6 = 0; // set RS485 transceiver to receive 166 | 167 | } 168 | 169 | 170 | 171 | unsigned int ReadAnalog(void) // Start ADC conversion, and return result 172 | { 173 | ADCON0bits.GO=1; // initiate conversion on the selected channel 174 | while(ADCON0bits.GO); 175 | return ADRES; // return result 176 | } 177 | 178 | double ReadCT(unsigned char Ch) 179 | { 180 | unsigned int n; 181 | double sumI; //sum = Sum 182 | unsigned char ADCch; 183 | 184 | ADCch=Ch+4; // Set ADC channel 185 | ADCch=(ADCch<<2)+1; // shift 2 pos to left, enable ADC 186 | ADCON0=ADCch; // channel select 187 | 188 | sumI = 0; 189 | 190 | sampleI=sampleI_CT[Ch]; // Get Sample and Filter values 191 | filteredI=filteredI_CT[Ch]; 192 | 193 | for (n = 0; n < SAMPLES; n++) 194 | { 195 | lastSampleI = sampleI; // Used for offset removal 196 | sampleI = ReadAnalog(); // Read port RAx 197 | lastFilteredI = filteredI; // Used for offset removal 198 | filteredI = (0.996*(lastFilteredI+sampleI-lastSampleI)); // Digital high pass filters to remove 2.5V DC offset. 199 | 200 | // Root-mean-square method current 201 | // 1) square current values 202 | // 2) sum 203 | sumI += (filteredI * filteredI); 204 | } 205 | 206 | sampleI_CT[Ch]=sampleI; 207 | filteredI_CT[Ch]=filteredI; // Store Sample and Filter values 208 | 209 | return (sqrt(sumI / SAMPLES)); // Return squareroot of uncalibrated value 210 | 211 | } 212 | 213 | void init(void) 214 | { 215 | OSCCON = 0b11100000; // setup 32Mhz internal oscillator (max 64Mhz) 216 | PORTA = 0; // Init PORTA 217 | LATA = 0; 218 | ANSEL = 0b11110000; // RC0, RC1, RC2, RC3 are analog inputs (pin 16,15,14,7) 219 | ANSELH = 0; // All digital IO 220 | TRISA = 0b00100000; // Set UART RX as input 221 | PORTC = 0; 222 | TRISC = 0b00001111; // RC0-RC3 analog inputs 223 | PORTB = 0; 224 | TRISB = 0b00000000; // all outputs 225 | 226 | 227 | 228 | #if defined(BAUD19K2) 229 | SPBRGH = 1; // Initialize UART 230 | SPBRG = 160; // Baudrate 19k2 231 | #endif 232 | #if defined(BAUD4K8) 233 | SPBRGH = 6; // Initialize UART 234 | SPBRG = 130; // Baudrate 4800 235 | #endif 236 | #if defined(BAUD1K2) 237 | SPBRGH = 0x1A; // Initialize UART 238 | SPBRG = 0x0A; // Baudrate 1200 239 | #endif 240 | BAUDCON = 0b00001000; // 16 bit Baudrate register is used 241 | TXSTA = 0b00100100; // Enable TX, 8 bit, Asynchronous mode 242 | RCSTA = 0b10010000; // Enable serial port TX and RX, 8 bit. 243 | 244 | ADCON0 = 0; // ADC disabled for now 245 | ADCON1 = 0; 246 | ADCON2 = 0b10000010; // Right justify, Tacq = 0 uS, FOSC/32 247 | 248 | T0CON = 0b10000111; // @ 8Mhz => 32 uS Timer0, 16 bit counter 249 | 250 | } 251 | 252 | void main(void) 253 | { 254 | char *pBytes; 255 | char x,n; 256 | unsigned int cs; 257 | 258 | init(); // initialize ports, ADC, UART 259 | 260 | for (x=0;x>8)); 308 | 309 | PORTCbits.RC5=1; // LED on 310 | UART_SendBuf(buffer,n); // send buffer to RS485 port 311 | PORTCbits.RC5=0; // LED off 312 | 313 | // printf("CT1:%5d CT2:%5d CT3:%5d\r\n",(int)(Irms[0]*100), (int)(Irms[1]*100), (int)(Irms[2]*100)); 314 | } 315 | 316 | 317 | } 318 | 319 | 320 | -------------------------------------------------------------------------------- /src/EVSE.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; Date: 1 February 2016 4 | ; 5 | ; 6 | ; 7 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 8 | ; of this software and associated documentation files (the "Software"), to deal 9 | ; in the Software without restriction, including without limitation the rights 10 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | ; copies of the Software, and to permit persons to whom the Software is 12 | ; furnished to do so, subject to the following conditions: 13 | ; 14 | ; The above copyright notice and this permission notice shall be included in 15 | ; all copies or substantial portions of the Software. 16 | ; 17 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | ; THE SOFTWARE. 24 | */ 25 | 26 | #ifndef __EVSE_MAIN 27 | #define __EVSE_MAIN 28 | 29 | #include "p18f25k22.h" 30 | #include 31 | #include 32 | #include "LCD.h" 33 | 34 | #define VERSION "1.07" // SmartEVSE software version 35 | //#define DEBUG_P // Debug print enable/disable 36 | 37 | #define ICAL 3.00 // Irms Calibration value (for Current transformers) 38 | #define MAX_MAINS 25 // max Current the Mains connection can supply 39 | #define MAX_CURRENT 13 // max charging Current for the EV 40 | #define MIN_CURRENT 6 // minimum Current the EV will accept 41 | #define MODE 0 // Normal EVSE mode 42 | #define LOCK 0 // No Cable lock 43 | #define CABLE_LIMIT 13 // Manual set Cable Limit (for use with Fixed Cable) 44 | #define CONFIG 0 // Configuration: 0= TYPE 2 socket, 1= Fixed Cable 45 | #define LOADBL 0 // Load Balancing disabled 46 | #define CHARGEDELAY 60 // Seconds to wait after overcurrent, before tryting again 47 | 48 | #define GOODFCS16 0x0f47 // crc16 frame check value 49 | #define ACK_TIMEOUT 1000 // 1000ms timeout 50 | 51 | #define STATE_A 1 // Vehicle not connected 52 | #define STATE_B 2 // Vehicle connected / not ready to accept energy 53 | #define STATE_C 3 // Vehicle connected / ready to accept energy / ventilation not required 54 | #define STATE_D 4 // Vehicle connected / ready to accept energy / ventilation required 55 | #define STATE_COMM_A 5 // Waiting for response from Master 56 | #define STATE_COMM_B 6 // Waiting for response from Master 57 | #define STATE_COMM_C 7 // Waiting for response from Master 58 | #define STATE_COMM_CB 8 // Waiting for response from Master 59 | 60 | #define PILOT_12V 1 61 | #define PILOT_9V 2 62 | #define PILOT_6V 3 63 | #define PILOT_DIODE 4 64 | #define PILOT_NOK 0 65 | 66 | #define NO_ERROR 0 67 | #define LESS_6A 1 68 | #define CT_NOCOMM 2 69 | #define TEMP_HIGH 3 70 | #define NOCURRENT 4 // No Current! ERROR=LESS_6A, switch to STATE A 71 | 72 | #define SOLENOID_LOCK {LATAbits.LATA4 = 1;LATAbits.LATA5 = 0;} 73 | #define SOLENOID_UNLOCK {LATAbits.LATA4 = 0;LATAbits.LATA5 = 1;} 74 | #define SOLENOID_OFF {LATAbits.LATA4 = 1;LATAbits.LATA5 = 1;} 75 | 76 | #define CONTACTOR_OFF LATBbits.LATB4 = 0; // Contactor OFF 77 | #define CONTACTOR_ON LATBbits.LATB4 = 1; // Contactor ON 78 | 79 | #define MENU_CONFIG 10 80 | #define MENU_MODE 20 81 | #define MENU_LOADBL 100 82 | #define MENU_MAINS 30 83 | #define MENU_MAX 40 84 | #define MENU_MIN 50 85 | #define MENU_LOCK 60 86 | #define MENU_CABLE 70 87 | #define MENU_CAL 80 88 | #define MENU_EXIT 90 89 | 90 | #ifdef DEBUG_P 91 | #define DEBUG_PRINT(x) printf(x) 92 | #else 93 | #define DEBUG_PRINT(x) 94 | #endif 95 | 96 | 97 | 98 | #pragma udata 99 | extern unsigned int MaxMains; // Max Mains Amps (hard limit, limited by the MAINS connection) 100 | extern unsigned int MaxCurrent; // Max Charge current 101 | extern unsigned int MinCurrent; // Minimal current the EV is happy with 102 | extern double ICal; // CT calibration value 103 | extern char Mode; // EVSE mode 104 | extern char Lock; // Cable lock enable/disable 105 | extern unsigned int CableLimit; // Fixed Cable Current limit (only used when config is set to Fixed Cable) 106 | extern char Config; // Configuration (Fixed Cable or Type 2 Socket) 107 | extern char LoadBl; // Load Balance Setting (Disable, Master or Slave) 108 | 109 | #define EEPROM_BYTES 16 // total 16 bytes 110 | 111 | 112 | extern double Irms[4]; // Momentary current per Phase (Amps *10) (23= 2.3A) 113 | // Max 4 phases supported 114 | extern unsigned int crc16; 115 | extern unsigned char State; 116 | extern unsigned char Error; 117 | extern unsigned char NextState; 118 | 119 | extern unsigned int MaxCapacity; // Cable limit (Amps)(limited by the wire in the charge cable, set automatically, or manually if Config=Fixed Cable) 120 | extern unsigned int Imeasured; // Max of all CT inputs (Amps *10) 121 | //extern int Iset; // PWM output is set to this current level (Amps *10) 122 | extern int Balanced[4]; // Amps value per EVSE (max 4) 123 | 124 | extern unsigned char RX1byte; 125 | extern unsigned char idx,idx2,ISRFLAG,ISR2FLAG; 126 | extern unsigned char menu; 127 | extern unsigned int locktimer,unlocktimer; // solenoid timers 128 | extern unsigned long Timer; // mS counter 129 | extern unsigned int ChargeTimer; // seconds counter 130 | extern unsigned char LCDTimer; 131 | extern unsigned char TempEVSE; // Temperature EVSE in deg C (0-125) 132 | extern unsigned char ButtonState; // Holds latest push Buttons state (LSB 2:0) 133 | extern unsigned char OldButtonState; // Holds previous push Buttons state (LSB 2:0) 134 | extern unsigned char LCDNav; 135 | extern unsigned char SubMenu; 136 | extern unsigned long ScrollTimer; 137 | extern unsigned char LCDpos; 138 | extern unsigned char ChargeDelay; // Delays charging up to 60 seconds in case of not enough current avilable. 139 | 140 | 141 | extern const far rom char MenuConfig[]; 142 | extern const far rom char MenuMode[]; 143 | extern const far rom char MenuLoadBl[]; 144 | extern const far rom char MenuMains[]; 145 | extern const far rom char MenuMax[]; 146 | extern const far rom char MenuMin[]; 147 | extern const far rom char MenuCable[]; 148 | extern const far rom char MenuLock[]; 149 | extern const far rom char MenuCal[]; 150 | 151 | void delay(unsigned int d); 152 | void read_settings(void); 153 | void write_settings(void); 154 | 155 | #endif -------------------------------------------------------------------------------- /src/EVSE_CTX.mcp: -------------------------------------------------------------------------------- 1 | [HEADER] 2 | magic_cookie={66E99B07-E706-4689-9E80-9B2582898A13} 3 | file_version=1.0 4 | device=PIC18F14K22 5 | [PATH_INFO] 6 | BuildDirPolicy=BuildDirIsProjectDir 7 | dir_src= 8 | dir_bin= 9 | dir_tmp= 10 | dir_sin= 11 | dir_inc= 12 | dir_lib=C:\Program Files\Microchip\mplabc18\v3.40\lib 13 | dir_lkr= 14 | [CAT_FILTERS] 15 | filter_src=*.asm;*.c 16 | filter_inc=*.h;*.inc 17 | filter_obj=*.o 18 | filter_lib=*.lib 19 | filter_lkr=*.lkr 20 | [CAT_SUBFOLDERS] 21 | subfolder_src= 22 | subfolder_inc= 23 | subfolder_obj= 24 | subfolder_lib= 25 | subfolder_lkr= 26 | [FILE_SUBFOLDERS] 27 | file_000=. 28 | [GENERATED_FILES] 29 | file_000=no 30 | [OTHER_FILES] 31 | file_000=no 32 | [FILE_INFO] 33 | file_000=CurrentTX.c 34 | [SUITE_INFO] 35 | suite_guid={5B7D72DD-9861-47BD-9F60-2BE967BF8416} 36 | suite_state=extended-mode 37 | [TOOL_SETTINGS] 38 | TS{DD2213A8-6310-47B1-8376-9430CDFC013F}= 39 | TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}=/m"$(BINDIR_)$(TARGETBASE).map" /w /o"$(BINDIR_)$(TARGETBASE).cof" 40 | TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}= 41 | TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}= 42 | [INSTRUMENTED_TRACE] 43 | enable=0 44 | transport=0 45 | format=0 46 | [CUSTOM_BUILD] 47 | Pre-Build= 48 | Pre-BuildEnabled=1 49 | Post-Build= 50 | Post-BuildEnabled=1 51 | -------------------------------------------------------------------------------- /src/EVSE_CTX.mcw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/src/EVSE_CTX.mcw -------------------------------------------------------------------------------- /src/EVSE_MAIN.mcp: -------------------------------------------------------------------------------- 1 | [HEADER] 2 | magic_cookie={66E99B07-E706-4689-9E80-9B2582898A13} 3 | file_version=1.0 4 | device=PIC18F25K22 5 | [PATH_INFO] 6 | BuildDirPolicy=BuildDirIsProjectDir 7 | dir_src= 8 | dir_bin= 9 | dir_tmp= 10 | dir_sin= 11 | dir_inc= 12 | dir_lib=C:\Program Files\Microchip\mplabc18\v3.40\lib 13 | dir_lkr= 14 | [CAT_FILTERS] 15 | filter_src=*.asm;*.c 16 | filter_inc=*.h;*.inc 17 | filter_obj=*.o 18 | filter_lib=*.lib 19 | filter_lkr=*.lkr 20 | [CAT_SUBFOLDERS] 21 | subfolder_src= 22 | subfolder_inc= 23 | subfolder_obj= 24 | subfolder_lib= 25 | subfolder_lkr= 26 | [FILE_SUBFOLDERS] 27 | file_000=. 28 | file_001=. 29 | file_002=. 30 | file_003=. 31 | [GENERATED_FILES] 32 | file_000=no 33 | file_001=no 34 | file_002=no 35 | file_003=no 36 | [OTHER_FILES] 37 | file_000=no 38 | file_001=no 39 | file_002=no 40 | file_003=no 41 | [FILE_INFO] 42 | file_000=EVSE.c 43 | file_001=LCD.c 44 | file_002=EVSE.h 45 | file_003=LCD.h 46 | [SUITE_INFO] 47 | suite_guid={5B7D72DD-9861-47BD-9F60-2BE967BF8416} 48 | suite_state=extended-mode 49 | [TOOL_SETTINGS] 50 | TS{DD2213A8-6310-47B1-8376-9430CDFC013F}= 51 | TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}=/m"$(BINDIR_)$(TARGETBASE).map" /w /o"$(BINDIR_)$(TARGETBASE).cof" 52 | TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}= 53 | TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}= 54 | [INSTRUMENTED_TRACE] 55 | enable=0 56 | transport=2 57 | format=0 58 | [CUSTOM_BUILD] 59 | Pre-Build= 60 | Pre-BuildEnabled=1 61 | Post-Build= 62 | Post-BuildEnabled=1 63 | -------------------------------------------------------------------------------- /src/EVSE_MAIN.mcs: -------------------------------------------------------------------------------- 1 | [Header] 2 | MagicCookie={0b13fe8c-dfe0-40eb-8900-6712719559a7} 3 | Version=1.0 4 | -------------------------------------------------------------------------------- /src/EVSE_MAIN.mcw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/src/EVSE_MAIN.mcw -------------------------------------------------------------------------------- /src/LCD.c: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; Date: 1 February 2016 4 | ; 5 | ; 6 | ; 7 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 8 | ; of this software and associated documentation files (the "Software"), to deal 9 | ; in the Software without restriction, including without limitation the rights 10 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | ; copies of the Software, and to permit persons to whom the Software is 12 | ; furnished to do so, subject to the following conditions: 13 | ; 14 | ; The above copyright notice and this permission notice shall be included in 15 | ; all copies or substantial portions of the Software. 16 | ; 17 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | ; THE SOFTWARE. 24 | */ 25 | 26 | #include "EVSE.h" 27 | #include "LCD.h" 28 | 29 | 30 | void LCD_write(unsigned char c) 31 | { 32 | unsigned char x,y; 33 | x= PORTB & 0xf0; 34 | PORTB=x | (0x0f & (c >>4)); 35 | PORTCbits.RC5 = 1; // LCD Enable 1 36 | PORTCbits.RC5 = 0; // LCD Enable 0 37 | delay(2); // changed from 1 to 2ms 38 | PORTB=x | (0x0f & c); 39 | PORTCbits.RC5 = 1; // LCD Enable 1 40 | PORTCbits.RC5 = 0; // LCD Enable 0 41 | delay(2); 42 | } 43 | 44 | void LCD_print(const far rom char *data ) // write string of data to LCD 45 | { 46 | PORTCbits.RC3 = 1; // LCD RS 47 | do 48 | { 49 | LCD_write(*data); 50 | } while (*++data); 51 | PORTCbits.RC3 = 0; // LCD RS 52 | } 53 | 54 | void LCD_print8(const far rom char *data ) // write 8 characters to LCD 55 | { 56 | unsigned char x=0; 57 | 58 | LCD_write(0x80); 59 | PORTCbits.RC3 = 1; // LCD RS 60 | do 61 | { 62 | LCD_write(*data++); 63 | } while (x++<8); 64 | PORTCbits.RC3 = 0; // LCD RS 65 | } 66 | 67 | void LCD_print_menu(const far rom char *data,char RowAdr ) // write string of data to LCD, with navigation arrows 68 | { 69 | LCD_write(RowAdr); // Set Row 70 | 71 | PORTCbits.RC3 = 1; // LCD RS 72 | if ((SubMenu && RowAdr==0xC0) || (!SubMenu && RowAdr==0x80)) LCD_write('<'); 73 | else LCD_write(' '); 74 | do 75 | { 76 | LCD_write(*data); 77 | } while (*++data); 78 | if ((SubMenu && RowAdr==0xC0) || (!SubMenu && RowAdr==0x80)) LCD_write('>'); 79 | else LCD_write(' '); 80 | PORTCbits.RC3 = 0; // LCD RS 81 | } 82 | 83 | void LCD_print_Amps(unsigned int Amps ) // write data to LCD 84 | { 85 | LCD_write(0xC0); 86 | PORTCbits.RC3 = 1; // LCD RS 87 | if (SubMenu) LCD_write('<'); 88 | else LCD_write(' '); 89 | LCD_write(' '); 90 | if (Amps>=100) 91 | { 92 | LCD_write( (unsigned char)(Amps/100)+0x30 ); 93 | Amps=Amps%100; 94 | } 95 | else LCD_write(' '); 96 | LCD_write( (unsigned char)(Amps/10)+0x30 ); 97 | LCD_write( (unsigned char)(Amps%10)+0x30 ); 98 | LCD_write('A'); 99 | LCD_write(' '); 100 | if (SubMenu) LCD_write('>'); 101 | else LCD_write(' '); 102 | PORTCbits.RC3 = 0; // LCD RS 103 | } 104 | 105 | 106 | void LCDHelp(void) // Display/Scroll helptext on LCD 107 | { 108 | unsigned char x; 109 | 110 | switch (LCDNav) 111 | { 112 | case MENU_CONFIG: 113 | x=strlenpgm(MenuConfig); 114 | LCD_print8(MenuConfig+LCDpos); 115 | break; 116 | case MENU_MODE: 117 | x=strlenpgm(MenuMode); 118 | LCD_print8(MenuMode+LCDpos); 119 | break; 120 | case MENU_LOADBL: 121 | x=strlenpgm(MenuLoadBl); 122 | LCD_print8(MenuLoadBl+LCDpos); 123 | break; 124 | case MENU_MAINS: 125 | x=strlenpgm(MenuMains); 126 | LCD_print8(MenuMains+LCDpos); 127 | break; 128 | case MENU_MAX: 129 | x=strlenpgm(MenuMax); 130 | LCD_print8(MenuMax+LCDpos); 131 | break; 132 | case MENU_MIN: 133 | x=strlenpgm(MenuMin); 134 | LCD_print8(MenuMin+LCDpos); 135 | break; 136 | case MENU_LOCK: 137 | x=strlenpgm(MenuLock); 138 | LCD_print8(MenuLock+LCDpos); 139 | break; 140 | case MENU_CABLE: 141 | x=strlenpgm(MenuCable); 142 | LCD_print8(MenuCable+LCDpos); 143 | break; 144 | case MENU_CAL: 145 | x=strlenpgm(MenuCal); 146 | LCD_print8(MenuCal+LCDpos); 147 | break; 148 | 149 | default: 150 | break; 151 | } 152 | if (LCDpos++==8) ScrollTimer=Timer-4000; 153 | else if (LCDpos > (x-8) ) 154 | { 155 | ScrollTimer=Timer-3000; 156 | LCDpos=8; 157 | } 158 | else ScrollTimer=Timer-4700; 159 | 160 | } 161 | 162 | 163 | 164 | // called once a second 165 | void LCD(void) 166 | { 167 | unsigned char x; 168 | 169 | if (LCDNav) 170 | { 171 | if (LCDTimer++ == 120) 172 | { 173 | LCDNav=0; // Exit Setup menu after 120 seconds. 174 | read_settings(); // don't save, but restore settings 175 | } 176 | else return; // disable LCD status messages when navigating LCD Menu 177 | } 178 | 179 | if (LCDTimer==10) LCDTimer=0; 180 | 181 | if (Error) 182 | { 183 | PORTCbits.RC0 = 1; // LCD backlight on 184 | 185 | if (Error==LESS_6A) 186 | { 187 | LCD_write(0x80); // address 00H / first row 188 | LCD_print((const far rom char *)"ERROR NO"); 189 | LCD_write(0xC0); // address 40H / second row 190 | LCD_print((const far rom char *)"CURRENT!"); 191 | } 192 | else if (Error==CT_NOCOMM) 193 | { 194 | LCD_write(0x80); // address 00H / first row 195 | LCD_print((const far rom char *)"ERROR NO"); 196 | LCD_write(0xC0); // address 40H / second row 197 | LCD_print((const far rom char *)"SER.COMM"); 198 | } 199 | else if (Error==TEMP_HIGH) 200 | { 201 | LCD_write(0x80); // address 00H / first row 202 | LCD_print((const far rom char *)"ERROR "); 203 | LCD_write(0xC0); // address 40H / second row 204 | LCD_print((const far rom char *)"HIGHTEMP"); 205 | } 206 | return; 207 | } 208 | 209 | 210 | if ((LCDTimer++>4) && Mode) 211 | { 212 | LCD_write(0x80); // address 00H / first row 213 | LCD_print((const far rom char *)"L1 L2 L3"); 214 | LCD_write(0xC0); // address 40H / second row 215 | PORTCbits.RC3 = 1; // LCD RS 216 | for (x=0; x<3 ;x++) 217 | { 218 | LCD_write( (unsigned char)(Irms[x]/100)+0x30 ); 219 | LCD_write( (unsigned char)((unsigned int)(Irms[x]/10)%10)+0x30 ); 220 | LCD_write(' '); 221 | } 222 | PORTCbits.RC3 = 0; // LCD RS 223 | 224 | } 225 | else if ((State == STATE_A) || (State == STATE_B)) 226 | { 227 | PORTCbits.RC0 = 0; // LCD backlight off 228 | 229 | LCD_write(0x80); // address 00H / first row 230 | LCD_print((const far rom char *)"READY TO"); 231 | LCD_write(0xC0); // address 40H / second row 232 | LCD_print((const far rom char *)"CHARGE"); 233 | PORTCbits.RC3 = 1; // LCD RS 234 | if (ChargeDelay>0) 235 | { 236 | LCD_write((ChargeDelay/10)+0x30 ); 237 | LCD_write((ChargeDelay%10)+0x30 ); 238 | } 239 | else 240 | { 241 | LCD_write(' '); 242 | LCD_write(' '); 243 | } 244 | PORTCbits.RC3 = 0; // LCD RS 245 | } 246 | else if (State == STATE_C) 247 | { 248 | PORTCbits.RC0 = 1; // LCD backlight on 249 | 250 | LCD_write(0x80); // address 00H / first row 251 | LCD_print((const far rom char *)"CHARGING"); 252 | LCD_write(0xC0); // address 40H / second row 253 | PORTCbits.RC3 = 1; // LCD RS 254 | LCD_write( (Balanced[0]/10)+0x30 ); 255 | LCD_write( (Balanced[0]%10)+0x30 ); 256 | LCD_write('A'); 257 | if (Mode) // Smart Mode? 258 | { 259 | LCD_write('('); 260 | LCD_write( (unsigned char)(MaxMains/10)+0x30 ); 261 | LCD_write( (unsigned char)(MaxMains%10)+0x30 ); 262 | LCD_write('A'); 263 | LCD_write(')'); 264 | } else LCD_print((const far rom char *)" "); // clear rest of row 265 | 266 | PORTCbits.RC3 = 0; 267 | } 268 | 269 | } 270 | 271 | 272 | //############################################################################################################################## 273 | // 10 CONFIG - Set to Fixed Cable or Type 2 Socket 274 | // 20 MODE - Set to Smart mode, or Normal EVSE mode 275 | // 25 LOADBL - Load Balance, set to Disable, Master or Slave 276 | // 30 MAINS - Set max MAINS Current (25-100) (Mode=Smart) 277 | // 40 MAX - Set MAX Charge Current for the EV (16-80) 278 | // 50 MIN - Set MIN Charge Current the EV will accept (Mode=Smart) 279 | // 60 LOCK - Cable lock Enable/disable 280 | // 70 CABLE - Set Fixed Cable Current limit 281 | // 80 CAL - Calibrate CT1 282 | // 90 EXIT - Exit Menu 283 | 284 | 285 | 286 | const far rom char StrConfig[] = "CONFIG"; 287 | const far rom char StrMode[] = " MODE "; 288 | const far rom char StrFixed[] = " Fixed"; 289 | const far rom char StrSocket[] = "Socket"; 290 | const far rom char StrSmart[] = " Smart"; 291 | const far rom char StrNormal[] = "Normal"; 292 | const far rom char StrMains[] = " MAINS"; 293 | const far rom char StrMax[] = " MAX "; 294 | const far rom char StrMin[] = " MIN "; 295 | const far rom char StrLock[] = " LOCK "; 296 | const far rom char StrSolenoid[] = "Soleno"; 297 | const far rom char StrMotor[] = "Motor "; 298 | const far rom char StrDisable[] = "Disabl"; 299 | const far rom char StrCable[] = " CABLE"; 300 | const far rom char StrCal[] = " CAL "; 301 | const far rom char StrLoadBl[] = "LOADBL"; 302 | const far rom char StrMaster[] = "Master"; 303 | const far rom char StrSlave1[] = "Slave1"; 304 | const far rom char StrSlave2[] = "Slave2"; 305 | const far rom char StrSlave3[] = "Slave3"; 306 | 307 | 308 | void LCDMenu(unsigned char Buttons) 309 | { 310 | static unsigned long ButtonTimer=0; 311 | static unsigned char ButtonRelease=0; // keeps track of LCD Menu Navigation 312 | static unsigned int CT1,CT1old; 313 | static double Iold; 314 | 315 | // Main Menu Navigation 316 | 317 | if ((LCDNav==0) && (Buttons==0x5) && (ButtonRelease==0)) // Button 2 pressed ? 318 | { 319 | LCDNav=1; // about to enter menu 320 | ButtonTimer=Timer; 321 | } 322 | else if (LCDNav==1 && ((ButtonTimer+2000) 323 | { 324 | LCDNav=MENU_CONFIG; // Main Menu entered 325 | PORTCbits.RC0 = 1; // LCD backlight on 326 | ButtonRelease=1; 327 | } 328 | else if ((LCDNav==1) && (Buttons==0x7)) // Button 2 released before entering menu? 329 | { 330 | LCDNav=0; 331 | LCD(); 332 | } 333 | else if ( (LCDNav>0) && ((LCDNav%10)==0) && (Buttons==0x3) && (ButtonRelease==0) ) // Button 1 > pressed 334 | { 335 | switch (LCDNav) 336 | { 337 | case MENU_CONFIG: 338 | if (SubMenu) 339 | { 340 | if (Config) Config=0; 341 | else Config=1; 342 | } 343 | else LCDNav=MENU_MODE; 344 | break; 345 | case MENU_MODE: 346 | if (SubMenu) 347 | { 348 | if (Mode) Mode=0; 349 | else Mode=1; 350 | } 351 | else LCDNav=MENU_LOADBL; 352 | break; 353 | case MENU_LOADBL: 354 | if (SubMenu) 355 | { 356 | if (LoadBl==4) LoadBl=0; // last menu item? goto first 357 | else LoadBl++; // goto next 358 | } 359 | else 360 | { 361 | if (Mode) LCDNav=MENU_MAINS; // Smart Mode? 362 | else LCDNav=MENU_MAX; 363 | } 364 | break; 365 | case MENU_MAINS: 366 | if (SubMenu) 367 | { 368 | MaxMains++; // Set new MaxMains 369 | if (MaxMains>100) MaxMains=100; // Max 100A 370 | } 371 | else LCDNav=MENU_MAX; 372 | break; 373 | case MENU_MAX: 374 | if (SubMenu) 375 | { 376 | MaxCurrent++; // Set new MaxCurrent 377 | if (MaxCurrent>80) MaxCurrent=80; // Max 80A 378 | } 379 | else 380 | { 381 | if (Mode) LCDNav=MENU_MIN; // Smart Mode? 382 | else if (Config) LCDNav=MENU_CABLE; // Cable Configuration, go to Cable Current 383 | else LCDNav=MENU_LOCK; // Fixed Cable, use the lock 384 | } 385 | break; 386 | case MENU_MIN: 387 | if (SubMenu) 388 | { 389 | MinCurrent++; // Set new MinCurrent 390 | if (MinCurrent>16) MinCurrent=16; // Max 16A 391 | } 392 | else 393 | { 394 | if (Config) LCDNav=MENU_CABLE; // Cable Configuration, go to Cable Current 395 | else LCDNav=MENU_LOCK; // Fixed Cable, use the lock 396 | } 397 | break; 398 | case MENU_LOCK: 399 | if (SubMenu) 400 | { 401 | if (Lock==2) Lock=0; 402 | else Lock++; 403 | break; 404 | } 405 | case MENU_CABLE: 406 | if (SubMenu) 407 | { 408 | CableLimit++; // Set new CableLimit 409 | if (CableLimit>80) CableLimit=80; // Max 80A 410 | } 411 | else 412 | { 413 | if (Mode) LCDNav=MENU_CAL; 414 | else LCDNav=MENU_EXIT; 415 | } 416 | break; 417 | case MENU_CAL: 418 | if (SubMenu) 419 | { 420 | if (CT1>=100 && CT1<1000) CT1++; // Increase CT1 measurement value by 0.1A 421 | // Max 99.9A 422 | } 423 | else 424 | { 425 | LCDNav=MENU_EXIT; 426 | } 427 | break; 428 | case MENU_EXIT: 429 | LCDNav=MENU_CONFIG; 430 | default: 431 | break; 432 | } 433 | ButtonRelease=1; 434 | } 435 | else if ( (LCDNav>0) && ((LCDNav%10)==0) && (Buttons==0x6) && (ButtonRelease==0) ) // Button 3 < pressed 436 | { 437 | switch (LCDNav) 438 | { 439 | case MENU_EXIT: 440 | if (Mode) LCDNav=MENU_CAL; // Smart Mode? Goto Cal CT1 441 | else if (Config) LCDNav=MENU_CABLE; // Cable Configuration, go to Cable Current 442 | else LCDNav=MENU_LOCK; // Fixed Cable, use the lock 443 | break; 444 | case MENU_CAL: 445 | if (SubMenu) 446 | { 447 | if (CT1>100) CT1--; // Min 10.0A 448 | } 449 | else 450 | { 451 | if (Config) LCDNav=MENU_CABLE; // Cable Configuration, go to Cable Current 452 | else LCDNav=MENU_LOCK; // Fixed Cable, use the lock 453 | } 454 | break; 455 | case MENU_CABLE: 456 | if (SubMenu) 457 | { 458 | CableLimit--; // Set new CableLimit 459 | if (CableLimit<13) CableLimit=13; // Min 13A 460 | break; 461 | } 462 | case MENU_LOCK: 463 | if (SubMenu) 464 | { 465 | if (Lock==0) Lock=2; 466 | else Lock--; 467 | } 468 | else 469 | { 470 | if (Mode) LCDNav=MENU_MIN; // Smart Mode? 471 | else LCDNav=MENU_MAX; 472 | } 473 | break; 474 | case MENU_MIN: 475 | if (SubMenu) 476 | { 477 | MinCurrent--; // Set new MinCurrent 478 | if (MinCurrent<6) MinCurrent=6; // Min 6A 479 | } 480 | else LCDNav=MENU_MAX; 481 | break; 482 | case MENU_MAX: 483 | if (SubMenu) 484 | { 485 | MaxCurrent--; // Set new MaxCurrent 486 | if (MaxCurrent<10) MaxCurrent=10; // Min 10A 487 | } 488 | else 489 | { 490 | if (Mode) LCDNav=MENU_MAINS; // Smart Mode? 491 | else LCDNav=MENU_LOADBL; 492 | } 493 | break; 494 | case MENU_MAINS: 495 | if (SubMenu) 496 | { 497 | MaxMains--; // Set new MaxMains 498 | if (MaxMains<25) MaxMains=25; // Min 25A 499 | } else LCDNav=MENU_LOADBL; 500 | break; 501 | case MENU_LOADBL: 502 | if (SubMenu) 503 | { 504 | if (LoadBl==0) LoadBl=4; // first menu item? goto last 505 | else LoadBl--; // goto previous 506 | } 507 | else LCDNav=MENU_MODE; 508 | break; 509 | case MENU_MODE: 510 | if (SubMenu) 511 | { 512 | if (Mode) Mode=0; 513 | else Mode=1; 514 | } 515 | else LCDNav=MENU_CONFIG; 516 | break; 517 | case MENU_CONFIG: 518 | if (SubMenu) 519 | { 520 | if (Config) Config=0; 521 | else Config=1; 522 | } 523 | else LCDNav=MENU_EXIT; 524 | default: 525 | break; 526 | } 527 | ButtonRelease=1; 528 | } 529 | else if (LCDNav>=10 && Buttons==0x5 && ButtonRelease==0) // Button 2 pressed? 530 | { 531 | if (SubMenu) // Are we in Submenu? 532 | { 533 | SubMenu=0; // yes, exit Submenu 534 | if (LCDNav==MENU_CAL) // Exit CT1 calibration? 535 | { 536 | if (CT1!=CT1old) // did the value change? 537 | { 538 | Iold=(double)(CT1old/ICal); 539 | ICal=(double)(CT1/Iold); // Calculate new Calibration value 540 | Irms[0]=CT1; // Set the Irms value, so the LCD update is instant 541 | } 542 | } 543 | } 544 | else // We are curently not in Submenu. 545 | { 546 | SubMenu=1; // Enter Submenu now 547 | if (LCDNav==MENU_CAL) // CT1 calibration start 548 | { 549 | CT1=(unsigned int)Irms[0]; // make working copy of CT1 value 550 | CT1old=CT1; // and a backup 551 | } 552 | else if (LCDNav==MENU_EXIT) // Exit Main Menu 553 | { 554 | LCDNav=0; 555 | SubMenu=0; 556 | PORTCbits.RC0 = 0; // LCD backlight off 557 | Error=NO_ERROR; // Clear Errors 558 | write_settings(); // Write to eeprom 559 | LCD(); 560 | } 561 | } 562 | ButtonRelease=1; 563 | } 564 | else if (Buttons==0x7) // Buttons released 565 | { 566 | ButtonRelease=0; 567 | } 568 | 569 | // 570 | // here we update the LCD 571 | // 572 | if (LCDNav==1) 573 | { 574 | LCD_write(0x80); 575 | LCD_print((const far rom char *)"Hold 2s "); 576 | LCD_write(0xC0); 577 | LCD_print((const far rom char *)"for Menu"); 578 | } 579 | else if (LCDNav==MENU_CONFIG) 580 | { 581 | LCD_print_menu(StrConfig,0x80); // add navigation arrows on both sides 582 | if (Config) LCD_print_menu(StrFixed,0xC0); // add spaces on both sides 583 | else LCD_print_menu(StrSocket,0xC0); 584 | } 585 | else if (LCDNav==MENU_MODE) 586 | { 587 | LCD_print_menu(StrMode,0x80); 588 | if (Mode) LCD_print_menu(StrSmart,0xC0); 589 | else LCD_print_menu(StrNormal,0xC0); 590 | } 591 | else if (LCDNav==MENU_LOADBL) 592 | { 593 | LCD_print_menu(StrLoadBl,0x80); 594 | if (LoadBl==0) LCD_print_menu(StrDisable,0xC0); 595 | else if (LoadBl==1) LCD_print_menu(StrMaster,0xC0); 596 | else if (LoadBl==2) LCD_print_menu(StrSlave1,0xC0); 597 | else if (LoadBl==3) LCD_print_menu(StrSlave2,0xC0); 598 | else LCD_print_menu(StrSlave3,0xC0); 599 | } 600 | else if (LCDNav==MENU_MAINS) 601 | { 602 | LCD_print_menu(StrMains,0x80); 603 | LCD_print_Amps(MaxMains); 604 | } 605 | else if (LCDNav==MENU_MAX) 606 | { 607 | LCD_print_menu(StrMax,0x80); 608 | LCD_print_Amps(MaxCurrent); 609 | } 610 | else if (LCDNav==MENU_MIN) 611 | { 612 | LCD_print_menu(StrMin,0x80); 613 | LCD_print_Amps(MinCurrent); 614 | } 615 | else if (LCDNav==MENU_LOCK) 616 | { 617 | LCD_print_menu(StrLock,0x80); 618 | LCD_write(0xC0); 619 | if (Lock==1) LCD_print_menu(StrSolenoid,0xC0); 620 | else if (Lock==2) LCD_print_menu(StrMotor,0xC0); 621 | else LCD_print_menu(StrDisable,0xC0); 622 | } 623 | else if (LCDNav==MENU_CABLE) 624 | { 625 | LCD_print_menu(StrCable,0x80); 626 | LCD_print_Amps(CableLimit); 627 | } 628 | else if (LCDNav==MENU_CAL) 629 | { 630 | LCD_print_menu(StrCal,0x80); 631 | LCD_write(0xC0); 632 | PORTCbits.RC3 = 1; // LCD RS 633 | if (SubMenu) 634 | { 635 | LCD_write('<'); 636 | LCD_write(' '); 637 | LCD_write( (unsigned char)(CT1/100)+0x30 ); 638 | LCD_write( (unsigned char)(CT1%100)/10+0x30 ); 639 | LCD_write('.'); 640 | LCD_write( (unsigned char)(CT1%10)+0x30 ); 641 | LCD_write('A'); 642 | LCD_write('>'); 643 | } 644 | else 645 | { 646 | LCD_write(' '); 647 | LCD_write(' '); 648 | LCD_write( (unsigned char)((unsigned int)Irms[0]/100)+0x30 ); 649 | LCD_write( (unsigned char)((unsigned int)Irms[0]%100/10)+0x30 ); 650 | LCD_write('.'); 651 | LCD_write( (unsigned char)((unsigned int)Irms[0]%10)+0x30 ); 652 | LCD_write('A'); 653 | LCD_write(' '); 654 | } 655 | PORTCbits.RC3 = 0; // LCD RS 656 | } 657 | else if (LCDNav==MENU_EXIT) 658 | { 659 | LCD_write(0x80); 660 | LCD_print((const far rom char *)"< EXIT >"); 661 | LCD_write(0xC0); 662 | LCD_print((const far rom char *)" MENU "); 663 | } 664 | 665 | ScrollTimer=Timer; // reset timer for HelpMenu text 666 | LCDpos=8; // reset position of scrolling text 667 | OldButtonState=Buttons; 668 | LCDTimer=0; 669 | 670 | } 671 | 672 | 673 | 674 | void LCD_init(void) // initialize the LCD 675 | { 676 | unsigned char x; 677 | 678 | PORTCbits.RC0 = 0; // LCD backlight off 679 | 680 | PORTCbits.RC5 = 0; // LCD Enable 0 681 | PORTCbits.RC4 = 0; // LCD R/W 682 | PORTCbits.RC3 = 0; // LCD RS 683 | 684 | x=PORTB & 0xf0; 685 | PORTB=x |(0x0f & 0x3); 686 | PORTCbits.RC5 = 1; // LCD Enable 1 687 | PORTCbits.RC5 = 0; // LCD Enable 0 688 | delay(5); // wait 5ms 689 | 690 | PORTCbits.RC5 = 1; // LCD Enable 1 691 | PORTCbits.RC5 = 0; // LCD Enable 0 692 | delay(1); // wait 1ms 693 | 694 | PORTCbits.RC5 = 1; // LCD Enable 1 695 | PORTCbits.RC5 = 0; // LCD Enable 0 696 | delay(1); // wait 1ms 697 | 698 | PORTB=x |(0x0f & 0x2); 699 | PORTCbits.RC5 = 1; // LCD Enable 1 700 | PORTCbits.RC5 = 0; // LCD Enable 0 701 | delay(1); // wait 1ms 702 | 703 | LCD_write(0x28); 704 | LCD_write(0x08); // display off 705 | LCD_write(0x01); // display clear 706 | delay(5); 707 | LCD_write(0x06); // entry mode set 708 | // LCD_write(0x0D); // display on/ blinking on 709 | LCD_write(0x0C); // display on/ blinking off 710 | 711 | LCD_write(0x80); // address 00H / first row 712 | LCD_print((const far rom char *)"Version "); 713 | LCD_write(0xC0); // address 40H / second row 714 | LCD_print((const far rom char *)VERSION); 715 | LCD_print((const far rom char *)" "); 716 | } 717 | 718 | -------------------------------------------------------------------------------- /src/LCD.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; Date: 1 February 2016 4 | ; 5 | ; 6 | ; 7 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 8 | ; of this software and associated documentation files (the "Software"), to deal 9 | ; in the Software without restriction, including without limitation the rights 10 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | ; copies of the Software, and to permit persons to whom the Software is 12 | ; furnished to do so, subject to the following conditions: 13 | ; 14 | ; The above copyright notice and this permission notice shall be included in 15 | ; all copies or substantial portions of the Software. 16 | ; 17 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | ; THE SOFTWARE. 24 | */ 25 | 26 | 27 | #ifndef __LCD_H 28 | #define __LCD_H 29 | 30 | void LCD_write(unsigned char c); 31 | void LCD_print(const far rom char *data ); 32 | void LCD_print8(const far rom char *data ); 33 | void LCD_print_menu(const far rom char *data,char RowAdr ); 34 | void LCD_print_Amps(unsigned int Amps ); 35 | 36 | extern void LCDHelp(void); 37 | extern void LCD(void); 38 | extern void LCDMenu(unsigned char Buttons); 39 | extern void LCD_init(void); 40 | 41 | #endif // #ifndef __LCD_H -------------------------------------------------------------------------------- /version2/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignoring files according to http://microchip.wikidot.com/faq:72 2 | /SmartEVSE2.X/build/ 3 | #Ignoring private Makefiles, to create them open the MPLAB IDE or use the C:\Program Files (x86)\Microchip\MPLABX\\mplab_ide\bin\prjMakefilesGenerator.bat script 4 | /SmartEVSE2.X/nbproject/Makefile-* 5 | /SmartEVSE2.X/nbproject/Package-* 6 | /SmartEVSE2.X/nbproject/private/ -------------------------------------------------------------------------------- /version2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | SmartEVSE2.X/bootloader.c 3 | SmartEVSE2.X/EVSE.c 4 | SmartEVSE2.X/GLCD.c 5 | SmartEVSE2.X/modbus.c 6 | SmartEVSE2.X/OneWire.c 7 | SmartEVSE2.X/utils.c 8 | ) 9 | 10 | add_executable(version2 ${SOURCES}) 11 | target_include_directories(version2 PRIVATE SmartEVSE2.X/) 12 | 13 | target_link_libraries(version2) 14 | -------------------------------------------------------------------------------- /version2/README.md: -------------------------------------------------------------------------------- 1 | SmartEVSE v2 2 | ========= 3 | 4 | Version 2 uses a PIC 18F26K22 microcontroller, Graphic 128x64 LCD. 5 | for compiling, MPLAB X IDE is used together with the XC8 compiler. 6 | 7 | set XC8 linker memory model settings to: double 32 bit, float 32 bit 8 | extended instruction set is not used on XC8 9 | 10 | - SmartEVSE2.X folder contains the sourcecode for the PIC microcontroller 11 | - eagle folder holds the pcb layouts (eagle 6.6) 12 | - manual folder has the latest manual. 13 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/EVSE.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | #ifndef __EVSE_MAIN 26 | #define __EVSE_MAIN 27 | 28 | #include 29 | 30 | #define _XTAL_FREQ 16000000L // 16Mhz Xtal frequency 31 | 32 | #define LOG_DEBUG 3 // Debug messages including measurement data 33 | #define LOG_INFO 2 // Information messages without measurement data 34 | #define LOG_WARN 1 // Warning or error messages 35 | #define LOG_OFF 0 36 | 37 | #define LOG_EVSE LOG_INFO // Default: LOG_INFO 38 | #define LOG_MODBUS LOG_WARN // Default: LOG_WARN 39 | 40 | #define VERSION "2.20" // SmartEVSE software version 41 | #define TRANSFORMER_COMP 100 // Current calculation compensation option for use with 230V-400V transformers, 42 | // where the primary (MAINS) current is 1.73 times the secondary (EVSE) current. 43 | // set to 100 for normal use, and to 173 for use with a transformer. 44 | 45 | //#define SPECIAL // if defined, it will modify program so that some menu options are not shown 46 | // should be undefined by default 47 | 48 | #define ICAL 1024 // Irms Calibration value (for Current transformers) 49 | #define MAX_MAINS 25 // max Current the Mains connection can supply 50 | #define MAX_CURRENT 13 // max charging Current for the EV 51 | #define MIN_CURRENT 6 // minimum Current the EV will accept 52 | #define MODE 0 // Normal EVSE mode 53 | #define LOCK 0 // No Cable lock 54 | #define MAX_CIRCUIT 16 // Max current of the EVSE circuit breaker 55 | #define CONFIG 0 // Configuration: 0= TYPE 2 socket, 1= Fixed Cable 56 | #define LOADBL 0 // Load Balancing disabled 57 | #define SWITCH 0 // 0= Charge on plugin, 1= (Push)Button on IO2 is used to Start/Stop charging. 58 | #define RC_MON 0 // Residual Current Monitoring on IO3. Disabled=0, RCM14=1 59 | #define CHARGEDELAY 60 // Seconds to wait after overcurrent, before trying again 60 | #define BACKLIGHT 60 // Seconds delay for the LCD backlight to turn off. 61 | #define START_CURRENT 4 // Start charging when surplus current on one phase exceeds 4A (Solar) 62 | #define STOP_TIME 10 // Stop charging after 10 minutes at MIN charge current (Solar) 63 | #define IMPORT_CURRENT 0 // Allow the use of grid power when solar charging (Amps) 64 | #define MAINS_METER 1 // Mains Meter, 1= Sensorbox, 2=Phoenix, 3= Finder, 4= Eastron, 5=Custom 65 | #ifdef SPECIAL 66 | #define GRID 1 // Grid, 0= 4-Wire CW, 1= 4-Wire CCW, 2= 3-Wire CW, 3= 3-Wire CCW 67 | #else 68 | #define GRID 0 // Grid, 0= 4-Wire CW, 1= 4-Wire CCW, 2= 3-Wire CW, 3= 3-Wire CCW 69 | #endif 70 | #define MAINS_METER_ADDRESS 10 71 | #define MAINS_METER_MEASURE 0 72 | #define PV_METER 0 73 | #define PV_METER_ADDRESS 11 74 | #define EV_METER 0 75 | #define EV_METER_ADDRESS 12 76 | #define MIN_METER_ADDRESS 10 77 | #define MAX_METER_ADDRESS 247 78 | #define EMCUSTOM_ENDIANESS 0 79 | #define EMCUSTOM_ISDOUBLE 0 80 | #define EMCUSTOM_UREGISTER 0 81 | #define EMCUSTOM_UDIVISOR 8 82 | #define EMCUSTOM_IREGISTER 0 83 | #define EMCUSTOM_IDIVISOR 8 84 | #define EMCUSTOM_PREGISTER 0 85 | #define EMCUSTOM_PDIVISOR 8 86 | #define EMCUSTOM_EREGISTER 0 87 | #define EMCUSTOM_EDIVISOR 8 88 | #define RFID_READER 0 89 | 90 | 91 | // Mode settings 92 | #define MODE_NORMAL 0 93 | #define MODE_SMART 1 94 | #define MODE_SOLAR 2 95 | 96 | #define ACK_TIMEOUT 1000 // 1000ms timeout 97 | #define NR_EVSES 8 98 | #define BROADCAST_ADR 0x09 99 | 100 | #define STATE_A 0 // A Vehicle not connected 101 | #define STATE_B 1 // B Vehicle connected / not ready to accept energy 102 | #define STATE_C 2 // C Vehicle connected / ready to accept energy / ventilation not required 103 | #define STATE_D 3 // D Vehicle connected / ready to accept energy / ventilation required (not implemented) 104 | #define STATE_COMM_B 4 // E State change request A->B (set by node) 105 | #define STATE_COMM_B_OK 5 // F State change A->B OK (set by master) 106 | #define STATE_COMM_C 6 // G State change request B->C (set by node) 107 | #define STATE_COMM_C_OK 7 // H State change B->C OK (set by master) 108 | #define STATE_ACTSTART 8 // I Activation mode in progress 109 | #define NOSTATE 255 110 | 111 | #define STATE_CB 10 // Test code state 112 | 113 | #define PILOT_12V 1 114 | #define PILOT_9V 2 115 | #define PILOT_6V 3 116 | #define PILOT_DIODE 4 117 | #define PILOT_NOK 0 118 | 119 | #ifdef SPECIAL 120 | #define STATE_A_TO_C PILOT_6V // Set to PILOT_6V to allow switching from STATE A to STATE C (without STATE B) 121 | #else 122 | #define STATE_A_TO_C PILOT_9V // default is PILOT_9V 123 | #endif 124 | 125 | #define NO_ERROR 0 126 | #define LESS_6A 1 127 | #define CT_NOCOMM 2 128 | #define TEMP_HIGH 4 129 | #define UNUSED 8 // Unused 130 | #define RCD_TRIPPED 16 // RCD tripped. >6mA DC residual current detected. 131 | #define NO_SUN 32 132 | #define Test_IO 64 133 | #define BL_FLASH 128 134 | 135 | #define SOLENOID_LOCK {LATAbits.LATA4 = 1;LATAbits.LATA5 = 0;} 136 | #define SOLENOID_UNLOCK {LATAbits.LATA4 = 0;LATAbits.LATA5 = 1;} 137 | #define SOLENOID_OFF {LATAbits.LATA4 = 1;LATAbits.LATA5 = 1;} // both outputs 12V 138 | #define SOLENOID_0V {LATAbits.LATA4 = 0;LATAbits.LATA5 = 0;} // both outputs 0V 139 | 140 | #define CONTACTOR_OFF LATBbits.LATB4 = 0; // Contactor OFF 141 | #define CONTACTOR_ON LATBbits.LATB4 = 1; // Contactor ON 142 | 143 | #define BACKLIGHT_OFF LATAbits.LATA3 = 0; // LCD Backlight OFF 144 | #define BACKLIGHT_ON LATAbits.LATA3 = 1; // LCD Backlight ON 145 | 146 | #define ONEWIRE_LOW {LATBbits.LATB2 = 0;TRISBbits.TRISB2 = 0;} // RB2 set to 0, set to output (driven low) 147 | #define ONEWIRE_HIGH {LATBbits.LATB2 = 1;TRISBbits.TRISB2 = 0;} // RB2 set to 1, set to output (driven low) 148 | #define ONEWIRE_FLOATHIGH {TRISBbits.TRISB2 = 1;} // RB2 input (floating high) 149 | 150 | #define MODBUS_INVALID 0 151 | #define MODBUS_OK 1 152 | #define MODBUS_REQUEST 2 153 | #define MODBUS_RESPONSE 3 154 | #define MODBUS_EXCEPTION 4 155 | 156 | #define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS 0x02 157 | #define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE 0x03 158 | 159 | #define MODBUS_EVSE_STATUS_START 0xA0 160 | #define MODBUS_EVSE_STATUS_END 0xAB 161 | #define MODBUS_EVSE_CONFIG_START 0xC0 162 | #define MODBUS_EVSE_CONFIG_END 0xCC 163 | #define MODBUS_SYS_CONFIG_START 0xE0 164 | #define MODBUS_SYS_CONFIG_END 0xF3 165 | 166 | // EVSE status 167 | #define STATUS_STATE 64 // 0xA0: State 168 | #define STATUS_ERROR 65 // 0xA1: Error 169 | #define STATUS_MAX 66 // 0xA2: Maximum charging current 170 | #define STATUS_MIN 67 // 0xA3: Minimum charging current 171 | #define STATUS_PHASE_COUNT 68 // 0xA4: Number of used phases (ToDo) 172 | #define STATUS_REAL_CURRENT 69 // 0xA5: Real charging current (ToDo) 173 | #define STATUS_CURRENT 70 // 0xA6: Charging current (A * 10) 174 | #define STATUS_ACCESS 71 // 0xA7: Access bit 175 | #define STATUS_MODE 72 // 0xA8: EVSE Mode 176 | #define STATUS_EVMETER 73 // 0xA9: Type of EV electric meter 177 | #define STATUS_EVMETERADDRESS 74 // 0xAA: Address of EV electric meter 178 | #define STATUS_SOLAR_TIMER 75 // 0xAB: Solar Timer 179 | 180 | // EVSE configuration 181 | #define MENU_ENTER 1 182 | #define MENU_CONFIG 2 // 0xC0: Configuration 183 | #define MENU_LOADBL 3 // 0xC1: Load Balance 184 | #define MENU_MIN 4 // 0xC2: MIN Charge Current the EV will accept 185 | #define MENU_MAX 5 // 0xC3: MAX Charge Current for this EVSE 186 | #define MENU_LOCK 6 // 0xC4: Cable lock 187 | #define MENU_START 7 // 0xC5: Surplus energy start Current 188 | #define MENU_STOP 8 // 0xC6: Stop solar charging at 6A after this time 189 | #define MENU_SWITCH 9 // 0xC7: External Start/Stop button 190 | #define MENU_RCMON 10 // 0xC8: Residual Current Monitor 191 | #define MENU_IMPORT 11 // 0xC9: Allow grid power when solar charging 192 | #define MENU_RFIDREADER 12 // 0xCA: Use RFID reader 193 | #define MENU_EVMETER 13 // 0xCB: Type of EV electric meter 194 | #define MENU_EVMETERADDRESS 14 // 0xCC: Address of EV electric meter 195 | 196 | // System configuration (same on all SmartEVSE in a LoadBalancing setup) 197 | #define MENU_CIRCUIT 15 // 0xE0: EVSE Circuit max Current 198 | #define MENU_MODE 16 // 0xE1: EVSE mode 199 | #define MENU_MAINS 17 // 0xE2: Max Mains Current 200 | #define MENU_CAL 18 // 0xE3: CT calibration value 201 | #define MENU_MAINSMETER 19 // 0xE4: Type of Mains electric meter 202 | #define MENU_MAINSMETERADDRESS 20 // 0xE5: Address of Mains electric meter 203 | #define MENU_MAINSMETERMEASURE 21 // 0xE6: What does Mains electric meter measure 204 | #define MENU_PVMETER 22 // 0xE7: Type of PV electric meter 205 | #define MENU_PVMETERADDRESS 23 // 0xE8: Address of PV electric meter 206 | #define MENU_EMCUSTOM_ENDIANESS 24 // 0xE9: Byte order of custom electric meter 207 | #define MENU_EMCUSTOM_IREGISTER 25 // 0xEA: Register for Current (A) of custom electric meter 208 | #define MENU_EMCUSTOM_IDIVISOR 26 // 0xEB: Divisor for Current (A) of custom electric meter (10^x) 209 | #define MENU_EMCUSTOM_UREGISTER 27 // 0xEC: Register for Voltage (V) of custom electric meter 210 | #define MENU_EMCUSTOM_UDIVISOR 28 // 0xED: Divisor for Voltage (V) of custom electric meter (10^x) 211 | #define MENU_EMCUSTOM_PREGISTER 29 // 0xEE: Register for Power (W) of custom electric meter 212 | #define MENU_EMCUSTOM_PDIVISOR 30 // 0xEF: Divisor for Power (W) of custom electric meter (10^x) 213 | #define MENU_EMCUSTOM_EREGISTER 31 // 0xF0: Register for Energy (kWh) of custom electric meter 214 | #define MENU_EMCUSTOM_EDIVISOR 32 // 0xF1: Divisor for Energy (kWh) of custom electric meter (10^x) 215 | #define MENU_GRID 33 // 0xF2: Grid type to which the Sensorbox is connected 216 | #define MENU_EMCUSTOM_ISDOUBLE 34 // 0xF3: Data type of custom electric meter 217 | #define MENU_EXIT 35 218 | 219 | #define MENU_STATE 50 220 | 221 | #if LOG_EVSE >= LOG_DEBUG 222 | #define LOG_DEBUG_EVSE 223 | #endif 224 | #if LOG_EVSE >= LOG_INFO 225 | #define LOG_INFO_EVSE 226 | #endif 227 | #if LOG_EVSE >= LOG_WARN 228 | #define LOG_WARN_EVSE 229 | #endif 230 | #if LOG_MODBUS >= LOG_DEBUG 231 | #define LOG_DEBUG_MODBUS 232 | #endif 233 | #if LOG_MODBUS >= LOG_INFO 234 | #define LOG_INFO_MODBUS 235 | #endif 236 | #if LOG_MODBUS >= LOG_WARN 237 | #define LOG_WARN_MODBUS 238 | #endif 239 | 240 | #define _RSTB_0 LATCbits.LATC4 = 0; 241 | #define _RSTB_1 LATCbits.LATC4 = 1; 242 | #define _A0_0 LATCbits.LATC0 = 0; 243 | #define _A0_1 LATCbits.LATC0 = 1; 244 | 245 | #define EM_SENSORBOX 1 // Mains meter types 246 | #define EM_PHOENIX_CONTACT 2 247 | #define EM_FINDER 3 248 | #define EM_EASTRON 4 249 | #define EM_ABB 5 250 | #define EM_CUSTOM 6 251 | 252 | #define ENDIANESS_LBF_LWF 0 253 | #define ENDIANESS_LBF_HWF 1 254 | #define ENDIANESS_HBF_LWF 2 255 | #define ENDIANESS_HBF_HWF 3 256 | 257 | extern char GLCDbuf[512]; // GLCD buffer (half of the display) 258 | 259 | extern unsigned int MaxMains; // Max Mains Amps (hard limit, limited by the MAINS connection) 260 | extern unsigned int MaxCurrent; // Max Charge current 261 | extern unsigned int MinCurrent; // Minimal current the EV is happy with 262 | extern unsigned long ICal; // CT calibration value 263 | extern char Mode; // EVSE mode 264 | extern char Lock; // Cable lock enable/disable 265 | extern unsigned int MaxCircuit; // Max current of the EVSE circuit 266 | extern char Config; // Configuration (Fixed Cable or Type 2 Socket) 267 | extern char LoadBl; // Load Balance Setting (Disable, Master or Node) 268 | extern char Switch; // Allow access to EVSE with button on IO2 269 | extern char RCmon; // Residual Current monitor 270 | extern char Grid; 271 | extern unsigned int StartCurrent; 272 | extern unsigned int StopTime; 273 | extern unsigned int ImportCurrent; 274 | extern unsigned char MainsMeter; // Type of Mains electric meter (0: Disabled / Constants EM_*) 275 | extern unsigned char MainsMeterAddress; 276 | extern unsigned char MainsMeterMeasure; // What does Mains electric meter measure (0: Mains (Home+EVSE+PV) / 1: Home+EVSE / 2: Home) 277 | extern unsigned char PVMeter; // Type of PV electric meter (0: Disabled / Constants EM_*) 278 | extern unsigned char PVMeterAddress; 279 | extern unsigned char EVMeter; // Type of EV electric meter (0: Disabled / Constants EM_*) 280 | extern unsigned char EVMeterAddress; 281 | extern unsigned char RFIDReader; 282 | 283 | extern signed int Irms[3]; // Momentary current per Phase (Amps *10) (23 = 2.3A) 284 | 285 | extern unsigned char State; 286 | extern unsigned char Error; 287 | extern unsigned char NextState; 288 | 289 | extern unsigned int MaxCapacity; // Cable limit (Amps)(limited by the wire in the charge cable, set automatically, or manually if Config=Fixed Cable) 290 | extern signed int Imeasured; // Max of all CT inputs (Amps * 10) (23 = 2.3A) 291 | extern signed int Isum; 292 | extern unsigned int Balanced[NR_EVSES]; // Amps value per EVSE 293 | 294 | extern unsigned char RX1byte; 295 | extern unsigned char idx2, ISR2FLAG; 296 | extern unsigned char menu; 297 | extern unsigned long Timer; // mS counter 298 | extern unsigned int ChargeTimer; // seconds counter 299 | extern unsigned char LCDTimer; 300 | extern unsigned char BacklightTimer; // remaining seconds the LCD backlight is active 301 | extern signed char TempEVSE; // Temperature EVSE in deg C (0-125) 302 | extern unsigned char ButtonState; // Holds latest push Buttons state (LSB 2:0) 303 | extern unsigned char OldButtonState; // Holds previous push Buttons state (LSB 2:0) 304 | extern unsigned char LCDNav; 305 | extern unsigned char SubMenu; 306 | extern unsigned long ScrollTimer; 307 | extern unsigned char LCDpos; 308 | extern unsigned char ChargeDelay; // Delays charging at least 60 seconds in case of not enough current available. 309 | extern unsigned char TestState; 310 | extern unsigned char unlockMagic; 311 | extern unsigned char unlock55; // unlock bytes set to 0 to prevent flash write at por 312 | extern unsigned char unlockAA; // unlock bytes set to 0 to prevent flash write at por 313 | extern unsigned char Access_bit; 314 | extern unsigned char GridActive; // When the CT's are used on Sensorbox2, it enables the GRID menu option. 315 | extern unsigned char CalActive; // When the CT's are used on Sensorbox(1.5 or 2), it enables the CAL menu option. 316 | extern unsigned int Iuncal; 317 | extern unsigned int SolarStopTimer; 318 | extern signed long EnergyCharged; 319 | extern signed long PowerMeasured; 320 | extern unsigned char RFIDstatus; 321 | 322 | extern unsigned char MenuItems[MENU_EXIT]; 323 | 324 | const far struct { 325 | char Key[8]; 326 | char LCD[9]; 327 | char Desc[52]; 328 | unsigned int Min; 329 | unsigned int Max; 330 | unsigned int Default; 331 | } MenuStr[MENU_EXIT + 1] = { 332 | {"", "", "Not in menu", 0, 0, 0}, 333 | {"", "", "Hold 2 sec", 0, 0, 0}, 334 | {"CONFIG", "CONFIG", "Set to Fixed Cable or Type 2 Socket", 0, 1, CONFIG}, 335 | {"LOADBL", "LOAD BAL", "Set Load Balancing mode for 2-8 SmartEVSEs", 0, NR_EVSES, LOADBL}, 336 | {"MIN", "MIN", "Set MIN Charge Current the EV will accept", 6, 16, MIN_CURRENT}, 337 | {"MAX", "MAX", "Set MAX Charge Current for this EVSE", 6, 80, MAX_CURRENT}, 338 | {"LOCK", "LOCK", "Cable locking actuator type", 0, 2, LOCK}, 339 | {"START", "START", "Surplus energy start Current", 1, 16, START_CURRENT}, 340 | {"STOP", "STOP", "Stop solar charging at 6A after this time", 0, 60, STOP_TIME}, 341 | {"SW", "SWITCH", "Switch function control on pin SW", 0, 4, SWITCH}, 342 | {"RCMON", "RCMON", "Residual Current Monitor on pin RCM", 0, 1, RC_MON}, 343 | {"IMPORT", "IMPORT", "Allow grid power when solar charging", 0, 6, IMPORT_CURRENT}, 344 | {"RFID", "RFID", "Use RFID reader, learn/remove cards", 0, 4, RFID_READER}, 345 | {"EVEM", "EV METER", "Type of EV electric meter", 0, EM_CUSTOM, EV_METER}, 346 | {"EVAD", "EV ADDR", "Address of EV electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, EV_METER_ADDRESS}, 347 | {"CIRCUIT","CIRCUIT", "Set EVSE Circuit max Current", 10, 160, MAX_CIRCUIT}, 348 | {"MODE", "MODE", "Set to Normal, Smart or Solar EVSE mode", 0, 2, MODE}, 349 | {"MAINS", "MAINS", "Set Max MAINS Current", 10, 200, MAX_MAINS}, 350 | {"CAL", "CAL", "Calibrate CT1 (CT2+3 will also change)", (unsigned int)(ICAL * 0.3), (unsigned int)(ICAL * 2.0), ICAL}, // valid range is 0.3 - 2.0 times measured value 351 | {"MAINEM", "MAINSMET", "Type of mains electric meter", 1, EM_CUSTOM, MAINS_METER}, 352 | {"MAINAD", "MAINSADR", "Address of mains electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, MAINS_METER_ADDRESS}, 353 | {"MAINM", "MAINSMES", "Mains electric meter scope (What does it measure?)", 0, 1, MAINS_METER_MEASURE}, 354 | {"PVEM", "PV METER", "Type of PV electric meter", 0, EM_CUSTOM, PV_METER}, 355 | {"PVAD", "PV ADDR", "Address of PV electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, PV_METER_ADDRESS}, 356 | {"EMBO" , "BYTE ORD", "Byte order of custom electric meter", 0, 3, EMCUSTOM_ENDIANESS}, 357 | {"EMIREG", "CUR REGI", "Register for Current (A) of custom electric meter", 0, 65530, EMCUSTOM_IREGISTER}, 358 | {"EMIDIV", "CUR DIVI", "Divisor for Current (A) of custom electric meter", 0, 7, EMCUSTOM_IDIVISOR}, 359 | {"EMUREG", "VOL REGI", "Register for Voltage (V) of custom electric meter", 0, 65530, EMCUSTOM_UREGISTER}, 360 | {"EMUDIV", "VOL DIVI", "Divisor for Voltage (V) of custom electric meter", 0, 7, EMCUSTOM_UDIVISOR}, 361 | {"EMPREG", "POW REGI", "Register for Power (W) of custom electric meter", 0, 65534, EMCUSTOM_PREGISTER}, 362 | {"EMPDIV", "POW DIVI", "Divisor for Power (W) of custom electric meter", 0, 7, EMCUSTOM_PDIVISOR}, 363 | {"EMEREG", "ENE REGI", "Register for Energy (kWh) of custom electric meter", 0, 65534, EMCUSTOM_EREGISTER}, 364 | {"EMEDIV", "ENE DIVI", "Divisor for Energy (kWh) of custom electric meter", 0, 7, EMCUSTOM_EDIVISOR}, 365 | {"GRID", "GRID", "Grid type to which the Sensorbox is connected", 0, 1, GRID}, 366 | {"EMDATA", "DATATYPE", "Data type of custom electric meter", 0, 1, EMCUSTOM_ISDOUBLE}, 367 | {"EXIT", "EXIT", "EXIT", 0, 0, 0} 368 | }; 369 | 370 | struct { 371 | unsigned char Desc[10]; 372 | unsigned char Endianness; // 0: low byte first, low word first, 1: low byte first, high word first, 2: high byte first, low word first, 3: high byte first, high word first 373 | unsigned char Function; // 3: holding registers, 4: input registers 374 | bool IsDouble; 375 | unsigned int URegister; // Single phase voltage (V) 376 | unsigned char UDivisor; // 10^x 377 | unsigned int IRegister; // Single phase current (A) 378 | unsigned char IDivisor; // 10^x 379 | unsigned int PRegister; // Total power (W) 380 | unsigned char PDivisor; // 10^x 381 | unsigned int ERegister; // Total energy (kWh) 382 | unsigned char EDivisor; // 10^x 383 | } EMConfig[EM_CUSTOM + 1] = { 384 | {"Disabled", ENDIANESS_LBF_LWF, 0, false, 0, 0, 0, 0, 0, 0, 0, 0}, // First entry! 385 | {"Sensorbox", ENDIANESS_HBF_HWF, 4, true, 0xFFFF, 0, 0, 0, 0xFFFF, 0, 0xFFFF, 0}, // Sensorbox (Own routine for request/receive) 386 | {"Phoenix C", ENDIANESS_HBF_LWF, 4, false, 0x0, 1, 0xC, 3, 0x28, 1, 0x3E, 1}, // PHOENIX CONTACT EEM-350-D-MCB (0,1V / mA / 0,1W / 0,1kWh) 387 | {"Finder", ENDIANESS_HBF_HWF, 4, true, 0x1000, 0, 0x100E, 0, 0x1026, 0, 0x1106, 3}, // Finder 7E.78.8.400.0212 (V / A / W / Wh) 388 | {"Eastron", ENDIANESS_HBF_HWF, 4, true, 0x0, 0, 0x6, 0, 0x34, 0, 0x156, 0}, // Eastron SDM630 (V / A / W / kWh) 389 | {"ABB", ENDIANESS_HBF_HWF, 3, false, 0x5B00, 1, 0x5B0C, 2, 0x5B14, 2, 0x5002, 2}, // ABB B23 212-100 (0.1V / 0.01A / 0.01W / 0.01kWh) RS485 wiring reversed 390 | {"Custom", ENDIANESS_LBF_LWF, 4, false, 0, 0, 0, 0, 0, 0, 0, 0} // Last entry! 391 | }; 392 | 393 | struct NodeStatus { 394 | // unsigned int State; 395 | // unsigned int Error; 396 | // unsigned int Max; 397 | // unsigned int Min; 398 | // unsigned int PhaseCount; 399 | // unsigned int RealCurrent; 400 | // unsigned int Current; 401 | // unsigned int Access; 402 | // unsigned int Mode; 403 | unsigned int EVMeter; 404 | unsigned int EVAddress; 405 | }; 406 | 407 | void RS485SendBuf(char *buffer, unsigned char len); 408 | void eeprom_read_object(void *obj_p, size_t obj_size); 409 | void eeprom_write_object(void *obj_p, size_t obj_size); 410 | void read_settings(void); 411 | void write_settings(void); 412 | void setSolarStopTimer(unsigned int Timer); 413 | void setState(unsigned char NewState); 414 | unsigned char getMenuItems(void); 415 | unsigned char setItemValue(unsigned char nav, unsigned int val); 416 | unsigned int getItemValue(unsigned char nav); 417 | const far char * getMenuItemOption(unsigned char nav); 418 | 419 | #endif -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/GLCD.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/version2/SmartEVSE2.X/GLCD.c -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/GLCD.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | #ifndef __GLCD_H 26 | #define __GLCD_H 27 | 28 | void GLCD_write(unsigned int c); 29 | void GLCD_write2(unsigned int c); 30 | void GLCD_write_buf(unsigned int c); 31 | void GLCD_write_buf2(unsigned int c); 32 | void GLCD_print(unsigned char x,unsigned char y,const far char* str); 33 | void GLCD_print_buf(unsigned char x,unsigned char y,const far char* str); 34 | void GLCD_print_buf2(unsigned char y,const far char* str); 35 | void GLCD_print_menu(unsigned char y,const far char* str); 36 | void glcd_clrln(unsigned char ln,unsigned char data); 37 | void GLCD_sendbuf2(unsigned char RowAdr); 38 | void GLCD_sendbuf4(unsigned char RowAdr); 39 | void GLCD_buffer_clr(void); 40 | void glcd_clear(void); 41 | void font_condense(unsigned char c, unsigned char *start, unsigned char *end, unsigned char space); 42 | 43 | extern void GLCDHelp(void); 44 | extern void GLCD(void); 45 | extern void GLCDMenu(unsigned char Buttons); 46 | extern void GLCD_init(void); 47 | extern void GLCD_version(void); 48 | 49 | #endif // #ifndef __GLCD_H -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # There exist several targets which are by default empty and which can be 3 | # used for execution of your targets. These targets are usually executed 4 | # before and after some main targets. They are: 5 | # 6 | # .build-pre: called before 'build' target 7 | # .build-post: called after 'build' target 8 | # .clean-pre: called before 'clean' target 9 | # .clean-post: called after 'clean' target 10 | # .clobber-pre: called before 'clobber' target 11 | # .clobber-post: called after 'clobber' target 12 | # .all-pre: called before 'all' target 13 | # .all-post: called after 'all' target 14 | # .help-pre: called before 'help' target 15 | # .help-post: called after 'help' target 16 | # 17 | # Targets beginning with '.' are not intended to be called on their own. 18 | # 19 | # Main targets can be executed directly, and they are: 20 | # 21 | # build build a specific configuration 22 | # clean remove built files from a configuration 23 | # clobber remove all built files 24 | # all build all configurations 25 | # help print help mesage 26 | # 27 | # Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and 28 | # .help-impl are implemented in nbproject/makefile-impl.mk. 29 | # 30 | # Available make variables: 31 | # 32 | # CND_BASEDIR base directory for relative paths 33 | # CND_DISTDIR default top distribution directory (build artifacts) 34 | # CND_BUILDDIR default top build directory (object files, ...) 35 | # CONF name of current configuration 36 | # CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) 37 | # CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) 38 | # CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) 39 | # CND_PACKAGE_DIR_${CONF} directory of package (current configuration) 40 | # CND_PACKAGE_NAME_${CONF} name of package (current configuration) 41 | # CND_PACKAGE_PATH_${CONF} path to package (current configuration) 42 | # 43 | # NOCDDL 44 | 45 | 46 | # Environment 47 | MKDIR=mkdir 48 | CP=cp 49 | CCADMIN=CCadmin 50 | RANLIB=ranlib 51 | 52 | 53 | # build 54 | build: .build-post 55 | 56 | .build-pre: 57 | # Add your pre 'build' code here... 58 | 59 | .build-post: .build-impl 60 | # Add your post 'build' code here... 61 | 62 | 63 | # clean 64 | clean: .clean-post 65 | 66 | .clean-pre: 67 | # Add your pre 'clean' code here... 68 | # WARNING: the IDE does not call this target since it takes a long time to 69 | # simply run make. Instead, the IDE removes the configuration directories 70 | # under build and dist directly without calling make. 71 | # This target is left here so people can do a clean when running a clean 72 | # outside the IDE. 73 | 74 | .clean-post: .clean-impl 75 | # Add your post 'clean' code here... 76 | 77 | 78 | # clobber 79 | clobber: .clobber-post 80 | 81 | .clobber-pre: 82 | # Add your pre 'clobber' code here... 83 | 84 | .clobber-post: .clobber-impl 85 | # Add your post 'clobber' code here... 86 | 87 | 88 | # all 89 | all: .all-post 90 | 91 | .all-pre: 92 | # Add your pre 'all' code here... 93 | 94 | .all-post: .all-impl 95 | # Add your post 'all' code here... 96 | 97 | 98 | # help 99 | help: .help-post 100 | 101 | .help-pre: 102 | # Add your pre 'help' code here... 103 | 104 | .help-post: .help-impl 105 | # Add your post 'help' code here... 106 | 107 | 108 | 109 | # include project implementation makefile 110 | include nbproject/Makefile-impl.mk 111 | 112 | # include project make variables 113 | include nbproject/Makefile-variables.mk 114 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/OneWire.c: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "EVSE.h" 31 | #include "utils.h" 32 | #include "OneWire.h" 33 | 34 | unsigned char RFID[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 35 | unsigned char RFIDlist[120]; // holds up to 20 RFIDs 36 | 37 | 38 | 39 | // ############################# OneWire functions ############################# 40 | 41 | 42 | 43 | // Reset 1-Wire device on IO2 (SW input) 44 | // returns: 1 Device found 45 | // 0 No device found 46 | // 255 Error. Line is pulled low (short, or external button pressed?) 47 | // 48 | unsigned char OneWireReset(void) { 49 | unsigned char r, savint; 50 | 51 | if (PORTBbits.RB2 == 0) return 255; // Error, pulled low by external device? 52 | 53 | ONEWIRE_LOW; // Drive wire low 54 | __delay_us(480); 55 | savint = INTCON; // Save interrupts state 56 | INTCONbits.GIE = 0; // Disable interrupts 57 | ONEWIRE_FLOATHIGH; // don't drive high, but use pullup 58 | __delay_us(70); 59 | if (PORTBbits.RB2 == 1) r = 0; // sample pin to see if there is a OneWire device.. 60 | else r = 1; 61 | INTCON = savint; // Restore interrupts 62 | __delay_us(410); 63 | return r; 64 | } 65 | 66 | void OneWireWriteBit(unsigned char v) { 67 | unsigned char savint; 68 | 69 | if (v & 1) { // write a '1' 70 | savint = INTCON; // Save interrupts state 71 | INTCONbits.GIE = 0; // Disable interrupts 72 | ONEWIRE_LOW; // Drive low 73 | __delay_us(10); 74 | ONEWIRE_HIGH; // Drive high 75 | INTCON = savint; // Restore interrupts 76 | __delay_us(55); 77 | } else { // write a '0' 78 | savint = INTCON; // Save interrupts state 79 | INTCONbits.GIE = 0; // Disable interrupts 80 | ONEWIRE_LOW; // Drive low 81 | __delay_us(65); 82 | ONEWIRE_HIGH; // Drive high 83 | INTCON = savint; // Restore interrupts 84 | __delay_us(5); 85 | } 86 | } 87 | 88 | unsigned char OneWireReadBit(void) { 89 | unsigned char r, savint; 90 | 91 | savint = INTCON; // Save interrupts state 92 | INTCONbits.GIE = 0; // Disable interrupts 93 | ONEWIRE_LOW; 94 | __delay_us(3); 95 | ONEWIRE_FLOATHIGH; 96 | __delay_us(10); 97 | if (PORTBbits.RB2) r = 1; // sample pin 98 | else r = 0; 99 | INTCON = savint; // Restore interrupts 100 | __delay_us(53); 101 | return r; 102 | } 103 | 104 | void OneWireWrite(unsigned char v) { 105 | unsigned char bitmask; 106 | for (bitmask = 0x01; bitmask ; bitmask <<= 1) { 107 | OneWireWriteBit( (bitmask & v)?1:0); 108 | } 109 | } 110 | 111 | unsigned char OneWireRead(void) { 112 | unsigned char bitmask, r = 0; 113 | 114 | for (bitmask = 0x01; bitmask ; bitmask <<= 1) { 115 | if ( OneWireReadBit()) r |= bitmask; 116 | } 117 | return r; 118 | } 119 | 120 | unsigned char OneWireReadCardId(void) { 121 | unsigned char x; 122 | 123 | if (OneWireReset() == 1) { // RFID card detected 124 | OneWireWrite(0x33); // OneWire ReadRom Command 125 | for (x=0 ; x<8 ; x++) RFID[x] = OneWireRead(); // read Family code (0x01) RFID ID (6 bytes) and crc8 126 | if (crc8(RFID,8)) { 127 | RFID[0] = 0; // CRC incorrect, clear first byte of RFID buffer 128 | return 0; 129 | } else { 130 | // for (x=1 ; x<7 ; x++) printf("%02x",RFID[x]); 131 | // printf("\r\n"); 132 | return 1; 133 | } 134 | } 135 | return 0; 136 | } 137 | 138 | 139 | 140 | // ############################## RFID functions ############################## 141 | 142 | 143 | 144 | // Read a list of 20 RFID's from eeprom 145 | // 146 | void ReadRFIDlist(void) { 147 | EEADR = 0; // start from adr 256 in eeprom 148 | EEADRH = 1; 149 | 150 | eeprom_read_object(RFIDlist, 120); 151 | } 152 | 153 | // Write a list of 20 RFID's to the eeprom 154 | // 155 | void WriteRFIDlist(void) { 156 | char savint; 157 | 158 | unlock55 = unlockMagic + 0x33; 159 | unlockAA = unlockMagic + 0x88; // set unlock variables to magic values 160 | 161 | savint = INTCON; // Save interrupts state 162 | INTCONbits.GIE = 0; // Disable interrupts 163 | 164 | EEADR = 0; // start from adr 256 in eeprom 165 | EEADRH = 1; 166 | 167 | eeprom_write_object(RFIDlist, 120); // write 120 bytes to eeprom 168 | 169 | unlock55 = 0; // clear unlock values 170 | unlockAA = 0; 171 | 172 | INTCON = savint; // Restore interrupts 173 | #ifdef LOG_DEBUG_EVSE 174 | printf("\nRFID list saved\n"); 175 | #endif 176 | } 177 | 178 | // scan for matching RFID in RFIDlist 179 | // returns offset+6 when found, 0 when not found 180 | unsigned char MatchRFID(void) { 181 | unsigned char offset = 0, r; 182 | 183 | do { 184 | r = memcmp(RFID + 1, RFIDlist + offset, 6 ); // compare read RFID with list of stored RFID's 185 | offset += 6; 186 | } while (r !=0 && offset < 114); 187 | 188 | if (r == 0) return offset; // return offset + 6 in RFIDlist 189 | else return 0; 190 | } 191 | 192 | 193 | // Store RFID card in memory and eeprom 194 | // returns 1 when successful 195 | // returns 2 when already stored 196 | // returns 0 when all slots are full. 197 | unsigned char StoreRFID(void) { 198 | unsigned char offset = 0, r; 199 | unsigned char empty[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; 200 | 201 | // first check if the Card ID was already stored. 202 | if ( MatchRFID() ) return 2; // already stored, that's ok. 203 | 204 | do { 205 | r = memcmp(empty, RFIDlist + offset, 6 ); 206 | offset += 6; 207 | } while (r !=0 && offset < 120); 208 | if (r != 0) return 0; // no more room to store RFID 209 | offset -= 6; 210 | // printf("offset %u ",offset); 211 | memcpy(RFIDlist + offset, RFID+1, 6); 212 | 213 | #ifdef LOG_DEBUG_EVSE 214 | printf("\nRFIDlist:"); 215 | for (r=0; r<120; r++) printf("%02x",RFIDlist[r]); 216 | #endif 217 | 218 | WriteRFIDlist(); 219 | return 1; 220 | } 221 | 222 | // Delete RFID card in memory and eeprom 223 | // returns 1 when successful, 0 when RFID was not found 224 | unsigned char DeleteRFID(void) { 225 | unsigned char offset = 0, r; 226 | 227 | offset = MatchRFID(); // find RFID in list 228 | if (offset) { 229 | offset -= 6; 230 | for (r = 0; r < 6; r++) RFIDlist[offset + r] = 0xff; 231 | } else return 0; 232 | 233 | // printf("deleted %u ",offset); 234 | // for (r=0; r<120; r++) printf("%02x",RFIDlist[r]); 235 | 236 | return 1; 237 | } 238 | 239 | void DeleteAllRFID(void) { 240 | unsigned char i; 241 | 242 | for (i = 0; i < 120; i++) RFIDlist[i] = 0xff; 243 | WriteRFIDlist(); 244 | #ifdef LOG_INFO_EVSE 245 | printf("\nAll RFID cards erased!"); 246 | #endif 247 | RFIDReader = 0; // RFID Reader Disabled 248 | } 249 | 250 | void CheckRFID(void) { 251 | unsigned char x; 252 | 253 | // When RFID is enabled, a OneWire RFID reader is expected on the SW input 254 | if (RFIDReader) { // RFID Reader set to Enabled, Learn or Delete 255 | if (OneWireReadCardId() ) { // Read card ID 256 | switch (RFIDReader) { 257 | case 1: // Enabled 258 | x = MatchRFID(); 259 | if (x && !RFIDstatus) { 260 | //printf("RFID card found!\n"); 261 | if (Access_bit) { 262 | Access_bit = 0; // Toggle Access bit on/off 263 | setState(STATE_A); // Switch back to state A 264 | } else Access_bit = 1; 265 | 266 | RFIDstatus = 1; 267 | } else if (!x) RFIDstatus = 7; // invalid card 268 | BacklightTimer = BACKLIGHT; 269 | break; 270 | case 2: // Learn Card 271 | x = StoreRFID(); 272 | if (x == 1) { 273 | printf("\nRFID card stored!"); 274 | RFIDstatus = 2; 275 | } else if (x == 2 && !RFIDstatus) { 276 | printf("\nRFID card was already stored!"); 277 | RFIDstatus = 4; 278 | } else if (!RFIDstatus) { 279 | printf("\nRFID storage full! Delete card first"); 280 | RFIDstatus = 6; 281 | } 282 | break; 283 | case 3: // Delete Card 284 | x = DeleteRFID(); 285 | if (x) { 286 | printf("\nRFID card deleted!"); 287 | RFIDstatus = 3; 288 | } else if (!RFIDstatus) { 289 | printf("\nRFID card not in list!"); 290 | RFIDstatus = 5; 291 | } 292 | break; 293 | default: 294 | break; 295 | } 296 | } else RFIDstatus = 0; 297 | } 298 | } -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/OneWire.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | void ReadRFIDlist(void); 26 | void DeleteAllRFID(void); 27 | void CheckRFID(void); 28 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/bootloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; This code will overwrite v 1.05 of the bootloader with version 1.06 5 | ; Version 1.06 has much better protection against unintended flash writes/erases 6 | ; 7 | ; 8 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 9 | ; of this software and associated documentation files (the "Software"), to deal 10 | ; in the Software without restriction, including without limitation the rights 11 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | ; copies of the Software, and to permit persons to whom the Software is 13 | ; furnished to do so, subject to the following conditions: 14 | ; 15 | ; The above copyright notice and this permission notice shall be included in 16 | ; all copies or substantial portions of the Software. 17 | ; 18 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | ; THE SOFTWARE. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | #include "bootloader.h" 31 | 32 | 33 | const far unsigned char bootloader[] = { 34 | 0x06, 0xD0, 0x0F, 0x01, 0x3A, 0x9F, 0xD0, 0xB2, 0x81, 0xBE, 0x7E, 0xEF, 0x7E, 0xF0, 0x55, 0x0E, 35 | 0x04, 0x6E, 0xAA, 0x0E, 0x05, 0x6E, 0x0F, 0x01, 0x3A, 0x9F, 0x20, 0xEE, 0x00, 0xF0, 0x00, 0x01, 36 | 0x81, 0xAE, 0xFE, 0xD7, 0x90, 0x0E, 0x71, 0x6E, 0x26, 0x0E, 0x72, 0x6E, 0x70, 0x86, 0x02, 0x0E, 37 | 0xD5, 0x6E, 0x71, 0x98, 0x74, 0x50, 0x74, 0x50, 0xD7, 0x6A, 0xD6, 0x6A, 0xF2, 0x94, 0x4E, 0xD8, 38 | 0xD5, 0x8E, 0x4C, 0xD8, 0xD5, 0x9E, 0xF2, 0xB4, 0xF7, 0xD7, 0xD6, 0xCF, 0x75, 0xFF, 0xD7, 0xCF, 39 | 0x76, 0xFF, 0x71, 0x88, 0x2B, 0xD9, 0x0F, 0x0A, 0xEC, 0xE1, 0x0F, 0x0E, 0x22, 0xD9, 0x00, 0xEE, 40 | 0x05, 0xF0, 0x24, 0xD9, 0x0F, 0x0A, 0xF9, 0xE0, 0x02, 0x50, 0x04, 0x0A, 0x07, 0xE0, 0x02, 0x50, 41 | 0x05, 0x0A, 0x01, 0xE1, 0x1B, 0xD9, 0x02, 0xC0, 0xEC, 0xFF, 0xF3, 0xD7, 0x10, 0xEE, 0x06, 0xF0, 42 | 0x00, 0x6A, 0x01, 0x6A, 0xED, 0xCF, 0xF4, 0xFF, 0xE6, 0x50, 0x30, 0xD8, 0xE2, 0x50, 0xEA, 0x62, 43 | 0xFB, 0xD7, 0xE1, 0x50, 0xE9, 0x62, 0xF8, 0xD7, 0x01, 0x50, 0xF4, 0x62, 0xCA, 0xD7, 0x00, 0x50, 44 | 0xEF, 0x62, 0xC7, 0xD7, 0x00, 0x6A, 0x01, 0x6A, 0x07, 0x50, 0xF6, 0x6E, 0xA9, 0x6E, 0x08, 0x50, 45 | 0xF7, 0x6E, 0xAA, 0x6E, 0x09, 0xC0, 0xF8, 0xFF, 0x00, 0xEE, 0x0C, 0xF0, 0x0A, 0x0E, 0x06, 0x60, 46 | 0xB8, 0xD7, 0xF9, 0x50, 0x06, 0x44, 0xF9, 0x26, 0x27, 0xD0, 0x2F, 0xD0, 0x39, 0xD0, 0x4F, 0xD0, 47 | 0x7C, 0xD0, 0xA8, 0xD0, 0xB5, 0xD0, 0xC4, 0xD0, 0x98, 0xD7, 0xFF, 0x00, 0x04, 0x00, 0xF2, 0xB4, 48 | 0x12, 0x00, 0x81, 0xBE, 0xFC, 0xD7, 0x81, 0xAE, 0xFE, 0xD7, 0x12, 0x00, 0x01, 0x18, 0x00, 0xC0, 49 | 0x01, 0xF0, 0x00, 0x6E, 0xE8, 0x3A, 0x0F, 0x0B, 0x00, 0x1A, 0x00, 0x38, 0xF0, 0x0B, 0x01, 0x1A, 50 | 51 | 0x00, 0x38, 0xE8, 0x44, 0x01, 0x1A, 0xE0, 0x0B, 0x01, 0x1A, 0x00, 0x1A, 0x12, 0x00, 0x00, 0x03, 52 | 0x01, 0x06, 0xFF, 0x84, 0x00, 0xFD, 0x00, 0x00, 0x0E, 0x0E, 0xF6, 0x6E, 0xFE, 0x0E, 0xF7, 0x6E, 53 | 0x00, 0x0E, 0xF8, 0x6E, 0x0A, 0x0E, 0x0B, 0x6E, 0x0C, 0x6A, 0x09, 0x00, 0xF5, 0x50, 0xAD, 0xD8, 54 | 0xDD, 0xDF, 0x0B, 0x06, 0x00, 0x0E, 0x0C, 0x5A, 0x0B, 0x50, 0x0C, 0x10, 0xF6, 0xE1, 0x9E, 0xD0, 55 | 0x09, 0x00, 0xF5, 0x50, 0xD3, 0xDF, 0xF6, 0x50, 0x3F, 0x0B, 0xFA, 0xE1, 0x00, 0x50, 0xC5, 0xEC, 56 | 0x7F, 0xF0, 0x01, 0x50, 0xC5, 0xEC, 0x7F, 0xF0, 0x0B, 0x06, 0x00, 0x0E, 0x0C, 0x5A, 0x0B, 0x50, 57 | 0x0C, 0x10, 0xEE, 0xE1, 0x8F, 0xD0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x0E, 58 | 0xF6, 0x16, 0x00, 0x0E, 0xF6, 0x5C, 0x00, 0x0E, 0xF7, 0x58, 0x01, 0x0E, 0xF8, 0x58, 0x02, 0xE6, 59 | 0xA6, 0x6A, 0x17, 0xD0, 0x00, 0x0E, 0xF6, 0x5C, 0xFD, 0x0E, 0xF7, 0x58, 0x00, 0x0E, 0xF8, 0x58, 60 | 0x0D, 0xE6, 0x00, 0x0E, 0xF6, 0x5C, 0x00, 0x0E, 0xF7, 0x58, 0x01, 0x0E, 0xF8, 0x58, 0x06, 0xE7, 61 | 0xA6, 0x6A, 0x07, 0xD0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x94, 0x0E, 0xA6, 0x6E, 62 | 0x8B, 0xD8, 0x40, 0x0E, 0xF6, 0x5E, 0xE8, 0x6A, 0xF7, 0x5A, 0xF8, 0x5A, 0x0B, 0x2E, 0xD7, 0xD7, 63 | 0x59, 0xD0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x0E, 0xF6, 0x16, 0x00, 0x0E, 64 | 0xF6, 0x5C, 0x00, 0x0E, 0xF7, 0x58, 0x01, 0x0E, 0xF8, 0x58, 0x02, 0xE6, 0xA6, 0x6A, 0x16, 0xD0, 65 | 0x00, 0x0E, 0xF6, 0x5C, 0xFD, 0x0E, 0xF7, 0x58, 0x00, 0x0E, 0xF8, 0x58, 0x0D, 0xE6, 0x00, 0x0E, 66 | 0xF6, 0x5C, 0x00, 0x0E, 0xF7, 0x58, 0x01, 0x0E, 0xF8, 0x58, 0x06, 0xE7, 0xA6, 0x6A, 0x06, 0xD0, 67 | 68 | 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x84, 0x0E, 0xA6, 0x6E, 0xEE, 0xCF, 0xF5, 0xFF, 69 | 0x0D, 0x00, 0xF6, 0x50, 0x3F, 0x0B, 0xFA, 0xE1, 0x0A, 0x00, 0x56, 0xD8, 0x09, 0x00, 0x0B, 0x2E, 70 | 0xD4, 0xD7, 0x28, 0xD0, 0xA6, 0x6A, 0xA6, 0x80, 0xA8, 0x50, 0xA9, 0x4A, 0xAA, 0x2A, 0x2D, 0xD8, 71 | 0x5D, 0xDF, 0x0B, 0x06, 0x00, 0x0E, 0x0C, 0x5A, 0x0B, 0x50, 0x0C, 0x10, 0xF4, 0xE1, 0x1E, 0xD0, 72 | 0x04, 0x0E, 0xA6, 0x6E, 0xEC, 0xCF, 0xA8, 0xFF, 0x3F, 0xD8, 0xA6, 0xB2, 0xFE, 0xD7, 0xA9, 0x4A, 73 | 0xAA, 0x2A, 0x0B, 0x06, 0x00, 0x0E, 0x0C, 0x5A, 0x0B, 0x50, 0x0C, 0x10, 0xF3, 0xE1, 0x0A, 0xD0, 74 | 0xC4, 0x0E, 0xA6, 0x6E, 0x08, 0x00, 0xEE, 0x50, 0xF5, 0x62, 0x2C, 0xD8, 0x0B, 0x00, 0x0B, 0x2E, 75 | 0xFA, 0xD7, 0x00, 0xD0, 0xA6, 0x6A, 0x06, 0x50, 0x08, 0xD8, 0x38, 0xDF, 0x00, 0x50, 0x05, 0xD8, 76 | 0x01, 0x50, 0x03, 0xD8, 0x04, 0x0E, 0x0D, 0xD8, 0xE5, 0xD6, 0x03, 0x6E, 0x0F, 0x0A, 0x06, 0xE0, 77 | 0x03, 0x50, 0x04, 0x0A, 0x03, 0xE0, 0x03, 0x50, 0x05, 0x0A, 0x02, 0xE1, 0x05, 0x0E, 0x01, 0xD8, 78 | 0x03, 0x50, 0x04, 0x00, 0xA4, 0xA8, 0xFE, 0xD7, 0x73, 0x6E, 0x12, 0x00, 0x71, 0xB2, 0xFF, 0x00, 79 | 0x04, 0x00, 0xA4, 0xAA, 0xFD, 0xD7, 0x74, 0x50, 0x02, 0x6E, 0x12, 0x00, 0xFF, 0x00, 0xFF, 0x00, 80 | 0xFF, 0x00, 0xA6, 0x6A, 0xF5, 0x6E, 0x0C, 0x00, 0x04, 0x00, 0x04, 0x50, 0xA7, 0x6E, 0x05, 0x50, 81 | 0xA7, 0x6E, 0xA6, 0x82, 0x00, 0x00, 0x12, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 82 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 83 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 84 | }; 85 | 86 | 87 | unsigned char checkbootloader(void) { 88 | unsigned int adr, i=0, cnt; 89 | unsigned char err=0, errcnt=0; 90 | 91 | INTCONbits.GIE = 0; // Disable interrupts 92 | 93 | EECON1 = 0x80; // Access Flash program memory 94 | 95 | TBLPTR = 0xFFF0; // set to serial nr. 96 | asm("TBLRD*+"); 97 | serialnr = TABLAT; // first read LSB 98 | asm("TBLRD*+"); 99 | serialnr |= TABLAT<<8; // then MSB 100 | 101 | TBLPTR = 0xFFD0; // Address unused by 1.05 bootloader, should be 0xff 102 | asm("TBLRD*+"); 103 | if (TABLAT != 0xFF) { 104 | INTCONbits.GIE = 1; // Enable interrupts 105 | return 0; // already updated to 1.06 or higher 106 | } 107 | 108 | // now erase and overwrite the bootloader @ FD00-FFFF, 12 blocks of 64 bytes 109 | 110 | unlock55 = unlockMagic + 0x33; // to protect against unintended flash writes/erase 111 | unlockAA = unlockMagic + 0x88; // we calculate the magic values 112 | 113 | do { 114 | i = 0; 115 | err = 0; 116 | adr = 0xFD00; 117 | do { 118 | memcpy(GLCDbuf, bootloader+i, 64); // copy 64 bytes to temp buffer 119 | if (i == 0x2c0) { 120 | GLCDbuf[48] = serialnr & 0xff; 121 | GLCDbuf[49] = serialnr >> 8; 122 | GLCDbuf[50] = 0; 123 | GLCDbuf[51] = 0; 124 | } 125 | 126 | TBLPTR = adr; // set pointer to start of block to erase 127 | EECON1 = 0x94; // select erase, and set write enable 128 | EECON2 = unlock55; 129 | EECON2 = unlockAA; // write magic values to enable erase 130 | EECON1bits.WR = 1; // start the actual erase 131 | 132 | TBLPTR = adr; // set pointer to start of block to erase 133 | cnt = 0; 134 | do { 135 | TABLAT = GLCDbuf[i%64]; // No debug print here, as it will modify the TBLPTR 136 | i++; 137 | asm("TBLWT*+"); // write to latch and increment 138 | } while (++cnt <64); 139 | 140 | asm("TBLRD*-"); // dummy read to point to the correct flash block 141 | EECON1 = 0x84; // select flash write, and set write enable 142 | EECON2 = unlock55; 143 | EECON2 = unlockAA; // write magic values to enable erase 144 | EECON1bits.WR = 1; // start the actual programming 145 | 146 | EECON1 = 0x80; // write disable 147 | TBLPTR = adr; 148 | i -=64; 149 | 150 | cnt = 0; 151 | do { 152 | asm("TBLRD*+"); // read back flash 153 | if (TABLAT != GLCDbuf[i%64]) err = 1; // and verify with buffer 154 | i++; 155 | } while (++cnt <64); 156 | 157 | adr +=64; 158 | } while (adr); 159 | 160 | } while (err && ++errcnt < 3); // try three times 161 | 162 | EECON1bits.WREN = 0; 163 | 164 | unlock55 = 0; 165 | unlockAA = 0; 166 | INTCONbits.GIE = 1; // Enable interrupts 167 | if (err) return 2; 168 | return 1; 169 | } 170 | 171 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/bootloader.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | // This is a guard condition so that contents of this file are not included 26 | // more than once. 27 | #ifndef BOOTLOADER_H 28 | #define BOOTLOADER_H 29 | 30 | extern char GLCDbuf[512]; // GLCD buffer (half of the display) 31 | extern unsigned char unlockMagic; 32 | extern unsigned char unlock55; // unlock bytes set to 0 to prevent flash write at por 33 | extern unsigned char unlockAA; // unlock bytes set to 0 to prevent flash write at por 34 | extern unsigned int serialnr; 35 | 36 | extern unsigned char checkbootloader(void); 37 | 38 | #endif /* BOOTLOADER_H */ 39 | 40 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/modbus.c: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "EVSE.h" 29 | #include "modbus.h" 30 | #include "utils.h" 31 | 32 | 33 | 34 | // ########################## Modbus helper functions ########################## 35 | 36 | 37 | 38 | /** 39 | * Send data over modbus 40 | * 41 | * @param unsigned char address 42 | * @param unsigned char function 43 | * @param unsigned char byte 44 | * @param unsigned int pointer to values 45 | * @param unsigned char count of values 46 | */ 47 | void ModbusSend(unsigned char address, unsigned char function, unsigned char byte, unsigned int *values, unsigned char count) { 48 | unsigned int cs, i, n = 0; 49 | char Tbuffer[49]; // Maximum 22 values 50 | 51 | // Device address 52 | Tbuffer[n++] = address; 53 | // Function 54 | Tbuffer[n++] = function; 55 | // The number of data bytes to follow 56 | if (byte) Tbuffer[n++] = byte; 57 | // Values 58 | for (i = 0; i < count; i++) { 59 | Tbuffer[n++] = ((unsigned char)(values[i]>>8)); 60 | Tbuffer[n++] = ((unsigned char)(values[i])); 61 | } 62 | // Calculate CRC16 from data 63 | cs = crc16(Tbuffer, n); 64 | Tbuffer[n++] = ((unsigned char)(cs)); 65 | Tbuffer[n++] = ((unsigned char)(cs>>8)); 66 | 67 | // Send buffer to RS485 port 68 | RS485SendBuf(Tbuffer, n); 69 | } 70 | 71 | /** 72 | * Send single value over modbus 73 | * 74 | * @param unsigned char address 75 | * @param unsigned char function 76 | * @param unsigned int register 77 | * @param unsigned int data 78 | */ 79 | void ModbusSend8(unsigned char address, unsigned char function, unsigned int reg, unsigned int data) { 80 | unsigned int values[2]; 81 | 82 | values[0] = reg; 83 | values[1] = data; 84 | 85 | ModbusSend(address, function, 0, values, 2); 86 | } 87 | 88 | /** 89 | * Combine Bytes received over modbus 90 | * 91 | * @param pointer to var 92 | * @param pointer to buf 93 | * @param unsigned char pos 94 | * @param unsigned char endianness:\n 95 | * 0: low byte first, low word first (little endian)\n 96 | * 1: low byte first, high word first\n 97 | * 2: high byte first, low word first\n 98 | * 3: high byte first, high word first (big endian) 99 | */ 100 | void combineBytes(void *var, unsigned char *buf, unsigned char pos, unsigned char endianness) { 101 | char *pBytes; 102 | 103 | pBytes = var; 104 | 105 | // XC8 is little endian 106 | switch(endianness) { 107 | case ENDIANESS_LBF_LWF: // low byte first, low word first (little endian) 108 | *pBytes++ = (unsigned char)buf[pos + 0]; 109 | *pBytes++ = (unsigned char)buf[pos + 1]; 110 | *pBytes++ = (unsigned char)buf[pos + 2]; 111 | *pBytes = (unsigned char)buf[pos + 3]; 112 | break; 113 | case ENDIANESS_LBF_HWF: // low byte first, high word first 114 | *pBytes++ = (unsigned char)buf[pos + 2]; 115 | *pBytes++ = (unsigned char)buf[pos + 3]; 116 | *pBytes++ = (unsigned char)buf[pos + 0]; 117 | *pBytes = (unsigned char)buf[pos + 1]; 118 | break; 119 | case ENDIANESS_HBF_LWF: // high byte first, low word first 120 | *pBytes++ = (unsigned char)buf[pos + 1]; 121 | *pBytes++ = (unsigned char)buf[pos + 0]; 122 | *pBytes++ = (unsigned char)buf[pos + 3]; 123 | *pBytes = (unsigned char)buf[pos + 2]; 124 | break; 125 | case ENDIANESS_HBF_HWF: // high byte first, high word first (big endian) 126 | *pBytes++ = (unsigned char)buf[pos + 3]; 127 | *pBytes++ = (unsigned char)buf[pos + 2]; 128 | *pBytes++ = (unsigned char)buf[pos + 1]; 129 | *pBytes = (unsigned char)buf[pos + 0]; 130 | break; 131 | default: 132 | break; 133 | } 134 | } 135 | 136 | 137 | 138 | // ########################### Modbus main functions ########################### 139 | 140 | 141 | 142 | /** 143 | * Request read holding (FC=3) or read input register (FC=04) to a device over modbus 144 | * 145 | * @param unsigned char address 146 | * @param unsigned char function 147 | * @param unsigned int register 148 | * @param unsigned int quantity 149 | */ 150 | void ModbusReadInputRequest(unsigned char address, unsigned char function, unsigned int reg, unsigned int quantity) { 151 | Modbus.RequestAddress = address; 152 | Modbus.RequestFunction = function; 153 | Modbus.RequestRegister = reg; 154 | ModbusSend8(address, function, reg, quantity); 155 | } 156 | 157 | /** 158 | * Response read holding (FC=3) or read input register (FC=04) to a device over modbus 159 | * 160 | * @param unsigned char address 161 | * @param unsigned char function 162 | * @param unsigned int pointer to values 163 | * @param unsigned char count of values 164 | */ 165 | void ModbusReadInputResponse(unsigned char address, unsigned char function, unsigned int *values, unsigned char count) { 166 | ModbusSend(address, function, count * 2u, values, count); 167 | } 168 | 169 | /** 170 | * Request write single register (FC=06) to a device over modbus 171 | * 172 | * @param unsigned char address 173 | * @param unsigned int register 174 | * @param unsigned int value 175 | */ 176 | void ModbusWriteSingleRequest(unsigned char address, unsigned int reg, unsigned int value) { 177 | Modbus.RequestAddress = address; 178 | Modbus.RequestFunction = 0x06; 179 | Modbus.RequestRegister = reg; 180 | ModbusSend8(address, 0x06, reg, value); 181 | } 182 | 183 | /** 184 | * Response write single register (FC=06) to a device over modbus 185 | * 186 | * @param unsigned char address 187 | * @param unsigned int register 188 | * @param unsigned int value 189 | */ 190 | void ModbusWriteSingleResponse(unsigned char address, unsigned int reg, unsigned int value) { 191 | ModbusSend8(address, 0x06, reg, value); 192 | } 193 | 194 | 195 | /** 196 | * Request write multiple register (FC=16) to a device over modbus 197 | * 198 | * @param unsigned char address 199 | * @param unsigned int register 200 | * @param unsigned char pointer to data 201 | * @param unsigned char count of data 202 | */ 203 | void ModbusWriteMultipleRequest(unsigned char address, unsigned int reg, unsigned int *values, unsigned char count) { 204 | unsigned int i, n = 0, cs; 205 | char Tbuffer[50]; 206 | 207 | Modbus.RequestAddress = address; 208 | Modbus.RequestFunction = 0x10; 209 | Modbus.RequestRegister = reg; 210 | 211 | // Device Address 212 | Tbuffer[n++] = address; 213 | // Function Code 16 214 | Tbuffer[n++] = 0x10; 215 | // Data Address of the first register 216 | Tbuffer[n++] = ((unsigned char)(reg>>8)); 217 | Tbuffer[n++] = ((unsigned char)(reg)); 218 | // Number of registers to write 219 | Tbuffer[n++] = 0x00; 220 | Tbuffer[n++] = count; 221 | // Number of data bytes to follow (2 registers x 2 bytes each = 4 bytes) 222 | Tbuffer[n++] = count * 2u; 223 | // Values 224 | for (i = 0; i < count; i++) { 225 | Tbuffer[n++] = ((unsigned char)(values[i]>>8)); 226 | Tbuffer[n++] = ((unsigned char)(values[i])); 227 | } 228 | // Calculate CRC16 from data 229 | cs = crc16(Tbuffer, n); 230 | Tbuffer[n++] = ((unsigned char)(cs)); 231 | Tbuffer[n++] = ((unsigned char)(cs>>8)); 232 | // Send buffer to RS485 port 233 | RS485SendBuf(Tbuffer, n); 234 | } 235 | 236 | /** 237 | * Response write multiple register (FC=16) to a device over modbus 238 | * 239 | * @param unsigned char address 240 | * @param unsigned int register 241 | * @param unsigned int count 242 | */ 243 | void ModbusWriteMultipleResponse(unsigned char address, unsigned int reg, unsigned int count) { 244 | ModbusSend8(address, 0x10, reg, count); 245 | } 246 | 247 | /** 248 | * Response an exception 249 | * 250 | * @param unsigned char address 251 | * @param unsigned char function 252 | * @param unsigned char exeption 253 | */ 254 | void ModbusException(unsigned char address, unsigned char function, unsigned char exception) { 255 | unsigned int temp[1]; 256 | ModbusSend(address, function, exception, temp, 0); 257 | } 258 | 259 | /** 260 | * Decode received modbus packet 261 | * 262 | * @param unsigned char pointer to buffer 263 | * @param unsigned char length of buffer 264 | */ 265 | void ModbusDecode(unsigned char *buf, unsigned char len) { 266 | // Clear old values 267 | Modbus.Address = 0; 268 | Modbus.Function = 0; 269 | Modbus.Register = 0; 270 | Modbus.RegisterCount = 0; 271 | Modbus.Value = 0; 272 | Modbus.DataLength = 0; 273 | Modbus.Type = MODBUS_INVALID; 274 | Modbus.Exception = 0; 275 | 276 | #ifdef LOG_INFO_MODBUS 277 | printf("\nReceived packet"); 278 | #endif 279 | #ifdef LOG_DEBUG_MODBUS 280 | printf(" (%i bytes) ", len); 281 | for (unsigned char x=0; x= 8) { 300 | // Modbus device address 301 | Modbus.Address = buf[0]; 302 | // Modbus function 303 | Modbus.Function = buf[1]; 304 | // calculate checksum over all data (including crc16) 305 | // when checksum == 0 data is ok. 306 | if (!crc16(buf, len)) { 307 | // CRC OK 308 | #ifdef LOG_DEBUG_MODBUS 309 | printf("\n valid Modbus packet: Address %02x Function %02x", Modbus.Address, Modbus.Function); 310 | #endif 311 | switch (Modbus.Function) { 312 | case 0x03: // (Read holding register) 313 | case 0x04: // (Read input register) 314 | if (len == 8) { 315 | // request packet 316 | Modbus.Type = MODBUS_REQUEST; 317 | // Modbus register 318 | Modbus.Register = (buf[2] <<8) | buf[3]; 319 | // Modbus register count 320 | Modbus.RegisterCount = (buf[4] <<8) | buf[5]; 321 | } else { 322 | // Modbus datacount 323 | Modbus.DataLength = buf[2]; 324 | if (Modbus.DataLength == len - 5) { 325 | // packet length OK 326 | // response packet 327 | Modbus.Type = MODBUS_RESPONSE; 328 | #ifdef LOG_WARN_MODBUS 329 | } else { 330 | printf("\nInvalid modbus FC=04 packet"); 331 | #endif 332 | } 333 | } 334 | break; 335 | case 0x06: 336 | // (Write single register) 337 | if (len == 8) { 338 | // request and response packet are the same 339 | Modbus.Type = MODBUS_OK; 340 | // Modbus register 341 | Modbus.Register = (buf[2] <<8) | buf[3]; 342 | // Modbus register count 343 | Modbus.RegisterCount = 1; 344 | // value 345 | Modbus.Value = (buf[4] <<8) | buf[5]; 346 | #ifdef LOG_WARN_MODBUS 347 | } else { 348 | printf("\nInvalid modbus FC=06 packet"); 349 | #endif 350 | } 351 | break; 352 | case 0x10: 353 | // (Write multiple register)) 354 | // Modbus register 355 | Modbus.Register = (buf[2] <<8) | buf[3]; 356 | // Modbus register count 357 | Modbus.RegisterCount = (buf[4] <<8) | buf[5]; 358 | if (len == 8) { 359 | // response packet 360 | Modbus.Type = MODBUS_RESPONSE; 361 | } else { 362 | // Modbus datacount 363 | Modbus.DataLength = buf[6]; 364 | if (Modbus.DataLength == len - 9) { 365 | // packet length OK 366 | // request packet 367 | Modbus.Type = MODBUS_REQUEST; 368 | #ifdef LOG_WARN_MODBUS 369 | } else { 370 | printf("\nInvalid modbus FC=16 packet"); 371 | #endif 372 | } 373 | } 374 | break; 375 | default: 376 | break; 377 | } 378 | 379 | // Modbus.Data 380 | if (Modbus.Type && Modbus.DataLength) { 381 | // Set pointer to Data 382 | Modbus.Data = buf; 383 | // Modbus data is always at the end ahead the checksum 384 | Modbus.Data = Modbus.Data + (len - Modbus.DataLength - 2); 385 | } 386 | 387 | // Request - Response check 388 | switch (Modbus.Type) { 389 | case MODBUS_REQUEST: 390 | Modbus.RequestAddress = Modbus.Address; 391 | Modbus.RequestFunction = Modbus.Function; 392 | Modbus.RequestRegister = Modbus.Register; 393 | break; 394 | case MODBUS_RESPONSE: 395 | // If address and function identical with last send or received request, it is a valid response 396 | if (Modbus.Address == Modbus.RequestAddress && Modbus.Function == Modbus.RequestFunction) { 397 | if (Modbus.Function == 0x03 || Modbus.Function == 0x04) 398 | Modbus.Register = Modbus.RequestRegister; 399 | } 400 | Modbus.RequestAddress = 0; 401 | Modbus.RequestFunction = 0; 402 | Modbus.RequestRegister = 0; 403 | break; 404 | case MODBUS_OK: 405 | // If address and function identical with last send or received request, it is a valid response 406 | if (Modbus.Address == Modbus.RequestAddress && Modbus.Function == Modbus.RequestFunction && Modbus.Address != BROADCAST_ADR) { 407 | Modbus.Type = MODBUS_RESPONSE; 408 | Modbus.RequestAddress = 0; 409 | Modbus.RequestFunction = 0; 410 | Modbus.RequestRegister = 0; 411 | } else { 412 | Modbus.Type = MODBUS_REQUEST; 413 | Modbus.RequestAddress = Modbus.Address; 414 | Modbus.RequestFunction = Modbus.Function; 415 | Modbus.RequestRegister = Modbus.Register; 416 | } 417 | default: 418 | break; 419 | } 420 | } 421 | } 422 | #ifdef LOG_DEBUG_MODBUS 423 | if(Modbus.Type) { 424 | printf(" Register %04x", Modbus.Register); 425 | } 426 | #endif 427 | #ifdef LOG_INFO_MODBUS 428 | switch (Modbus.Type) { 429 | case MODBUS_REQUEST: 430 | printf(" Request"); 431 | break; 432 | case MODBUS_RESPONSE: 433 | printf(" Response"); 434 | break; 435 | } 436 | #endif 437 | } 438 | 439 | 440 | 441 | // ########################### EVSE modbus functions ########################### 442 | 443 | 444 | /** 445 | * Decode measurement value 446 | * 447 | * @param pointer to buf 448 | * @param unsigned char pos 449 | * @param unsigned char Endianness 450 | * @param signed char Divisor 451 | * @return signed long Measurement 452 | */ 453 | signed long receiveMeasurement(unsigned char *buf, unsigned char pos, unsigned char Endianness, bool IsDouble, signed char Divisor) { 454 | signed double dCombined; 455 | signed long lCombined; 456 | 457 | if (IsDouble) { 458 | combineBytes(&dCombined, buf, pos, Endianness); 459 | if (Divisor >= 0) { 460 | lCombined = dCombined / (signed long)pow10[Divisor]; 461 | } else { 462 | lCombined = dCombined * (signed long)pow10[-Divisor]; 463 | } 464 | } else { 465 | combineBytes(&lCombined, buf, pos, Endianness); 466 | if (Divisor >= 0) { 467 | lCombined = lCombined / (signed long)pow10[Divisor]; 468 | } else { 469 | lCombined = lCombined * (signed long)pow10[-Divisor]; 470 | } 471 | } 472 | 473 | return lCombined; 474 | } 475 | 476 | /** 477 | * Send Energy measurement request over modbus 478 | * 479 | * @param unsigned char Meter 480 | * @param unsigned char Address 481 | */ 482 | void requestEnergyMeasurement(unsigned char Meter, unsigned char Address) { 483 | ModbusReadInputRequest(Address, EMConfig[Meter].Function, EMConfig[Meter].ERegister, 2); 484 | } 485 | 486 | /** 487 | * Read energy measurement from modbus 488 | * 489 | * @param pointer to buf 490 | * @param unsigned char Meter 491 | * @return signed long Energy (Wh) 492 | */ 493 | signed long receiveEnergyMeasurement(unsigned char *buf, unsigned char Meter) { 494 | return receiveMeasurement(buf, 0, EMConfig[Meter].Endianness, EMConfig[Meter].IsDouble, EMConfig[Meter].EDivisor - 3); 495 | } 496 | 497 | /** 498 | * Send Power measurement request over modbus 499 | * 500 | * @param unsigned char Meter 501 | * @param unsigned char Address 502 | */ 503 | void requestPowerMeasurement(unsigned char Meter, unsigned char Address) { 504 | ModbusReadInputRequest(Address, EMConfig[Meter].Function, EMConfig[Meter].PRegister, 2); 505 | } 506 | 507 | /** 508 | * Read Power measurement from modbus 509 | * 510 | * @param pointer to buf 511 | * @param unsigned char Meter 512 | * @return signed long Power (W) 513 | */ 514 | signed long receivePowerMeasurement(unsigned char *buf, unsigned char Meter) { 515 | return receiveMeasurement(buf, 0, EMConfig[Meter].Endianness, EMConfig[Meter].IsDouble, EMConfig[Meter].PDivisor); 516 | } 517 | 518 | /** 519 | * Send current measurement request over modbus 520 | * 521 | * @param unsigned char Meter 522 | * @param unsigned char Address 523 | */ 524 | void requestCurrentMeasurement(unsigned char Meter, unsigned char Address) { 525 | switch(Meter) { 526 | case EM_SENSORBOX: 527 | ModbusReadInputRequest(Address, 4, 0, 20); 528 | break; 529 | case EM_EASTRON: 530 | // Phase 1-3 current: Register 0x06 - 0x0B (unsigned) 531 | // Phase 1-3 power: Register 0x0C - 0x11 (signed) 532 | ModbusReadInputRequest(Address, 4, 0x06, 12); 533 | break; 534 | case EM_ABB: 535 | // Phase 1-3 current: Register 0x5B0C - 0x5B11 (unsigned) 536 | // Phase 1-3 power: Register 0x5B16 - 0x5B1B (signed) 537 | ModbusReadInputRequest(Address, 3, 0x5B0C, 16); 538 | break; 539 | default: 540 | ModbusReadInputRequest(Address, EMConfig[Meter].Function, EMConfig[Meter].IRegister, 6); 541 | break; 542 | } 543 | } 544 | 545 | /** 546 | * Read current measurement from modbus 547 | * 548 | * @param pointer to buf 549 | * @param unsigned char Meter 550 | * @param pointer to Current (mA) 551 | * @return unsigned char error 552 | */ 553 | unsigned char receiveCurrentMeasurement(unsigned char *buf, unsigned char Meter, signed long *var) { 554 | unsigned char x, offset; 555 | 556 | // No CAL option in Menu 557 | CalActive = 0; 558 | 559 | switch(Meter) { 560 | case EM_SENSORBOX: 561 | // return immediately if the data contains no new P1 or CT measurement 562 | if (buf[3] == 0) return 0; // error!! 563 | // determine if there is P1 data present, otherwise use CT data 564 | if (buf[3] & 0x80) offset = 16; // P1 data present 565 | else offset = 28; // Use CTs 566 | // offset 16 is Smart meter P1 current 567 | for (x = 0; x < 3; x++) { 568 | // SmartEVSE works with Amps * 10 569 | var[x] = receiveMeasurement(buf, offset + (x * 4), EMConfig[Meter].Endianness, EMConfig[Meter].IsDouble, EMConfig[Meter].IDivisor - 3); 570 | // When using CT's , adjust the measurements with calibration value 571 | if (offset == 28) { 572 | if (x == 0) Iuncal = abs((var[x]/10)); // Store uncalibrated CT1 measurement (10mA) 573 | var[x] = (signed long)var[x] * (signed int)ICal / ICAL; 574 | // When MaxMains is set to >100A, it's assumed 200A:50ma CT's are used. 575 | if (MaxMains > 100) var[x] = var[x] * 2; // Multiply measured currents with 2 576 | // very small negative currents are shown as zero. 577 | if ((var[x] > -1) && (var[x] < 1)) var[x] = 0; 578 | CalActive = 1; // Enable CAL option in Menu 579 | } 580 | } 581 | // Set Sensorbox 2 to 3/4 Wire configuration (and phase Rotation) (v2.16) 582 | if (buf[1] >= 0x10 && offset == 28) { 583 | GridActive = 1; // Enable the GRID menu option 584 | #ifdef SPECIAL // Only when Load balancing is Disabled/Master 585 | if ((buf[1] & 0x3) != GRID && (LoadBl < 2)) ModbusWriteSingleRequest(0x0A, 0x800, GRID); 586 | #else 587 | if ((buf[1] & 0x3) != (Grid << 1) && (LoadBl < 2)) ModbusWriteSingleRequest(0x0A, 0x800, Grid << 1); 588 | #endif 589 | } else GridActive = 0; 590 | break; 591 | default: 592 | for (x = 0; x < 3; x++) { 593 | var[x] = receiveMeasurement(buf, (x * 4), EMConfig[Meter].Endianness, EMConfig[Meter].IsDouble, EMConfig[Meter].IDivisor - 3); 594 | } 595 | break; 596 | } 597 | 598 | // Get sign from power measurement on some electric meters 599 | switch(Meter) { 600 | case EM_EASTRON: 601 | for (x = 0; x < 3; x++) { 602 | if (receiveMeasurement(buf, ((x + 3) * 4), EMConfig[Meter].Endianness, EMConfig[Meter].IsDouble, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x]; 603 | } 604 | break; 605 | case EM_ABB: 606 | for (x = 0; x < 3; x++) { 607 | if (receiveMeasurement(buf, ((x + 5) * 4), EMConfig[Meter].Endianness, EMConfig[Meter].IsDouble, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x]; 608 | } 609 | break; 610 | } 611 | 612 | // all OK 613 | return 1; 614 | } 615 | 616 | /** 617 | * Map a Modbus register to an item ID (MENU_xxx or STATUS_xxx) 618 | * 619 | * @return unsigned char ItemID 620 | */ 621 | unsigned char mapModbusRegister2ItemID() { 622 | unsigned int RegisterStart, ItemStart, Count; 623 | 624 | // Register 0x0*: Node -> Master 625 | if (Modbus.Register == 0x01) { 626 | return 255; 627 | // Do not change Charge Mode when set to Normal or Load Balancing is disabled 628 | } else if (Modbus.Register == 0xA8 && (Mode == 0 || LoadBl == 0) ) { 629 | return 255; 630 | 631 | // Register 0xA*: Status 632 | } else if (Modbus.Register >= MODBUS_EVSE_STATUS_START && Modbus.Register <= MODBUS_EVSE_STATUS_END) { 633 | RegisterStart = MODBUS_EVSE_STATUS_START; 634 | ItemStart = STATUS_STATE; 635 | Count = MODBUS_EVSE_STATUS_END - MODBUS_EVSE_STATUS_START + 1; 636 | 637 | // Register 0xC*: Configuration 638 | } else if (Modbus.Register >= MODBUS_EVSE_CONFIG_START && Modbus.Register <= MODBUS_EVSE_CONFIG_END) { 639 | RegisterStart = MODBUS_EVSE_CONFIG_START; 640 | ItemStart = MENU_CONFIG; 641 | Count = MODBUS_EVSE_CONFIG_END - MODBUS_EVSE_CONFIG_START + 1; 642 | 643 | // Register 0xE*: Load balancing configuration (same on all SmartEVSE) 644 | } else if (Modbus.Register >= MODBUS_SYS_CONFIG_START && Modbus.Register <= MODBUS_SYS_CONFIG_END) { 645 | RegisterStart = MODBUS_SYS_CONFIG_START; 646 | ItemStart = MENU_CIRCUIT; 647 | Count = MODBUS_SYS_CONFIG_END - MODBUS_SYS_CONFIG_START + 1; 648 | 649 | } else { 650 | return 0; 651 | } 652 | 653 | if (Modbus.RegisterCount <= (RegisterStart + Count) - Modbus.Register) { 654 | return (Modbus.Register - RegisterStart + ItemStart); 655 | } else { 656 | return 0; 657 | } 658 | } 659 | 660 | /** 661 | * Read item values and send modbus response 662 | */ 663 | void ReadItemValueResponse(void) { 664 | unsigned char ItemID; 665 | unsigned char i; 666 | unsigned int values[12]; 667 | 668 | ItemID = mapModbusRegister2ItemID(); 669 | if (ItemID == 255) return; 670 | 671 | if (ItemID) { 672 | for (i = 0; i < Modbus.RegisterCount; i++) { 673 | values[i] = getItemValue(ItemID + i); 674 | } 675 | ModbusReadInputResponse(Modbus.Address, Modbus.Function, values, Modbus.RegisterCount); 676 | } else { 677 | ModbusException(Modbus.Address, Modbus.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS); 678 | } 679 | } 680 | 681 | /** 682 | * Write item values and send modbus response 683 | */ 684 | void WriteItemValueResponse(void) { 685 | unsigned char ItemID; 686 | unsigned char OK = 0; 687 | 688 | ItemID = mapModbusRegister2ItemID(); 689 | if (ItemID == 255) return; 690 | 691 | if (ItemID) { 692 | OK = setItemValue(ItemID, Modbus.Value); 693 | } 694 | 695 | if (OK && ItemID < STATUS_STATE) write_settings(); 696 | 697 | if (Modbus.Address != BROADCAST_ADR || LoadBl == 0) { 698 | if (!ItemID) { 699 | ModbusException(Modbus.Address, Modbus.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS); 700 | } else if (!OK) { 701 | ModbusException(Modbus.Address, Modbus.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE); 702 | } else { 703 | ModbusWriteSingleResponse(Modbus.Address, Modbus.Register, Modbus.Value); 704 | } 705 | } 706 | } 707 | 708 | /** 709 | * Write multiple item values and send modbus response 710 | */ 711 | void WriteMultipleItemValueResponse(void) { 712 | unsigned char ItemID; 713 | unsigned int i, OK = 0, value; 714 | 715 | ItemID = mapModbusRegister2ItemID(); 716 | if (ItemID == 255) return; 717 | 718 | if (ItemID) { 719 | for (i = 0; i < Modbus.RegisterCount; i++) { 720 | value = (Modbus.Data[i * 2] <<8) | Modbus.Data[(i * 2) + 1]; 721 | OK += setItemValue(ItemID + i, value); 722 | } 723 | } 724 | 725 | if (OK && ItemID < STATUS_STATE) write_settings(); 726 | 727 | if (Modbus.Address != BROADCAST_ADR || LoadBl == 0) { 728 | if (!ItemID) { 729 | ModbusException(Modbus.Address, Modbus.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS); 730 | } else if (!OK) { 731 | ModbusException(Modbus.Address, Modbus.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE); 732 | } else { 733 | ModbusWriteMultipleResponse(Modbus.Address, Modbus.Register, OK); 734 | } 735 | } 736 | } 737 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/modbus.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | struct { 26 | unsigned char Address; 27 | unsigned char Function; 28 | unsigned int Register; 29 | unsigned int RegisterCount; 30 | unsigned int Value; 31 | unsigned char *Data; 32 | unsigned char DataLength; 33 | unsigned char Type; 34 | unsigned char RequestAddress; 35 | unsigned char RequestFunction; 36 | unsigned int RequestRegister; 37 | unsigned char Exception; 38 | } Modbus; 39 | 40 | // ########################### Modbus main functions ########################### 41 | 42 | void ModbusReadInputRequest(unsigned char address, unsigned char function, unsigned int reg, unsigned int quantity); 43 | void ModbusReadInputResponse(unsigned char address, unsigned char function, unsigned int *values, unsigned char count); 44 | void ModbusWriteSingleRequest(unsigned char address, unsigned int reg, unsigned int value); 45 | void ModbusWriteSingleResponse(unsigned char address, unsigned int reg, unsigned int value); 46 | void ModbusWriteMultipleRequest(unsigned char address, unsigned int reg, unsigned int *values, unsigned char count); 47 | void ModbusWriteMultipleResponse(unsigned char address, unsigned int reg, unsigned int count); 48 | void ModbusException(unsigned char address, unsigned char function, unsigned char exception); 49 | void ModbusDecode(unsigned char *buf, unsigned char len); 50 | 51 | // ########################### EVSE modbus functions ########################### 52 | 53 | signed long receiveMeasurement(unsigned char *buf, unsigned char pos, unsigned char Endianness, bool IsDouble, signed char Divisor); 54 | void requestEnergyMeasurement(unsigned char Meter, unsigned char Address); 55 | signed long receiveEnergyMeasurement(unsigned char *buf, unsigned char Meter); 56 | void requestPowerMeasurement(unsigned char Meter, unsigned char Address); 57 | signed long receivePowerMeasurement(unsigned char *buf, unsigned char Meter); 58 | void requestCurrentMeasurement(unsigned char Meter, unsigned char Address); 59 | unsigned char receiveCurrentMeasurement(unsigned char *buf, unsigned char Meter, signed long *var); 60 | 61 | void ReadItemValueResponse(void); 62 | void WriteItemValueResponse(void); 63 | void WriteMultipleItemValueResponse(void); 64 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/Makefile-default.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Generated Makefile - do not edit! 3 | # 4 | # Edit the Makefile in the project folder instead (../Makefile). Each target 5 | # has a -pre and a -post target defined where you can add customized code. 6 | # 7 | # This makefile implements configuration specific macros and targets. 8 | 9 | 10 | # Include project Makefile 11 | ifeq "${IGNORE_LOCAL}" "TRUE" 12 | # do not include local makefile. User is passing all local related variables already 13 | else 14 | include Makefile 15 | # Include makefile containing local settings 16 | ifeq "$(wildcard nbproject/Makefile-local-default.mk)" "nbproject/Makefile-local-default.mk" 17 | include nbproject/Makefile-local-default.mk 18 | endif 19 | endif 20 | 21 | # Environment 22 | MKDIR=gnumkdir -p 23 | RM=rm -f 24 | MV=mv 25 | CP=cp 26 | 27 | # Macros 28 | CND_CONF=default 29 | ifeq ($(TYPE_IMAGE), DEBUG_RUN) 30 | IMAGE_TYPE=debug 31 | OUTPUT_SUFFIX=elf 32 | DEBUGGABLE_SUFFIX=elf 33 | FINAL_IMAGE=dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} 34 | else 35 | IMAGE_TYPE=production 36 | OUTPUT_SUFFIX=hex 37 | DEBUGGABLE_SUFFIX=elf 38 | FINAL_IMAGE=dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} 39 | endif 40 | 41 | ifeq ($(COMPARE_BUILD), true) 42 | COMPARISON_BUILD=-mafrlcsj 43 | else 44 | COMPARISON_BUILD= 45 | endif 46 | 47 | ifdef SUB_IMAGE_ADDRESS 48 | 49 | else 50 | SUB_IMAGE_ADDRESS_COMMAND= 51 | endif 52 | 53 | # Object Directory 54 | OBJECTDIR=build/${CND_CONF}/${IMAGE_TYPE} 55 | 56 | # Distribution Directory 57 | DISTDIR=dist/${CND_CONF}/${IMAGE_TYPE} 58 | 59 | # Source Files Quoted if spaced 60 | SOURCEFILES_QUOTED_IF_SPACED=EVSE.c GLCD.c bootloader.c utils.c 61 | 62 | # Object Files Quoted if spaced 63 | OBJECTFILES_QUOTED_IF_SPACED=${OBJECTDIR}/EVSE.p1 ${OBJECTDIR}/GLCD.p1 ${OBJECTDIR}/bootloader.p1 ${OBJECTDIR}/utils.p1 64 | POSSIBLE_DEPFILES=${OBJECTDIR}/EVSE.p1.d ${OBJECTDIR}/GLCD.p1.d ${OBJECTDIR}/bootloader.p1.d ${OBJECTDIR}/utils.p1.d 65 | 66 | # Object Files 67 | OBJECTFILES=${OBJECTDIR}/EVSE.p1 ${OBJECTDIR}/GLCD.p1 ${OBJECTDIR}/bootloader.p1 ${OBJECTDIR}/utils.p1 68 | 69 | # Source Files 70 | SOURCEFILES=EVSE.c GLCD.c bootloader.c utils.c 71 | 72 | 73 | 74 | CFLAGS= 75 | ASFLAGS= 76 | LDLIBSOPTIONS= 77 | 78 | ############# Tool locations ########################################## 79 | # If you copy a project from one host to another, the path where the # 80 | # compiler is installed may be different. # 81 | # If you open this project with MPLAB X in the new host, this # 82 | # makefile will be regenerated and the paths will be corrected. # 83 | ####################################################################### 84 | # fixDeps replaces a bunch of sed/cat/printf statements that slow down the build 85 | FIXDEPS=fixDeps 86 | 87 | .build-conf: ${BUILD_SUBPROJECTS} 88 | ifneq ($(INFORMATION_MESSAGE), ) 89 | @echo $(INFORMATION_MESSAGE) 90 | endif 91 | ${MAKE} -f nbproject/Makefile-default.mk dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} 92 | 93 | MP_PROCESSOR_OPTION=18F26K22 94 | # ------------------------------------------------------------------------------------ 95 | # Rules for buildStep: compile 96 | ifeq ($(TYPE_IMAGE), DEBUG_RUN) 97 | ${OBJECTDIR}/EVSE.p1: EVSE.c nbproject/Makefile-${CND_CONF}.mk 98 | @${MKDIR} "${OBJECTDIR}" 99 | @${RM} ${OBJECTDIR}/EVSE.p1.d 100 | @${RM} ${OBJECTDIR}/EVSE.p1 101 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -D__DEBUG=1 -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/EVSE.p1 EVSE.c 102 | @-${MV} ${OBJECTDIR}/EVSE.d ${OBJECTDIR}/EVSE.p1.d 103 | @${FIXDEPS} ${OBJECTDIR}/EVSE.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 104 | 105 | ${OBJECTDIR}/GLCD.p1: GLCD.c nbproject/Makefile-${CND_CONF}.mk 106 | @${MKDIR} "${OBJECTDIR}" 107 | @${RM} ${OBJECTDIR}/GLCD.p1.d 108 | @${RM} ${OBJECTDIR}/GLCD.p1 109 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -D__DEBUG=1 -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/GLCD.p1 GLCD.c 110 | @-${MV} ${OBJECTDIR}/GLCD.d ${OBJECTDIR}/GLCD.p1.d 111 | @${FIXDEPS} ${OBJECTDIR}/GLCD.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 112 | 113 | ${OBJECTDIR}/bootloader.p1: bootloader.c nbproject/Makefile-${CND_CONF}.mk 114 | @${MKDIR} "${OBJECTDIR}" 115 | @${RM} ${OBJECTDIR}/bootloader.p1.d 116 | @${RM} ${OBJECTDIR}/bootloader.p1 117 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -D__DEBUG=1 -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/bootloader.p1 bootloader.c 118 | @-${MV} ${OBJECTDIR}/bootloader.d ${OBJECTDIR}/bootloader.p1.d 119 | @${FIXDEPS} ${OBJECTDIR}/bootloader.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 120 | 121 | ${OBJECTDIR}/utils.p1: utils.c nbproject/Makefile-${CND_CONF}.mk 122 | @${MKDIR} "${OBJECTDIR}" 123 | @${RM} ${OBJECTDIR}/utils.p1.d 124 | @${RM} ${OBJECTDIR}/utils.p1 125 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -D__DEBUG=1 -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/utils.p1 utils.c 126 | @-${MV} ${OBJECTDIR}/utils.d ${OBJECTDIR}/utils.p1.d 127 | @${FIXDEPS} ${OBJECTDIR}/utils.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 128 | 129 | else 130 | ${OBJECTDIR}/EVSE.p1: EVSE.c nbproject/Makefile-${CND_CONF}.mk 131 | @${MKDIR} "${OBJECTDIR}" 132 | @${RM} ${OBJECTDIR}/EVSE.p1.d 133 | @${RM} ${OBJECTDIR}/EVSE.p1 134 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/EVSE.p1 EVSE.c 135 | @-${MV} ${OBJECTDIR}/EVSE.d ${OBJECTDIR}/EVSE.p1.d 136 | @${FIXDEPS} ${OBJECTDIR}/EVSE.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 137 | 138 | ${OBJECTDIR}/GLCD.p1: GLCD.c nbproject/Makefile-${CND_CONF}.mk 139 | @${MKDIR} "${OBJECTDIR}" 140 | @${RM} ${OBJECTDIR}/GLCD.p1.d 141 | @${RM} ${OBJECTDIR}/GLCD.p1 142 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/GLCD.p1 GLCD.c 143 | @-${MV} ${OBJECTDIR}/GLCD.d ${OBJECTDIR}/GLCD.p1.d 144 | @${FIXDEPS} ${OBJECTDIR}/GLCD.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 145 | 146 | ${OBJECTDIR}/bootloader.p1: bootloader.c nbproject/Makefile-${CND_CONF}.mk 147 | @${MKDIR} "${OBJECTDIR}" 148 | @${RM} ${OBJECTDIR}/bootloader.p1.d 149 | @${RM} ${OBJECTDIR}/bootloader.p1 150 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/bootloader.p1 bootloader.c 151 | @-${MV} ${OBJECTDIR}/bootloader.d ${OBJECTDIR}/bootloader.p1.d 152 | @${FIXDEPS} ${OBJECTDIR}/bootloader.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 153 | 154 | ${OBJECTDIR}/utils.p1: utils.c nbproject/Makefile-${CND_CONF}.mk 155 | @${MKDIR} "${OBJECTDIR}" 156 | @${RM} ${OBJECTDIR}/utils.p1.d 157 | @${RM} ${OBJECTDIR}/utils.p1 158 | ${MP_CC} $(MP_EXTRA_CC_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -c -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=$(CND_CONF) -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib $(COMPARISON_BUILD) -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto -o ${OBJECTDIR}/utils.p1 utils.c 159 | @-${MV} ${OBJECTDIR}/utils.d ${OBJECTDIR}/utils.p1.d 160 | @${FIXDEPS} ${OBJECTDIR}/utils.p1.d $(SILENT) -rsi ${MP_CC_DIR}../ 161 | 162 | endif 163 | 164 | # ------------------------------------------------------------------------------------ 165 | # Rules for buildStep: assemble 166 | ifeq ($(TYPE_IMAGE), DEBUG_RUN) 167 | else 168 | endif 169 | 170 | # ------------------------------------------------------------------------------------ 171 | # Rules for buildStep: assembleWithPreprocess 172 | ifeq ($(TYPE_IMAGE), DEBUG_RUN) 173 | else 174 | endif 175 | 176 | # ------------------------------------------------------------------------------------ 177 | # Rules for buildStep: link 178 | ifeq ($(TYPE_IMAGE), DEBUG_RUN) 179 | dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}: ${OBJECTFILES} nbproject/Makefile-${CND_CONF}.mk 180 | @${MKDIR} dist/${CND_CONF}/${IMAGE_TYPE} 181 | ${MP_CC} $(MP_EXTRA_LD_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -Wl,-Map=dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.map -D__DEBUG=1 -DXPRJ_default=$(CND_CONF) -Wl,--defsym=__MPLAB_BUILD=1 -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto $(COMPARISON_BUILD) -Wl,--memorysummary,dist/${CND_CONF}/${IMAGE_TYPE}/memoryfile.xml -o dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${DEBUGGABLE_SUFFIX} ${OBJECTFILES_QUOTED_IF_SPACED} 182 | @${RM} dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.hex 183 | 184 | else 185 | dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}: ${OBJECTFILES} nbproject/Makefile-${CND_CONF}.mk 186 | @${MKDIR} dist/${CND_CONF}/${IMAGE_TYPE} 187 | ${MP_CC} $(MP_EXTRA_LD_PRE) -mcpu=$(MP_PROCESSOR_OPTION) -Wl,-Map=dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.map -DXPRJ_default=$(CND_CONF) -Wl,--defsym=__MPLAB_BUILD=1 -fno-short-double -fno-short-float -memi=wordwrite -mrom=0-FCFB -O3 -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-download -mdefault-config-bits -mc90lib -std=c90 -gdwarf-3 -mstack=compiled:auto:auto:auto $(COMPARISON_BUILD) -Wl,--memorysummary,dist/${CND_CONF}/${IMAGE_TYPE}/memoryfile.xml -o dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${DEBUGGABLE_SUFFIX} ${OBJECTFILES_QUOTED_IF_SPACED} 188 | 189 | endif 190 | 191 | 192 | # Subprojects 193 | .build-subprojects: 194 | 195 | 196 | # Subprojects 197 | .clean-subprojects: 198 | 199 | # Clean Targets 200 | .clean-conf: ${CLEAN_SUBPROJECTS} 201 | ${RM} -r build/default 202 | ${RM} -r dist/default 203 | 204 | # Enable dependency checking 205 | .dep.inc: .depcheck-impl 206 | 207 | DEPFILES=$(shell mplabwildcard ${POSSIBLE_DEPFILES}) 208 | ifneq (${DEPFILES},) 209 | include ${DEPFILES} 210 | endif 211 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/Makefile-genesis.properties: -------------------------------------------------------------------------------- 1 | # 2 | #Tue May 26 14:12:51 CEST 2020 3 | default.Pack.dfplocation=C\:\\Program Files (x86)\\Microchip\\MPLABX\\v5.25\\packs\\Microchip\\PIC18F-K_DFP\\1.1.58 4 | default.languagetoolchain.dir=C\:\\Program Files (x86)\\Microchip\\xc8\\v2.10\\bin 5 | configurations-xml=d70c476e0ecc946eb258dff8e2ab36d8 6 | com-microchip-mplab-nbide-embedded-makeproject-MakeProject.md5=6e453b0cf7f7da72a932cfdb2f655401 7 | default.languagetoolchain.version=2.10 8 | host.platform=windows 9 | conf.ids=default 10 | default.com-microchip-mplab-nbide-toolchainXC8-XC8LanguageToolchain.md5=23d12c447ed4f9462f01e2202bc2f36a 11 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/Makefile-impl.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Generated Makefile - do not edit! 3 | # 4 | # Edit the Makefile in the project folder instead (../Makefile). Each target 5 | # has a pre- and a post- target defined where you can add customization code. 6 | # 7 | # This makefile implements macros and targets common to all configurations. 8 | # 9 | # NOCDDL 10 | 11 | 12 | # Building and Cleaning subprojects are done by default, but can be controlled with the SUB 13 | # macro. If SUB=no, subprojects will not be built or cleaned. The following macro 14 | # statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf 15 | # and .clean-reqprojects-conf unless SUB has the value 'no' 16 | SUB_no=NO 17 | SUBPROJECTS=${SUB_${SUB}} 18 | BUILD_SUBPROJECTS_=.build-subprojects 19 | BUILD_SUBPROJECTS_NO= 20 | BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} 21 | CLEAN_SUBPROJECTS_=.clean-subprojects 22 | CLEAN_SUBPROJECTS_NO= 23 | CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} 24 | 25 | 26 | # Project Name 27 | PROJECTNAME=SmartEVSE2.X 28 | 29 | # Active Configuration 30 | DEFAULTCONF=default 31 | CONF=${DEFAULTCONF} 32 | 33 | # All Configurations 34 | ALLCONFS=default 35 | 36 | 37 | # build 38 | .build-impl: .build-pre 39 | ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf 40 | 41 | 42 | # clean 43 | .clean-impl: .clean-pre 44 | ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf 45 | 46 | # clobber 47 | .clobber-impl: .clobber-pre .depcheck-impl 48 | ${MAKE} SUBPROJECTS=${SUBPROJECTS} CONF=default clean 49 | 50 | 51 | 52 | # all 53 | .all-impl: .all-pre .depcheck-impl 54 | ${MAKE} SUBPROJECTS=${SUBPROJECTS} CONF=default build 55 | 56 | 57 | 58 | # dependency checking support 59 | .depcheck-impl: 60 | # @echo "# This code depends on make tool being used" >.dep.inc 61 | # @if [ -n "${MAKE_VERSION}" ]; then \ 62 | # echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES}))" >>.dep.inc; \ 63 | # echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ 64 | # echo "include \$${DEPFILES}" >>.dep.inc; \ 65 | # echo "endif" >>.dep.inc; \ 66 | # else \ 67 | # echo ".KEEP_STATE:" >>.dep.inc; \ 68 | # echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ 69 | # fi 70 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/Makefile-local-default.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Generated Makefile - do not edit! 3 | # 4 | # 5 | # This file contains information about the location of compilers and other tools. 6 | # If you commmit this file into your revision control server, you will be able to 7 | # to checkout the project and build it from the command line with make. However, 8 | # if more than one person works on the same project, then this file might show 9 | # conflicts since different users are bound to have compilers in different places. 10 | # In that case you might choose to not commit this file and let MPLAB X recreate this file 11 | # for each user. The disadvantage of not commiting this file is that you must run MPLAB X at 12 | # least once so the file gets created and the project can be built. Finally, you can also 13 | # avoid using this file at all if you are only building from the command line with make. 14 | # You can invoke make with the values of the macros: 15 | # $ makeMP_CC="/opt/microchip/mplabc30/v3.30c/bin/pic30-gcc" ... 16 | # 17 | SHELL=cmd.exe 18 | PATH_TO_IDE_BIN=C:/Program Files (x86)/Microchip/MPLABX/v5.25/mplab_platform/platform/../mplab_ide/modules/../../bin/ 19 | # Adding MPLAB X bin directory to path. 20 | PATH:=C:/Program Files (x86)/Microchip/MPLABX/v5.25/mplab_platform/platform/../mplab_ide/modules/../../bin/:$(PATH) 21 | # Path to java used to run MPLAB X when this makefile was created 22 | MP_JAVA_PATH="C:\Program Files (x86)\Microchip\MPLABX\v5.25\sys\java\jre1.8.0_181/bin/" 23 | OS_CURRENT="$(shell uname -s)" 24 | MP_CC="C:\Program Files (x86)\Microchip\xc8\v2.10\bin\xc8-cc.exe" 25 | # MP_CPPC is not defined 26 | # MP_BC is not defined 27 | MP_AS="C:\Program Files (x86)\Microchip\xc8\v2.10\bin\xc8-cc.exe" 28 | MP_LD="C:\Program Files (x86)\Microchip\xc8\v2.10\bin\xc8-cc.exe" 29 | MP_AR="C:\Program Files (x86)\Microchip\xc8\v2.10\bin\xc8-ar.exe" 30 | DEP_GEN=${MP_JAVA_PATH}java -jar "C:/Program Files (x86)/Microchip/MPLABX/v5.25/mplab_platform/platform/../mplab_ide/modules/../../bin/extractobjectdependencies.jar" 31 | MP_CC_DIR="C:\Program Files (x86)\Microchip\xc8\v2.10\bin" 32 | # MP_CPPC_DIR is not defined 33 | # MP_BC_DIR is not defined 34 | MP_AS_DIR="C:\Program Files (x86)\Microchip\xc8\v2.10\bin" 35 | MP_LD_DIR="C:\Program Files (x86)\Microchip\xc8\v2.10\bin" 36 | MP_AR_DIR="C:\Program Files (x86)\Microchip\xc8\v2.10\bin" 37 | # MP_BC_DIR is not defined 38 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/Makefile-variables.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Generated - do not edit! 3 | # 4 | # NOCDDL 5 | # 6 | CND_BASEDIR=`pwd` 7 | # default configuration 8 | CND_ARTIFACT_DIR_default=dist/default/production 9 | CND_ARTIFACT_NAME_default=SmartEVSE2.X.production.hex 10 | CND_ARTIFACT_PATH_default=dist/default/production/SmartEVSE2.X.production.hex 11 | CND_PACKAGE_DIR_default=${CND_DISTDIR}/default/package 12 | CND_PACKAGE_NAME_default=smartevse2.x.tar 13 | CND_PACKAGE_PATH_default=${CND_DISTDIR}/default/package/smartevse2.x.tar 14 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/Package-default.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # 4 | # Generated - do not edit! 5 | # 6 | 7 | # Macros 8 | TOP=`pwd` 9 | CND_CONF=default 10 | CND_DISTDIR=dist 11 | TMPDIR=build/${CND_CONF}/${IMAGE_TYPE}/tmp-packaging 12 | TMPDIRNAME=tmp-packaging 13 | OUTPUT_PATH=dist/${CND_CONF}/${IMAGE_TYPE}/SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} 14 | OUTPUT_BASENAME=SmartEVSE2.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} 15 | PACKAGE_TOP_DIR=smartevse2.x/ 16 | 17 | # Functions 18 | function checkReturnCode 19 | { 20 | rc=$? 21 | if [ $rc != 0 ] 22 | then 23 | exit $rc 24 | fi 25 | } 26 | function makeDirectory 27 | # $1 directory path 28 | # $2 permission (optional) 29 | { 30 | mkdir -p "$1" 31 | checkReturnCode 32 | if [ "$2" != "" ] 33 | then 34 | chmod $2 "$1" 35 | checkReturnCode 36 | fi 37 | } 38 | function copyFileToTmpDir 39 | # $1 from-file path 40 | # $2 to-file path 41 | # $3 permission 42 | { 43 | cp "$1" "$2" 44 | checkReturnCode 45 | if [ "$3" != "" ] 46 | then 47 | chmod $3 "$2" 48 | checkReturnCode 49 | fi 50 | } 51 | 52 | # Setup 53 | cd "${TOP}" 54 | mkdir -p ${CND_DISTDIR}/${CND_CONF}/package 55 | rm -rf ${TMPDIR} 56 | mkdir -p ${TMPDIR} 57 | 58 | # Copy files and create directories and links 59 | cd "${TOP}" 60 | makeDirectory ${TMPDIR}/smartevse2.x/bin 61 | copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 62 | 63 | 64 | # Generate tar file 65 | cd "${TOP}" 66 | rm -f ${CND_DISTDIR}/${CND_CONF}/package/smartevse2.x.tar 67 | cd ${TMPDIR} 68 | tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/package/smartevse2.x.tar * 69 | checkReturnCode 70 | 71 | # Cleanup 72 | cd "${TOP}" 73 | rm -rf ${TMPDIR} 74 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/configurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | EVSE.h 8 | GLCD.h 9 | bootloader.h 10 | utils.h 11 | modbus.h 12 | OneWire.h 13 | 14 | 17 | 18 | 21 | EVSE.c 22 | GLCD.c 23 | bootloader.c 24 | utils.c 25 | modbus.c 26 | OneWire.c 27 | 28 | 31 | Makefile 32 | 33 | 34 | 35 | . 36 | 37 | Makefile 38 | 39 | 40 | 41 | localhost 42 | PIC18F26K22 43 | 44 | 45 | 46 | XC8 47 | 2.30 48 | 2 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | false 64 | false 65 | 66 | 67 | 68 | 69 | 70 | 71 | false 72 | 73 | false 74 | 75 | false 76 | false 77 | false 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microchip.mplab.nbide.embedded.makeproject 4 | 5 | 6 | SmartEVSE2 7 | fdb4042a-930b-4408-84eb-a906493948a2 8 | 0 9 | c 10 | 11 | h 12 | 13 | ISO-8859-1 14 | 15 | 16 | . 17 | 18 | 19 | 20 | default 21 | 2 22 | 23 | 24 | 25 | false 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "EVSE.h" 30 | #include "utils.h" 31 | 32 | 33 | unsigned char crc8(unsigned char *buf, unsigned char len) { 34 | unsigned char crc = 0, i, mix, inbyte; 35 | 36 | while (len--) { 37 | inbyte = *buf++; 38 | for (i = 8; i; i--) { 39 | mix = (crc ^ inbyte) & 0x01; 40 | crc >>= 1; 41 | if (mix) crc ^= 0x8C; 42 | inbyte >>= 1; 43 | } 44 | } 45 | return crc; 46 | } 47 | 48 | /** 49 | * Calculates 16-bit CRC of given data 50 | * used for Frame Check Sequence on data frame 51 | * 52 | * @param unsigned char pointer to buffer 53 | * @param unsigned char length of buffer 54 | * @return unsigned int CRC 55 | */ 56 | unsigned int crc16(unsigned char *buf, unsigned char len) { 57 | unsigned int pos, crc = 0xffff; 58 | unsigned char i; 59 | 60 | // Poly used is x^16+x^15+x^2+x 61 | for (pos = 0; pos < len; pos++) { 62 | crc ^= (unsigned int)buf[pos]; // XOR byte into least sig. byte of crc 63 | 64 | for (i = 8; i != 0; i--) { // Loop over each bit 65 | if ((crc & 0x0001) != 0) { // If the LSB is set 66 | crc >>= 1; // Shift right and XOR 0xA001 67 | crc ^= 0xA001; 68 | } else // Else LSB is not set 69 | crc >>= 1; // Just shift right 70 | } 71 | } 72 | 73 | return crc; 74 | } 75 | 76 | /** 77 | * Delay for number of mS (blocking) 78 | * 79 | * @param unsigned int d: Number or milliseconds 80 | */ 81 | void delay(unsigned int d) { 82 | unsigned long x; 83 | x = Timer; // read Timer value (increased every ms) 84 | while (Timer < (x + d)); 85 | } 86 | 87 | /** 88 | * Insert rounded value into string in printf style 89 | * 90 | * @param pointer to string 91 | * @param string Format 92 | * @param signed long Value to round and insert 93 | * @param unsinged char Divisor where to set decimal point 94 | * @param unsigned char Decimal place count 95 | */ 96 | void sprintfl(unsigned char *str, const unsigned char *Format, signed long Value, unsigned char Divisor, unsigned char Decimal) { 97 | signed long val; 98 | 99 | val = Value / (signed long) pow10[Divisor - Decimal - 1]; 100 | // Round value 101 | if(val < 0) val -= 5; 102 | else val += 5; 103 | val /= 10; 104 | // Split value 105 | if(Decimal > 0) sprintf(str, Format, (signed int) (val / (signed long) pow10[Decimal]), (unsigned int) (abs(val) % pow10[Decimal])); 106 | else sprintf(str, Format, (signed int) val); 107 | } 108 | 109 | /* triwave8: triangle (sawtooth) wave generator. Useful for 110 | turning a one-byte ever-increasing value into a 111 | one-byte value that oscillates up and down. 112 | 113 | input output 114 | 0..127 0..254 (positive slope) 115 | 128..255 254..0 (negative slope) 116 | */ 117 | unsigned char triwave8(unsigned char in) { 118 | if (in & 0x80) { 119 | in = 255u - in; 120 | } 121 | unsigned char out = in << 1; 122 | return out; 123 | } 124 | 125 | unsigned char scale8(unsigned char i, unsigned char scale) { 126 | return (((unsigned int) i) * (1 + (unsigned int) (scale))) >> 8; 127 | } 128 | 129 | /* easing functions; see http://easings.net 130 | 131 | ease8InOutQuad: 8-bit quadratic ease-in / ease-out function 132 | */ 133 | unsigned char ease8InOutQuad(unsigned char i) { 134 | unsigned char j = i; 135 | if (j & 0x80) { 136 | j = 255u - j; 137 | } 138 | unsigned char jj = scale8(j, j); 139 | unsigned char jj2 = jj << 1; 140 | if (i & 0x80) { 141 | jj2 = 255u - jj2; 142 | } 143 | return jj2; 144 | } 145 | -------------------------------------------------------------------------------- /version2/SmartEVSE2.X/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | ; Project: Smart EVSE 3 | ; 4 | ; 5 | ; 6 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 7 | ; of this software and associated documentation files (the "Software"), to deal 8 | ; in the Software without restriction, including without limitation the rights 9 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | ; copies of the Software, and to permit persons to whom the Software is 11 | ; furnished to do so, subject to the following conditions: 12 | ; 13 | ; The above copyright notice and this permission notice shall be included in 14 | ; all copies or substantial portions of the Software. 15 | ; 16 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | ; THE SOFTWARE. 23 | */ 24 | 25 | // This is a guard condition so that contents of this file are not included 26 | // more than once. 27 | #ifndef UTILS_H 28 | #define UTILS_H 29 | 30 | unsigned long pow10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; 31 | unsigned char crc8(unsigned char *buf, unsigned char len); 32 | unsigned int crc16(unsigned char *buf, unsigned char len); 33 | void delay(unsigned int d); 34 | void sprintfl(unsigned char *str, const unsigned char *Format, signed long Value, unsigned char Divisor, unsigned char Decimal); 35 | unsigned char triwave8(unsigned char in); 36 | unsigned char scale8(unsigned char i, unsigned char scale); 37 | unsigned char ease8InOutQuad(unsigned char i); 38 | 39 | #endif /* UTILS_H */ 40 | -------------------------------------------------------------------------------- /version2/eagle/LCD_boardv2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/version2/eagle/LCD_boardv2.pdf -------------------------------------------------------------------------------- /version2/eagle/SmartEVSEv2.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/version2/eagle/SmartEVSEv2.2.pdf -------------------------------------------------------------------------------- /version2/manual/SmartEVSEv2.2_install_v2.16.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/version2/manual/SmartEVSEv2.2_install_v2.16.pdf -------------------------------------------------------------------------------- /version2/manual/SmartEVSEv2_manual_1.07.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SmartEVSE/smartevse/bc7d65f60d0eb803d70d6d689d91f1b3edb9431d/version2/manual/SmartEVSEv2_manual_1.07.pdf --------------------------------------------------------------------------------