crash with reverse engineering C++ code (#1518)

I tried reverse engineering an Arduino library (c++). Some work, but the LiquidCrystal_I2C crashes.

The crash report is:

System.NullReferenceException: De objectverwijzing is niet op een exemplaar van een object ingesteld.

bij SoftwareIdeasModeler.Core.SourceCodeParsing.ObjectStructureGeneration.ObjectStructureGenerator.ProcessMethod(UmlClass umlClass, ParsedPart part)

bij SoftwareIdeasModeler.Core.SourceCodeParsing.ObjectStructureGeneration.ObjectStructureGenerator.ProcessPart(ParsedFile file, String package, ParsedPart part, IModelElement parentElement)

bij SoftwareIdeasModeler.Core.SourceCodeParsing.ObjectStructureGeneration.ObjectStructureGenerator.ProcessPart(ParsedFile file, String package, ParsedPart part, IModelElement parentElement)

bij SoftwareIdeasModeler.Core.SourceCodeParsing.ObjectStructureGeneration.ObjectStructureGenerator.ProcessPart(ParsedFile file, String package, ParsedPart part, IModelElement parentElement)

bij SoftwareIdeasModeler.Core.SourceCodeParsing.ObjectStructureGeneration.ObjectStructureGenerator.ProcessProject(List`1 parsedFiles)

bij SoftwareIdeasModeler.Dialogs.Importing.SourceCode.SourceCodeImporter.GetDiagramItems(IList`1 files)

bij SoftwareIdeasModeler.Dialogs.Importing.SourceCode.SourceCodeImporter.Import()

bij SoftwareIdeasModeler.Dialogs.Importing.SourceCode.ImportForm.okButton_Click(Object sender, EventArgs e)

bij System.Windows.Forms.Control.OnClick(EventArgs e)

bij System.Windows.Forms.Button.OnClick(EventArgs e)

LiquidCrystal_I2C.h

//DFRobot.com

#ifndef LiquidCrystal_I2C_h

#define LiquidCrystal_I2C_h

#include <inttypes.h>

#include "Print.h"

#include <Wire.h>

// commands

#define LCD_CLEARDISPLAY 0x01

#define LCD_RETURNHOME 0x02

#define LCD_ENTRYMODESET 0x04

#define LCD_DISPLAYCONTROL 0x08

#define LCD_CURSORSHIFT 0x10

#define LCD_FUNCTIONSET 0x20

#define LCD_SETCGRAMADDR 0x40

#define LCD_SETDDRAMADDR 0x80

// flags for display entry mode

#define LCD_ENTRYRIGHT 0x00

#define LCD_ENTRYLEFT 0x02

#define LCD_ENTRYSHIFTINCREMENT 0x01

#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for display on/off control

#define LCD_DISPLAYON 0x04

#define LCD_DISPLAYOFF 0x00

#define LCD_CURSORON 0x02

#define LCD_CURSOROFF 0x00

#define LCD_BLINKON 0x01

#define LCD_BLINKOFF 0x00

// flags for display/cursor shift

#define LCD_DISPLAYMOVE 0x08

#define LCD_CURSORMOVE 0x00

#define LCD_MOVERIGHT 0x04

#define LCD_MOVELEFT 0x00

// flags for function set

#define LCD_8BITMODE 0x10

#define LCD_4BITMODE 0x00

#define LCD_2LINE 0x08

#define LCD_1LINE 0x00

#define LCD_5x10DOTS 0x04

#define LCD_5x8DOTS 0x00

// flags for backlight control

#define LCD_BACKLIGHT 0x08

#define LCD_NOBACKLIGHT 0x00

#define En B00000100 // Enable bit

#define Rw B00000010 // Read/Write bit

#define Rs B00000001 // Register select bit

class LiquidCrystal_I2C : public Print {

public:

LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows);

void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS );

void clear();

void home();

void noDisplay();

void display();

void noBlink();

void blink();

void noCursor();

void cursor();

void scrollDisplayLeft();

void scrollDisplayRight();

void printLeft();

void printRight();

void leftToRight();

void rightToLeft();

void shiftIncrement();

void shiftDecrement();

void noBacklight();

void backlight();

void autoscroll();

void noAutoscroll();

void createChar(uint8_t, uint8_t[]);

void setCursor(uint8_t, uint8_t);

#if defined(ARDUINO) && ARDUINO >= 100

virtual size_t write(uint8_t);

#else

virtual void write(uint8_t);

#endif

void command(uint8_t);

void init();

////compatibility API function aliases

void blink_on(); // alias for blink()

void blink_off(); // alias for noBlink()

void cursor_on(); // alias for cursor()

void cursor_off(); // alias for noCursor()

void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight()

void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar()

void printstr(const char[]);

////Unsupported API functions (not implemented in this library)

uint8_t status();

void setContrast(uint8_t new_val);

uint8_t keypad();

void setDelay(int,int);

void on();

void off();

uint8_t init_bargraph(uint8_t graphtype);

void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);

void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);

private:

void init_priv();

void send(uint8_t, uint8_t);

void write4bits(uint8_t);

void expanderWrite(uint8_t);

void pulseEnable(uint8_t);

uint8_t _Addr;

uint8_t _displayfunction;

uint8_t _displaycontrol;

uint8_t _displaymode;

uint8_t _numlines;

uint8_t _cols;

uint8_t _rows;

uint8_t _backlightval;

};

#endif

LiquidCrystal_I2C.cpp

//www.DFRobot.com

//last updated on 21/12/2011

//Tim Starling Fix the reset bug (Thanks Tim)

//wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)

//Support Forum: http://www.dfrobot.com/forum/

//Compatible with the Arduino IDE 1.0

//Library version:1.1

#include "LiquidCrystal_I2C.h"

#include <inttypes.h>

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#define printIIC(args) Wire.write(args)

inline size_t LiquidCrystal_I2C::write(uint8_t value) {

send(value, Rs);

return 1;

}

#else

#include "WProgram.h"

#define printIIC(args) Wire.send(args)

inline void LiquidCrystal_I2C::write(uint8_t value) {

send(value, Rs);

}

#endif

#include "Wire.h"

// When the display powers up, it is configured as follows:

//

// 1. Display clear

// 2. Function set:

// DL = 1; 8-bit interface data

// N = 0; 1-line display

// F = 0; 5x8 dot character font

// 3. Display on/off control:

// D = 0; Display off

// C = 0; Cursor off

// B = 0; Blinking off

// 4. Entry mode set:

// I/D = 1; Increment by 1

// S = 0; No shift

//

// Note, however, that resetting the Arduino doesn't reset the LCD, so we

// can't assume that its in that state when a sketch starts (and the

// LiquidCrystal constructor is called).

LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows)

{

_Addr = lcd_Addr;

_cols = lcd_cols;

_rows = lcd_rows;

_backlightval = LCD_NOBACKLIGHT;

}

void LiquidCrystal_I2C::init(){

init_priv();

}

void LiquidCrystal_I2C::init_priv()

{

Wire.begin();

_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;

begin(_cols, _rows);

}

void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {

if (lines > 1) {

_displayfunction |= LCD_2LINE;

}

_numlines = lines;

// for some 1 line displays you can select a 10 pixel high font

if ((dotsize != 0) && (lines == 1)) {

_displayfunction |= LCD_5x10DOTS;

}

// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!

// according to datasheet, we need at least 40ms after power rises above 2.7V

// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50

delay(50);

// Now we pull both RS and R/W low to begin commands

expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)

delay(1000);

//put the LCD into 4 bit mode

// this is according to the hitachi HD44780 datasheet

// figure 24, pg 46

// we start in 8bit mode, try to set 4 bit mode

write4bits(0x03 << 4);

delayMicroseconds(4500); // wait min 4.1ms

// second try

write4bits(0x03 << 4);

delayMicroseconds(4500); // wait min 4.1ms

// third go!

write4bits(0x03 << 4);

delayMicroseconds(150);

// finally, set to 4-bit interface

write4bits(0x02 << 4);

// set # lines, font size, etc.

command(LCD_FUNCTIONSET | _displayfunction);

// turn the display on with no cursor or blinking default

_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;

display();

// clear it off

clear();

// Initialize to default text direction (for roman languages)

_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;

// set the entry mode

command(LCD_ENTRYMODESET | _displaymode);

home();

}

/********** high level commands, for the user! */

void LiquidCrystal_I2C::clear(){

command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero

delayMicroseconds(2000); // this command takes a long time!

}

void LiquidCrystal_I2C::home(){

command(LCD_RETURNHOME); // set cursor position to zero

delayMicroseconds(2000); // this command takes a long time!

}

void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row){

int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };

if ( row > _numlines ) {

row = _numlines-1; // we count rows starting w/0

}

command(LCD_SETDDRAMADDR | (col + row_offsets[row]));

}

// Turn the display on/off (quickly)

void LiquidCrystal_I2C::noDisplay() {

_displaycontrol &= ~LCD_DISPLAYON;

command(LCD_DISPLAYCONTROL | _displaycontrol);

}

void LiquidCrystal_I2C::display() {

_displaycontrol |= LCD_DISPLAYON;

command(LCD_DISPLAYCONTROL | _displaycontrol);

}

// Turns the underline cursor on/off

void LiquidCrystal_I2C::noCursor() {

_displaycontrol &= ~LCD_CURSORON;

command(LCD_DISPLAYCONTROL | _displaycontrol);

}

void LiquidCrystal_I2C::cursor() {

_displaycontrol |= LCD_CURSORON;

command(LCD_DISPLAYCONTROL | _displaycontrol);

}

// Turn on and off the blinking cursor

void LiquidCrystal_I2C::noBlink() {

_displaycontrol &= ~LCD_BLINKON;

command(LCD_DISPLAYCONTROL | _displaycontrol);

}

void LiquidCrystal_I2C::blink() {

_displaycontrol |= LCD_BLINKON;

command(LCD_DISPLAYCONTROL | _displaycontrol);

}

// These commands scroll the display without changing the RAM

void LiquidCrystal_I2C::scrollDisplayLeft(void) {

command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);

}

void LiquidCrystal_I2C::scrollDisplayRight(void) {

command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);

}

// This is for text that flows Left to Right

void LiquidCrystal_I2C::leftToRight(void) {

_displaymode |= LCD_ENTRYLEFT;

command(LCD_ENTRYMODESET | _displaymode);

}

// This is for text that flows Right to Left

void LiquidCrystal_I2C::rightToLeft(void) {

_displaymode &= ~LCD_ENTRYLEFT;

command(LCD_ENTRYMODESET | _displaymode);

}

// This will 'right justify' text from the cursor

void LiquidCrystal_I2C::autoscroll(void) {

_displaymode |= LCD_ENTRYSHIFTINCREMENT;

command(LCD_ENTRYMODESET | _displaymode);

}

// This will 'left justify' text from the cursor

void LiquidCrystal_I2C::noAutoscroll(void) {

_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;

command(LCD_ENTRYMODESET | _displaymode);

}

// Allows us to fill the first 8 CGRAM locations

// with custom characters

void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {

location &= 0x7; // we only have 8 locations 0-7

command(LCD_SETCGRAMADDR | (location << 3));

for (int i=0; i<8; i++) {

write(charmap);

}

}

// Turn the (optional) backlight off/on

void LiquidCrystal_I2C::noBacklight(void) {

_backlightval=LCD_NOBACKLIGHT;

expanderWrite(0);

}

void LiquidCrystal_I2C::backlight(void) {

_backlightval=LCD_BACKLIGHT;

expanderWrite(0);

}

/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystal_I2C::command(uint8_t value) {

send(value, 0);

}

/************ low level data pushing commands **********/

// write either command or data

void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {

uint8_t highnib=value&0xf0;

uint8_t lownib=(value<<4)&0xf0;

write4bits((highnib)|mode);

write4bits((lownib)|mode);

}

void LiquidCrystal_I2C::write4bits(uint8_t value) {

expanderWrite(value);

pulseEnable(value);

}

void LiquidCrystal_I2C::expanderWrite(uint8_t _data){

Wire.beginTransmission(_Addr);

printIIC((int)(_data) | _backlightval);

Wire.endTransmission();

}

void LiquidCrystal_I2C::pulseEnable(uint8_t _data){

expanderWrite(_data | En); // En high

delayMicroseconds(1); // enable pulse must be >450ns

expanderWrite(_data & ~En); // En low

delayMicroseconds(50); // commands need > 37us to settle

}

// Alias functions

void LiquidCrystal_I2C::cursor_on(){

cursor();

}

void LiquidCrystal_I2C::cursor_off(){

noCursor();

}

void LiquidCrystal_I2C::blink_on(){

blink();

}

void LiquidCrystal_I2C::blink_off(){

noBlink();

}

void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){

createChar(char_num, rows);

}

void LiquidCrystal_I2C::setBacklight(uint8_t new_val){

if(new_val){

backlight(); // turn backlight on

}else{

noBacklight(); // turn backlight off

}

}

void LiquidCrystal_I2C::printstr(const char c[]){

//This function is not identical to the function used for "real" I2C displays

//it's here so the user sketch doesn't have to be changed

print(c);

}

// unsupported API functions

void LiquidCrystal_I2C::off(){}

void LiquidCrystal_I2C::on(){}

void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {}

uint8_t LiquidCrystal_I2C::status(){return 0;}

uint8_t LiquidCrystal_I2C::keypad (){return 0;}

uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;}

void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){}

void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){}

void LiquidCrystal_I2C::setContrast(uint8_t new_val){}

Created
15 August 2017 19:04:02
Closed
15 August 2017 22:46:40
Requested by
Nico Verduin
State
Solved
Version
11.15
OperatingSystem
Windows 10 64 bit
Solved in
11.16

Dusan Rodina - softwareideas.net 16 August 2017 7:55:22

It should work now.

Nico Verduin 17 August 2017 18:51:02

Yep works. Just reverse engineered the Arduino core libraries into a giant class diagram :)

TrackedRequestComment
Your Name:
You can use these formatting tags: [b]bold[/b] [i]italic[/i] [u]underline[/u] [url]www.example.com[/url] [code]some code[/code] [quote]quoted text[/quote] [list]one list item per line[/list]