Skip to content
Snippets Groups Projects
Commit fafc6ef2 authored by Kevin Lyda's avatar Kevin Lyda :speech_balloon:
Browse files

Function stubs done.

parent 15c01345
Branches
No related tags found
No related merge requests found
Pipeline #
...@@ -18,7 +18,22 @@ func New(c Config) (Counter, error) { ...@@ -18,7 +18,22 @@ func New(c Config) (Counter, error) {
// Counter is an interface for Geiger Counters // Counter is an interface for Geiger Counters
type Counter interface { type Counter interface {
GetReading() (*Reading, error) Clear() error
Version() (string, error)
SerialNum() (string, error)
GetCPM() (uint16, error)
GetCPS() (uint16, error)
GetVoltage() (int16, error)
GetHistoryData()
TurnOnCPS() error
TurnOffCPS() error
GetAutoCPS() (uint16, error)
TurnOffPower()
GetConfiguration()
SetConfiguration()
ResetConfiguration()
SetDate(date string)
SetTime(time string)
} }
// Config contain the configuration for a Geiger Counter // Config contain the configuration for a Geiger Counter
......
...@@ -8,11 +8,18 @@ ...@@ -8,11 +8,18 @@
package geiger package geiger
import ( import (
"fmt"
"time" "time"
"github.com/tarm/serial" "github.com/tarm/serial"
) )
// The Ideal and Low voltage threshholds
const (
VoltageIdeal = 98
VoltageTooLow = 75
)
const ( const (
powerOnOff = 0 powerOnOff = 0
alarmOnOff = 1 alarmOnOff = 1
...@@ -87,18 +94,11 @@ const ( ...@@ -87,18 +94,11 @@ const (
saveMax saveMax
) )
const (
key1 = iota
key2
key3
key4
)
const ( const (
historyDataMaxSize = 0x1000 historyDataMaxSize = 0x1000
historyAddrMaxSize = 0x10000 historyAddrMaxSize = 0x10000
forFirmware = 2.23 forFirmware = 2.23
kNVMSize = 256 nvmSize = 256
) )
const ( const (
...@@ -140,692 +140,26 @@ const ( ...@@ -140,692 +140,26 @@ const (
errSecond = "Failed to set second" errSecond = "Failed to set second"
) )
// CONFIGURATION DATA
//
// Setting the configuration data of the GQ GMC is not a
// straight forward procedure. The following statement is the
// principle reason why: the GQ GMC does not use or keep a RAM copy
// of its non-volatile memory (NVM) (configuration data is in NVM).
// That condition coupled with the fact that the EEPROM
// used by the GQ GMC can only be reprogrammed
// all 256 bytes at a shot means that if you write a byte of
// configuration data and then read back the configuration data,
// you will not see your data changed as expected.
//
// All this means that in order to change the configuration
// parameters and have the GQ GMC change its operations accordingly,
// 1) the host computer must keep its own copy of NVM,
// 2) update its own copy of NVM,
// 3) issue the erase configuration command,
// 4) write all 256 bytes of configuration data at one shot,
// 5) follow immediately with an update configuration command.
//
// When the GQ GMC receives the update configuration command,
// then and only then does it re-configure its operation in
// accordance with the NVM configuration data. Keeping the host
// computer's copy of the NVM accurate and up to date can be
// problematic since behind the back of the host computer,
// the GQ GMC can be changed manually.
//
// The GQGMC software makes a valiant attempt to hide all this
// from the user. First, immediately following the opening of
// the USB port, the software silently reads the configuration
// data from the GQ GMC to obtain its own copy of NVM.
// From that point on, it is assumed that no manual changes
// to the GQ GMC will occur. The GQGMC software then reads/writes
// it own local copy of NVM. When the user issues the Update CFG
// command, the GQGMC software silently
// 1) issues the erase configuraton command,
// 2) writes all 256 bytes of NVM,
// 3) issues the update configuration command.
// The user software may at any time cause a Get configuration
// command in which case, the user must be aware that the GQGMC's
// local copy of NVM will be overwritten.
// getConfigurationData public method reads configuration data. You
// don't request pieces of the configuration data, all 256 bytes
// are returned, although, there are currently only about 60
// bytes used (corresponding to about 50 parameters). The command is
// get_cfg_cmd (see GQ GMC COMMANDS above).
void
func (gc *GQGMCCounter) getConfigurationData()
{
// Issue command to get configuration and read returned data.
communicate(get_cfg_cmd, reinterpret_cast<char *>(&mCFG_Data),
sizeof(mCFG_Data));
// If read of returned data failed, set error code.
if (mRead_status == false)
{
mError_code = eGet_CFG;
}
// debugging code
/*
uint8_t * inp = (uint8_t *)&mCFG_Data;
for(uint32_t i=0; i<64; i++)
{
cout << Hex(inp[i]) << "-";
if (i > 0)
if (((i+1)%16) == 0) cout << endl;
if (i > 62)break;
}
cout << endl;
*/
// end debug code
return;
} // end getConfigurationData()
// The following get methods are provided in order to access the
// configuration data, not all configuration data, but only those
// parameters which are needed to retrieve and parse the history data.
// getSaveDataType is a get method to retrieve the saved data type
// parameter in the configuration data. Note that SaveDataType is
// retrieved from the host computer's local copy of NVM
// configuration data. The return type is an enumeration
// which matches the following possibilities:
// 0 = logging is off,
// 1 = counts per second,
// 2 = counts per minute,
// 3 = CPM averaged per hour.
enum saveDataType_t
func (gc *GQGMCCounter) getSaveDataType()
{
return ((enum saveDataType_t)(mCFG_Data.saveDataType));
} // end getSaveDataType()
// setSaveDataType is a set method to reconfigure the data type
// logged in the history buffer. This method is provided as a
// convenience instead of using the writeConfigurationData method
// since changing the saved data type is considered to be
// more commonly used configuration change. The passed argument
// is an enumeration (see definition in gqgmc.hh) whose value
// is to be the new value of the saveDataType configuration
// parameter. Note that only the host computer's local copy
// of NVM is updated. The user must issue a update configuration
// command to cause the GQGMC to implement the NVM changes.
void
func (gc *GQGMCCounter) setSaveDataType(enum saveDataType_t newSaveDataType)
{
uint8_t saveData = uint8_t(newSaveDataType);
// Use writeConfigurationData method
writeConfigurationData(eSaveDataType, eSaveDataType_bytecnt, &saveData);
// error condition will be handled by writeConfigurationData()
return;
} // end setSaveDatatype method
// getDataSaveAddress is get method to retrieve the address
// in the history buffer where the logged data begins. See
// getHistoryData method for an explanation of the
// dataSaveAddress in the configuration data structure.
// The returned value is a 32 bit address, although the
// dataSaveAddress maximum value cannot exceed 24 bits worth.
// Note that the DataSaveAddress is retrieved from the host
// computer's local copy of the GQ GMC's NVM configuration data.
uint32_t
func (gc *GQGMCCounter) getDataSaveAddress()
{
uint32_t address(0);
address |= (uint32_t(mCFG_Data.dataSaveAddress2) << 16);
address |= (uint32_t(mCFG_Data.dataSaveAddress1) << 8);
address |= (uint32_t(mCFG_Data.dataSaveAddress0) << 0);
return address;
} // end getDataSaveAddress()
// The resetDataSaveAddress sets the dataSaveAddress configuration
// parameter to the value of 0x10. This is provided as a
// convenience instead of using writeConfigurationData() directly
// because setting the start of the history buffer back to zero
// would be a common thing to do. Note that the DataSaveAddress
// is being updated in the host computer's local copy of the
// GQ GMC's NVM configuration data. The user must issue the
// update configuration command to force the GQ GMC to implement
// the NVM configuration data changes.
void
func (gc *GQGMCCounter) resetDataSaveAddress()
{
uint32_t address(0x10); // 0x10 provides room for date/timestamp
// Use writeConfigurationData() method
writeConfigurationData(eDataSaveAddress, eDataSaveAddress_bytecnt,
(uint8_t *)(&address));
// error condition handled by writeConfigurationData()
return;
} // end resetDataSaveAddress()
// writeConfiguratonData is the public method to write configuration
// data. It takes the following parameters.
//
// cfgParameter is actually the offset from the beginning of the
// configuration data of the desired parameter. It was explicitly
// created this way and assigned the offset as its enumeration value so
// that cfgParameter serves both as an enumeration and as the actual
// address of the configuration parameter.
//
// cfgData is a pointer to an array of raw binary for the parameter.
//
// cfgDataCount is the number of bytes of cfgData. Since cfgData is
// passed as pointer, we need to supply the array length separately
// as the cfgDataCount parameter.
//
// Note that this method updates the local copy of the GQ GMC's
// NVM configuration data. As noted previously in the documentation,
// the GQ GMC does not support a direct method of updating its
// NVM configuration data and having it take effect immediately.
//
// This method is not an exact reflection of the native GQ GMC write
// configuration command. The native GQ GMC write configuration
// only writes one byte at a time. So writing multibyte configuration
// parameters would take multiple writes, one per data byte. Instead,
// we abstract the write configuration command so the user does not
// have to know this much detail. We can do this because we
// know a priori the base address of each parameter and how many
// bytes each parameter needs. So this method is intended to
// handle parameters with multibyte data by requiring the user
// to only pass the parameter enumeration, its byte count, and
// value.
//
// Note that changes to the configuration data do not have
// immediate effect since we writing to the local copy of the
// GQ GMC's NVM configuration data. To take effect, the user must
// call the updateConfigurationData() method. Before doing so, all
// changes to the configuration data should be completed so that
// interdependent configuration parameters are updated
// simultaneously.
void
func (gc *GQGMCCounter) writeConfigurationData(enum cfg_param_t cfgParameter,
enum cfg_bytecnt_t cfgDataCount,
uint8_t const * const cfgData)
{
uint8_t * pCfg_Data = (uint8_t *)&mCFG_Data + uint8_t(cfgParameter);
for(int i=0; i<cfgDataCount; i++)
{
// Convert little endian to big endian which GQ GMC wants.
if (mBig_endian)
pCfg_Data[i] = cfgData[i];
else
pCfg_Data[i] = cfgData[cfgDataCount-1-i];
} // end for loop
return;
} // end writeConfigurationData()
// loadConfigurationData private method writes all 256 bytes
// of the configuration data to the GQ GMC. This will take
// over a minute to complete. This is a practice in patience.
// The GQ GMC's write_cfg_cmd only transmits a single byte
// at a time. So it takes 256 transmits and each transmit
// has to wait for a 0xAA return. The user obviously should
// not update the NVM configuration too often.
void
func (gc *GQGMCCounter) loadConfigurationData()
{
const
uint32_t retsize = 1;
char ret_char[retsize+1];
// Need a pointer to the local host computer's copy
// of the NVM configuration data.
uint8_t * pCfg_Data = (uint8_t *)&mCFG_Data;
// Begin formulating the write configuration data command.
// "AD" is just a place holder for the address byte and data byte
// that will be dynamically derived and inserted.
string write_cfg_cmd = "<WCFGAD>>";
// The parameter and its data have to be dynamically derived.
// write_cfg_cmd[5] is parameter enumeration (aka address offset)
// write_cfg_cmd[6] is parameter data
// Pack address and data into write_cfg_data_cmd with big
// endian byte order.
// Address (ie, parameter) is less than 256 since configuration
// data has a fixed size of 256 bytes, so address is one byte.
// pack address and data into command
for(uint16_t i=0; i<kNVMSize; i++)
{
// Increment the address for each additional data byte.
write_cfg_cmd[5] = uint8_t(i);
// Load data one byte at a time
write_cfg_cmd[6] = pCfg_Data[i];
/* // debug code
if (i < 64)
{
for(int i=0; i<5; i++)
cout << write_cfg_cmd[i];
cout << Hex(write_cfg_cmd[5]);
cout << Hex(write_cfg_cmd[6]);
cout << write_cfg_cmd[7];
cout << write_cfg_cmd[8];
cout << endl;
}
*/ // end debug code
// Issue command to write configuration data, one byte
// at a time because that is the native write configuration
// command of the GQ GMC.
communicate(write_cfg_cmd, ret_char, retsize);
// if read of returned data succeeded, convert raw data to float
if (mRead_status == true)
{
// We really don't care about the return value of 0xAA. If the
// GQ GMC does not recognize the command, it returns nothing and
// we get a read_status error.
}
else // else for failure, set error code
{
mError_code = eWrite_CFG;
break; // break out of for loop
} // end (read_status == true)
} // end for loop
return;
} // loadConfigurationData()
// eraseConfigurationData public method erases the configuration data
// in its entirety. The configuration returns to its factory default
// setting. It might have been better to call this the reset
// configuration data command. The command is erase_cfg_cmd
// (see GQ GMC COMMANDS above).
void
func (gc *GQGMCCounter) eraseConfigurationData()
{
const
uint32_t retsize = 1;
char ret_char[retsize+1];
// Issue command to erase NVM configuration.
communicate(erase_cfg_cmd, ret_char, retsize);
// If read of returned data succeeded, convert raw data to float,
if (mRead_status == true)
{
// We really don't care about the return value of 0xAA. If the
// GQ GMC does not recognize the command, it returns nothing and
// we get a read_status error.
}
else // else for failure, set the error code.
{
mError_code = eErase_CFG;
}
return;
} // end eraseConfigurationData()
// The updateConfigurationdata public method is called to make changes
// to configuration data take effect. All other methods to modify
// the configuration data do not cause the GQ GMC to immediately
// change operation. This would not be desireable since various
// changes to the configuration may be interdependent and so
// we would want the changes to take effect simultaneously to
// insure proper operation. There are no arguments to call.
// The command is update_cfg_cmd (see GQ GMC COMMANDS above).
// The user who calls this method may want to pop-up a window
// stating that this will take about one minute. That is about
// how long it will take to write all 256 bytes to the GQ GMC.
// This method calls eraseConfigurationData() and
// loadConfigurationData() as part of the procedure needed to
// force the GQ GMC to implement operational changes per the
// new NVM configuration data.
void
func (gc *GQGMCCounter) updateConfigurationData()
{
const
uint32_t retsize = 1;
char ret_char[retsize+1];
// 1st, we have to erase configuration data
// cout << erase_cfg_cmd << endl; // debug
eraseConfigurationData();
// 2nd, write all 256 bytes of NVM to GQ GMC
// cout << "load cfg" << endl; // debug
loadConfigurationData();
// cout << update_cfg_cmd << endl; // debug
// Issue command to update NVM and force GQ GMC to change
// operation in accordance to new configuration data.
communicate(update_cfg_cmd, ret_char, retsize);
// If read of returned data succeeded, convert raw data to float,
if (mRead_status == true)
{
// We really don't care about the return value of 0xAA. If the
// GQ GMC does not recognize the command, it returns nothing and
// we get a read_status error.
}
else // else for failure, set the error code.
{
mError_code = eUpdate_CFG;
}
return;
} // end updateConfigurationData()
// sendKey is the public method to emulate any one of the 4 keys on
// the front panel of the GQ GMC. The front panel has a 'left arrow',
// 'up arrow, 'down arrow', and 'enter' keys. These are used to
// navigate through the GQ GMC's menu system. In principle, the
// menu system can be used to set virtually any and all of the
// configuration data (although this is not recommended for
// such configuration data as the calibration values).
// So instead of the writeConfigurationData method,
// the proper sequence of sending the keys would do the
// same thing. The command is derived dynamically, but the actual
// command is "<KEY0>>" or "<KEY1>>" or "<KEY2>>" or "<KEY3>>".
// So for the purpose that the user need not know the actual
// command string, the softkey_t enumeration is created and used
// as the passed argument to the method. See the enum softkey_t
// declaration in gqgmc.hh for more discussion.
//
// For successive sendKey calls there is a trick to know when
// using the sendKey method. The trick is you can't
// transmit sendKey too fast and you can't do it too slow.
// Another thing is that the Save Data option menu starts with
// the current data type and then cycles through the other options.
// So you have to know what is the current data type and
// then send the Enter key the proper number of times to cycle
// to the desired option. When moving through the menu we use
// 0.5 seconds, but when moving through a pop up options menu
// we have to move faster and so should use 0.25 seconds
// between sendKey in that context.
void
func (gc *GQGMCCounter) sendKey(enum softkey_t key)
{
char inp[1]; // This will not be used, just needed as dummy arg
// Begin formulating the send key command.
string keycmd = "<KEY";
// Append key number which is an enumeration equal to the
// ASCII value of the key, ie, '0', '1', '2', or '3'.
keycmd += uint8_t(key);
// Append ">>"
keycmd += ">>";
communicate(keycmd, inp, 0); // no return data
// Since the sendkey command returns no data there is no way to
// test success of communication.
// Debug code
/*
for(int i=0; i<7; i++)
cout << Hex(keycmd[i]);
cout << endl;
*/
return;
} // end sendKey()
// setDate is the public method to set the date. The date is passed as
// an ASCII string with the format of <month><day><year>, for example,
// 112312 is November (11th month) 12, 2012. The year is specified
// as the last two digits of the century since presumably the date is
// is being set to the current date. In reality, the GQ GMC has a separate
// command for setting each of the month, day, and year.
void
func (gc *GQGMCCounter) setDate(string date)
{
const
uint32_t retsize = 1;
char ret_char[retsize+1];
// The date is broken up into three separate commands one each for
// month, day, and year as supported by the GQ GMC.
// Set the month, <SETDATEMMXX>> where XX = month byte.
{
// uint16_t is necessary since ss >> uint8_t does not work.
uint16_t month=0;
string setMonthCmd;
stringstream ss;
ss << date[0] << date[1];
ss >> month;
//cout << "month = " << Hex(uint8_t(month)) << endl;
setMonthCmd = "<SETDATEMM";
setMonthCmd += uint8_t(month);
setMonthCmd += ">>";
communicate(setMonthCmd, ret_char, retsize);
}
// Set the day, <SETDATEDDXX>> where XX = day byte.
{
uint16_t day=0;
string setDayCmd;
stringstream ss;
ss << date[2] << date[3];
ss >> day;
//cout << "day = " << Hex(uint8_t(day)) << endl;
setDayCmd = "<SETDATEDD";
setDayCmd += uint8_t(day);
setDayCmd += ">>";
communicate(setDayCmd, ret_char, retsize);
}
// Set the year, <SETDATEYYXX>> where XX = year byte.
{
uint16_t year=0;
string setYearCmd;
stringstream ss;
ss << date[4] << date[5];
ss >> year;
//cout << "year = " << Hex(uint8_t(year)) << endl;
setYearCmd = "<SETDATEYY";
setYearCmd += uint8_t(year);
setYearCmd += ">>";
communicate(setYearCmd, ret_char, retsize);
}
return;
} // end set Date()
// setTime is the public method to set the time of day. The time is
// passed as an ASCII string with the format of <hour><minutes><seconds>,
// for example, 142256 is the 14th hour, 22 minutes after the hour,
// 56 seconds after the minute. The hour is given in 24 hour format
// counting from 0 to 23. In reality, the GQ GMC provides a separate
// command for setting each of the hour, minutes and seconds.
void
func (gc *GQGMCCounter) setTime(string time)
{
const
uint32_t retsize = 1;
char ret_char[retsize+1];
// The time is broken up into three separate commands one each for
// hour, minute, and second as supported by the GQ GMC.
// Set the hour, <SETTIMEHHXX>> where XX = hour byte.
{
uint16_t hour=0; // stringstream does not convert to uint8_t
string setHourCmd;
stringstream ss;
ss << time[0] << time[1];
ss >> hour;
//cout << "hours = " << Hex(uint8_t(hour)) << endl;
setHourCmd = "<SETTIMEHH";
setHourCmd += uint8_t(hour);
setHourCmd += ">>";
communicate(setHourCmd, ret_char, retsize);
}
// Set the minute, <SETTIMEMMXX>> where XX = minute byte.
{
uint16_t minute=0;
string setMinuteCmd;
stringstream ss;
ss << time[2] << time[3];
ss >> minute;
//cout << "minute = " << Hex(uint8_t(minute)) << endl;
setMinuteCmd = "<SETTIMEMM";
setMinuteCmd += uint8_t(minute);
setMinuteCmd += ">>";
communicate(setMinuteCmd, ret_char, retsize);
}
// Set the seconds, <SETTIMESSXX>> where XX = second byte.
{
uint16_t second=0;
string setSecondCmd;
stringstream ss;
ss << time[4] << time[5];
ss >> second;
//cout << "second = " << Hex(uint8_t(second)) << endl;
setSecondCmd = "<SETTIMESS";
setSecondCmd += uint8_t(second);
setSecondCmd += ">>";
communicate(setSecondCmd, ret_char, retsize);
}
return;
} // end setTime()
// PRIVATE METHODS
// communicate private method is used to write/read data to/from
// the GMC-300. This method is expressedly designed to be called
// by methods which send an ASCII string and expect to receive
// returned data. However for flexibility, if the command string
// is null, no command is transmitted and if the expected number
// of return bytes is zero, no read is performed.
// cmd is the ASCII string command.
// retdata is the repository for the returned data.
// retbytes is the number of bytes of returned data.
void
func (gc *GQGMCCounter) communicate(const string cmd, char * retdata, uint32_t retbytes)
{
// Clear the USB port of any left over data from last exchange. Even
// though we know how many bytes the GQ GMC transmits for each
// command, experience has shown this is the safe thing to do since
// there is no protocol for the returned data.
clearUSB();
//cout << cmd << endl;
// 1st, issue the command to the GMC-300, this is always an ASCII
// string.
// For flexibility, only transmit if cmdbytes is not 'null'.
if (cmd.size() > 0) sendCmd(cmd);
// 2nd, read the return data, for all commands except get version
// this is always raw binary data.
// For flexibility, only read if return is not 'null'.
if (retbytes > 0) readCmdReturn(retdata, retbytes);
return;
} // end communicate()
// sendCmd is the private method (the basic method) to transmit
// the command to the GMC-300.
// cmd is the ASCII string to send as the command.
void
func (gc *GQGMCCounter) sendCmd(const string cmd)
{
// This is a common place to reset the error code since it is always
// called for any command.
mError_code = eNoProblem;
// This is a common place to reset the read status since every read
// is always preceeded by a write command (except for turn_on_cps!).
mRead_status = true;
// Call low level C stdio routine to write to USB port.
write(mUSB_serial, cmd.c_str(), cmd.size());
return;
} // end sendCmd()
// readCmdReturn is the private method (the basic method) to read
// the return bytes from the command.
// retdata is the repository for the returned data.
// retbytes is the number of bytes of the returned data.
void
func (gc *GQGMCCounter) readCmdReturn(char * retdata, uint32_t retbytes)
{
uint32_t rcvd = 0; // the number of received bytes
char * inp = &retdata[0]; // pointer to returned data char array
// start pointer off at beginning of
// repository.
// Assume read will succeed, replicated here only because of the
// nature of the turn_on_cps command which automatically returns
// data without a preceeding write.
mRead_status = true;
// Now read the returned raw byte string. Do this by reading one byte
// at a time until the requested number of bytes are attained. However,
// the serial port has been setup to timeout each read attempt. So if
// after N calls to read, we haven't yet read all N bytes, declare
// a failure. The read is done this way to avoid an indefinite blocking
// situation when 0 bytes are returned by the GQ GMC. The only good thing
// about this methodology is that the largest possible read is only 4K
// for the history data. So the read never really takes that much time.
for(uint32_t i=0; i<retbytes; i++)
{
rcvd += read(mUSB_serial, inp, 1);
inp = &retdata[rcvd];
if (rcvd >= retbytes) break;
} // end for loop
// debugging code
/*
inp = &retdata[0];
for(uint32_t i=0; i<retbytes; i++)
{
cout << Hex(inp[i]) << "-";
if (i > 0)
if (((i+1)%16) == 0) cout << endl;
if (i > 62)break;
}
cout << endl;
cout << "rcvd = " << rcvd << endl;
*/
// end debug code
// Communication is considered a failure if less than the expected
// number of bytes is returned by the GMC-300.
if (rcvd < retbytes)
mRead_status = false;
return;
} // readCmdReturn()
// GQGMCCounter is a GQ GMC Counter // GQGMCCounter is a GQ GMC Counter
type GQGMCCounter struct { type GQGMCCounter struct {
fh string // TODO: make this a file handle. port *serial.Port
config serial.Config config *serial.Config
} }
// NewGQGMC creates a new GQGMC Counter instance // NewGQGMC creates a new GQGMC Counter instance
func NewGQGMC(c Config) (*GQGMCCounter, error) { func NewGQGMC(c Config) (*GQGMCCounter, error) {
var gc GQGMCCounter cfg := serial.Config{
portCfg := serial.Config {
Name: c.Device, Name: c.Device,
Baud: 57600, Baud: 57600,
ReadTimeout: 500 * time.Millisecond, ReadTimeout: 500 * time.Millisecond,
} }
gc.port = OpenPort(portCfg) p, err := serial.OpenPort(&cfg)
if err != nil {
return nil, err
}
//vers := getVersion() //vers := getVersion()
//getConfigurationData() //getConfigurationData()
return &gc, nil return &GQGMCCounter{port: p, config: &cfg}, nil
} }
// Clear clears out any remaining data // Clear clears out any remaining data
...@@ -879,12 +213,6 @@ func (gc *GQGMCCounter) GetCPS() (uint16, error) { ...@@ -879,12 +213,6 @@ func (gc *GQGMCCounter) GetCPS() (uint16, error) {
return 0, nil return 0, nil
} }
const (
VoltageIdeal = 98
VoltageTooLow = 75
)
// GetVoltage returns current battery voltage // GetVoltage returns current battery voltage
func (gc *GQGMCCounter) GetVoltage() (int16, error) { func (gc *GQGMCCounter) GetVoltage() (int16, error) {
// Do this differently - for 9.6 return 96. And if not supported, // Do this differently - for 9.6 return 96. And if not supported,
...@@ -910,8 +238,10 @@ func (gc *GQGMCCounter) GetVoltage() (int16, error) { ...@@ -910,8 +238,10 @@ func (gc *GQGMCCounter) GetVoltage() (int16, error) {
// GetHistoryData Should return history data but is unimplemented for now // GetHistoryData Should return history data but is unimplemented for now
func (gc *GQGMCCounter) GetHistoryData() { func (gc *GQGMCCounter) GetHistoryData() {
// It's not recommended to use this so blank for now. // It's not recommended to use this so blank for now.
return
} }
// TurnOnCPS turns on CPS collection
func (gc *GQGMCCounter) TurnOnCPS() error { func (gc *GQGMCCounter) TurnOnCPS() error {
// turnOnCPS is public method to enable automatic reporting of the // turnOnCPS is public method to enable automatic reporting of the
// count per second (CPS) value. First, I would say don't use this // count per second (CPS) value. First, I would say don't use this
...@@ -928,14 +258,18 @@ func (gc *GQGMCCounter) TurnOnCPS() error { ...@@ -928,14 +258,18 @@ func (gc *GQGMCCounter) TurnOnCPS() error {
// bytes so that samples > 255 can be reported (even though unlikely). // bytes so that samples > 255 can be reported (even though unlikely).
//sendCmd(turn_on_cps_cmd); //sendCmd(turn_on_cps_cmd);
// There is no pass/fail return from GQ GMC // There is no pass/fail return from GQ GMC
return nil
} }
// TurnOffCPS turns off CPS collection
func (gc *GQGMCCounter) TurnOffCPS() error { func (gc *GQGMCCounter) TurnOffCPS() error {
//sendCmd(turn_off_cps_cmd); //sendCmd(turn_off_cps_cmd);
//call Clear() //call Clear()
return nil
} }
func (gc *GQGMCCounter) getAutoCPS() (uint16, error) { // GetAutoCPS gets a reading once auto CPS is turned on
func (gc *GQGMCCounter) GetAutoCPS() (uint16, error) {
//uint32_t cpssize = 2; // 2 bytes of returned data //uint32_t cpssize = 2; // 2 bytes of returned data
//read-from-port(cps_char, cpssize); //read-from-port(cps_char, cpssize);
// 1st byte is MSB, but note that upper two bits are reserved bits. // 1st byte is MSB, but note that upper two bits are reserved bits.
...@@ -946,7 +280,93 @@ func (gc *GQGMCCounter) getAutoCPS() (uint16, error) { ...@@ -946,7 +280,93 @@ func (gc *GQGMCCounter) getAutoCPS() (uint16, error) {
return 0, nil return 0, nil
} }
// TurnOffPower turns the device off
func (gc *GQGMCCounter) TurnOffPower() { func (gc *GQGMCCounter) TurnOffPower() {
sendCmd(turn_off_pwr_cmd); //sendCmd(turn_off_pwr_cmd)
// Note that power off cannot fail because the GQ GMC returns nothing. // Note that power off cannot fail because the GQ GMC returns nothing.
return
}
// GetConfiguration reads configuration data
func (gc *GQGMCCounter) GetConfiguration() {
// Issue command to get configuration and read returned data.
// communicate(get_cfg_cmd, reinterpret_cast<char *>(&mCFG_Data),
}
// SetConfiguration writes configuration data
func (gc *GQGMCCounter) SetConfiguration() {
// See the ConfigurationData functions in gqgmc.cc
}
// ResetConfiguration resets to factory default
func (gc *GQGMCCounter) ResetConfiguration() {
//uint32_t retsize = 1;
//char ret_char[retsize+1];
//communicate(erase_cfg_cmd, ret_char, retsize);
}
// SetDate sets the date - format of YYYYMMDD
func (gc *GQGMCCounter) SetDate(date string) {
//setMonthCmd = "<SETDATEMM";
//setMonthCmd += uint8_t(month);
//setMonthCmd += ">>";
//communicate(setMonthCmd, ret_char, retsize);
//setDayCmd = "<SETDATEDD";
//setDayCmd += uint8_t(day);
//setDayCmd += ">>";
//communicate(setDayCmd, ret_char, retsize);
// year - last two digits
//setYearCmd = "<SETDATEYY";
//setYearCmd += uint8_t(year);
//setYearCmd += ">>";
//communicate(setYearCmd, ret_char, retsize);
}
// SetTime sets the time (HH:MM:SS)
func (gc *GQGMCCounter) SetTime(time string) {
//setHourCmd = "<SETTIMEHH";
//setHourCmd += uint8_t(hour);
//setHourCmd += ">>";
//communicate(setHourCmd, ret_char, retsize);
//setMinuteCmd = "<SETTIMEMM";
//setMinuteCmd += uint8_t(minute);
//setMinuteCmd += ">>";
//communicate(setMinuteCmd, ret_char, retsize);
//setSecondCmd = "<SETTIMESS";
//setSecondCmd += uint8_t(second);
//setSecondCmd += ">>";
//communicate(setSecondCmd, ret_char, retsize);
}
func (gc *GQGMCCounter) communicate(cmd []byte, length uint32) ([]byte, error) {
//clearUSB();
//if (cmd.size() > 0) sendCmd(cmd);
//if (retbytes > 0) readCmdReturn(retdata, retbytes);
return nil, nil
}
func (gc *GQGMCCounter) sendCmd(cmd []byte) {
// The port write thing
gc.port.Write(cmd)
return
}
func (gc *GQGMCCounter) readCmdReturn(length uint32) ([]byte, error) {
// Now read the returned raw byte string. Do this by reading one byte
// at a time until the requested number of bytes are attained. However,
// the serial port has been setup to timeout each read attempt. So if
// after N calls to read, we haven't yet read all N bytes, declare
// a failure. The read is done this way to avoid an indefinite blocking
// situation when 0 bytes are returned by the GQ GMC. The only good thing
// about this methodology is that the largest possible read is only 4K
// for the history data. So the read never really takes that much time.
//for(uint32_t i=0; i<retbytes; i++)
// rcvd += read(mUSB_serial, inp, 1);
// inp = &retdata[rcvd];
// if (rcvd >= retbytes) break;
return nil, nil
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment